diff --git a/.dockerignore b/.dockerignore index f5faf1f0e3da..46c83b0467bd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ -.git awx/ui/node_modules diff --git a/.dput.cf b/.dput.cf deleted file mode 100644 index 11dbd7a65983..000000000000 --- a/.dput.cf +++ /dev/null @@ -1,6 +0,0 @@ -[mini_dinstall] -fqdn = localhost -method = local -incoming = FIXME/deb-repo/mini-dinstall/incoming -run_dinstall = 0 -post_upload_command = mini-dinstall -b -v diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index ed45b0d4320d..000000000000 --- a/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true - -[Makefile] -indent_style = tab - -[**.py] -indent_style = space -indent_size = 4 - -[**.{js,less,html}] -indent_style = space -indent_size = 4 - -[**.{json}] -indent_style = space -indent_size = 2 diff --git a/.env b/.env index a906b0df7c3e..827440c6aa6c 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ PYTHONUNBUFFERED=true +SELENIUM_DOCKER_TAG=latest diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 35f0eeec19dd..4e01f0442b11 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -1,3 +1,4 @@ +--- files: awx/ui/: labels: component:ui diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index caceb2de456e..2a7fb229d879 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -30,8 +30,9 @@ https://www.ansible.com/security ##### STEPS TO REPRODUCE - + ##### EXPECTED RESULTS diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000000..384b1dc78b84 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: "\U0001F41B Bug report" +about: Create a report to help us improve + +--- + + +##### ISSUE TYPE + - Bug Report + +##### SUMMARY + + +##### ENVIRONMENT +* AWX version: X.Y.Z +* AWX install method: openshift, minishift, docker on linux, docker for mac, boot2docker +* Ansible version: X.Y.Z +* Operating System: +* Web Browser: + +##### STEPS TO REPRODUCE + + + +##### EXPECTED RESULTS + + + +##### ACTUAL RESULTS + + + +##### ADDITIONAL INFORMATION + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000000..98fe2f5869da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: "✨ Feature request" +about: Suggest an idea for this project + +--- + + +##### ISSUE TYPE + - Feature Idea + +##### SUMMARY + diff --git a/.github/ISSUE_TEMPLATE/security_bug_report.md b/.github/ISSUE_TEMPLATE/security_bug_report.md new file mode 100644 index 000000000000..2763db4e309a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security_bug_report.md @@ -0,0 +1,9 @@ +--- +name: "\U0001F525 Security bug report" +about: How to report security vulnerabilities + +--- + +For all security related bugs, email security@ansible.com instead of using this issue tracker and you will receive a prompt response. + +For more information on the Ansible community's practices regarding responsible disclosure, see https://www.ansible.com/security diff --git a/.gitignore b/.gitignore index b1674af81187..71d2015cf257 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,16 @@ + +installer/inventory +# Ignore generated schema +swagger.json +schema.json +reference-schema.json + # Tags .tags .tags1 # Tower +awx-dev awx/settings/local_*.py* awx/*.sqlite3 awx/*.sqlite3_* @@ -22,8 +30,15 @@ awx/ui/build_test awx/ui/client/languages awx/ui/templates/ui/index.html awx/ui/templates/ui/installing.html -/tower-license -/tower-license/** +awx/ui_next/node_modules/ +awx/ui_next/src/locales/ +awx/ui_next/coverage/ +awx/ui_next/build +awx/ui_next/.env.local +awx/ui_next/instrumented +rsyslog.pid +tools/prometheus/data +tools/docker-compose/Dockerfile # Tower setup playbook testing setup/test/roles/postgresql @@ -52,10 +67,12 @@ __pycache__ **/node_modules/** /tmp **/npm-debug.log* +**/package-lock.json # UI build flag files awx/ui/.deps_built awx/ui/.release_built +awx/ui/.release_deps_built # Testing .cache @@ -67,6 +84,7 @@ pep8.txt scratch testem.log awx/awx_test.sqlite3-journal +.pytest_cache/ # Mac OS X *.DS_Store @@ -111,8 +129,8 @@ local/ *.mo requirements/vendor .i18n_built -VERSION .idea/* +*credentials*.y*ml* # AWX python libs populated by requirements.txt awx/lib/.deps_built @@ -120,4 +138,16 @@ awx/lib/site-packages venv/* use_dev_supervisor.txt + +# Ansible module tests +/awx_collection_test_venv/ +/awx_collection/*.tar.gz +/sanity/ +/awx_collection_build/ + .idea/* +*.unison.tmp +*.# +/tools/docker-compose/overrides/ +/awx/ui_next/.ui-built +/Dockerfile diff --git a/.mini-dinstall.cf b/.mini-dinstall.cf deleted file mode 100644 index d8c2bc8fa03b..000000000000 --- a/.mini-dinstall.cf +++ /dev/null @@ -1,16 +0,0 @@ -[DEFAULT] -archivedir = FIXME/deb-repo -mail_to = -verify_sigs = false -architectures = all, amd64 -archive_style = flat -generate_release = true -mail_on_success = false -release_codename = ansible-tower -release_description = Ansible Tower -release_label = ansible-tower -release_origin = ansible-tower - -[trusty] - -[precise] diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 1a4a32f323e4..000000000000 --- a/.pylintrc +++ /dev/null @@ -1,6 +0,0 @@ -[MASTER] - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=site-packages,ui,migrations,data - diff --git a/.yamllint b/.yamllint new file mode 100644 index 000000000000..11c769cff1d9 --- /dev/null +++ b/.yamllint @@ -0,0 +1,12 @@ +--- +ignore: | + .tox + awx/main/tests/data/inventory/plugins/** + # vault files + awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml + awx/ui/test/e2e/tests/smoke-vars.yml + +extends: default + +rules: + line-length: disable diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000000..6237a9f54aca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,381 @@ +# Changelog + +This is a list of high-level changes for each release of AWX. A full list of commits can be found at `https://github.com/ansible/awx/releases/tag/`. + +# 17.0.1 (January 26, 2021) +- Fixed pgdocker directory permissions issue with Local Docker installer: https://github.com/ansible/awx/pull/9152 +- Fixed a bug in the UI which caused toggle settings to not be changed when clicked: https://github.com/ansible/awx/pull/9093 + +# 17.0.0 (January 22, 2021) +- AWX now requires PostgreSQL 12 by default: https://github.com/ansible/awx/pull/8943 + **Note:** users who encounter permissions errors at upgrade time should `chown -R ~/.awx/pgdocker` to ensure it's owned by the user running the install playbook +- Added support for region name for OpenStack inventory: https://github.com/ansible/awx/issues/5080 +- Added the ability to chain undefined attributes in custom notification templates: https://github.com/ansible/awx/issues/8677 +- Dramatically simplified the `image_build` role: https://github.com/ansible/awx/pull/8980 +- Fixed a bug which can cause schema migrations to fail at install time: https://github.com/ansible/awx/issues/9077 +- Fixed a bug which caused the `is_superuser` user property to be out of date in certain circumstances: https://github.com/ansible/awx/pull/8833 +- Fixed a bug which sometimes results in race conditions on setting access: https://github.com/ansible/awx/pull/8580 +- Fixed a bug which sometimes causes an unexpected delay in stdout for some playbooks: https://github.com/ansible/awx/issues/9085 +- (UI) Added support for credential password prompting on job launch: https://github.com/ansible/awx/pull/9028 +- (UI) Added the ability to configure LDAP settings in the UI: https://github.com/ansible/awx/issues/8291 +- (UI) Added a sync button to the Project detail view: https://github.com/ansible/awx/issues/8847 +- (UI) Added a form for configuring Google Outh 2.0 settings: https://github.com/ansible/awx/pull/8762 +- (UI) Added searchable keys and related keys to the Credentials list: https://github.com/ansible/awx/issues/8603 +- (UI) Added support for advanced search and copying to Notification Templates: https://github.com/ansible/awx/issues/7879 +- (UI) Added support for prompting on workflow nodes: https://github.com/ansible/awx/issues/5913 +- (UI) Added support for session timeouts: https://github.com/ansible/awx/pull/8250 +- (UI) Fixed a bug that broke websocket streaming for the insecure ws:// protocol: https://github.com/ansible/awx/pull/8877 +- (UI) Fixed a bug in the user interface when a translation for the browser's preferred locale isn't available: https://github.com/ansible/awx/issues/8884 +- (UI) Fixed bug where navigating from one survey question form directly to another wasn't reloading the form: https://github.com/ansible/awx/issues/7522 +- (UI) Fixed a bug which can cause an uncaught error while launching a Job Template: https://github.com/ansible/awx/issues/8936 +- Updated autobahn to address CVE-2020-35678 + +## 16.0.0 (December 10, 2020) +- AWX now ships with a reimagined user interface. **Please read this before upgrading:** https://groups.google.com/g/awx-project/c/KuT5Ao92HWo +- Removed support for syncing inventory from Red Hat CloudForms - https://github.com/ansible/awx/commit/0b701b3b2 +- Removed support for Mercurial-based project updates - https://github.com/ansible/awx/issues/7932 +- Upgraded NodeJS to actively maintained LTS 14.15.1 - https://github.com/ansible/awx/pull/8766 +- Added Git-LFS to the default image build - https://github.com/ansible/awx/pull/8700 +- Added the ability to specify `metadata.labels` in the podspec for container groups - https://github.com/ansible/awx/issues/8486 +- Added support for Kubernetes pod annotations - https://github.com/ansible/awx/pull/8434 +- Added the ability to label the web container in local Docker installs - https://github.com/ansible/awx/pull/8449 +- Added additional metadata (as an extra var) to playbook runs to report the SCM branch name - https://github.com/ansible/awx/pull/8433 +- Fixed a bug that caused k8s installations to fail due to an incorrect Helm repo - https://github.com/ansible/awx/issues/8715 +- Fixed a bug that prevented certain Workflow Approval resources from being deleted - https://github.com/ansible/awx/pull/8612 +- Fixed a bug that prevented the deletion of inventories stuck in "pending deletion" state - https://github.com/ansible/awx/issues/8525 +- Fixed a display bug in webhook notifications with certain unicode characters - https://github.com/ansible/awx/issues/7400 +- Improved support for exporting dependent objects (Inventory Hosts and Groups) in the `awx export` CLI tool - https://github.com/ansible/awx/commit/607bc0788 + +## 15.0.1 (October 20, 2020) +- Added several optimizations to improve performance for a variety of high-load simultaneous job launch use cases https://github.com/ansible/awx/pull/8403 +- Added the ability to source roles and collections from requirements.yaml files (not just requirements.yml) - https://github.com/ansible/awx/issues/4540 +- awx.awx collection modules now provide a clearer error message for incompatible versions of awxkit - https://github.com/ansible/awx/issues/8127 +- Fixed a bug in notification messages that contain certain unicode characters - https://github.com/ansible/awx/issues/7400 +- Fixed a bug that prevents the deletion of Workflow Approval records - https://github.com/ansible/awx/issues/8305 +- Fixed a bug that broke the selection of webhook credentials - https://github.com/ansible/awx/issues/7892 +- Fixed a bug which can cause confusing behavior for social auth logins across distinct browser tabs - https://github.com/ansible/awx/issues/8154 +- Fixed several bugs in the output of Workflow Job Templates using the `awx export` tool - https://github.com/ansible/awx/issues/7798 https://github.com/ansible/awx/pull/7847 +- Fixed a race condition that can lead to missing hosts when running parallel inventory syncs - https://github.com/ansible/awx/issues/5571 +- Fixed an HTTP 500 error when certain LDAP group parameters aren't properly set - https://github.com/ansible/awx/issues/7622 +- Updated a few dependencies in response to several CVEs: + * CVE-2020-7720 + * CVE-2020-7743 + * CVE-2020-7676 + +## 15.0.0 (September 30, 2020) +- Added improved support for fetching Ansible collections from private Galaxy content sources (such as https://github.com/ansible/galaxy_ng) - https://github.com/ansible/awx/issues/7813 + **Note:** as part of this change, new Organizations created in the AWX API will _no longer_ automatically synchronize roles and collections from galaxy.ansible.com by default. More details on this change can be found at: https://github.com/ansible/awx/issues/8341#issuecomment-707310633 +- AWX now utilizes a version of certifi that auto-discovers certificates in the system certificate store - https://github.com/ansible/awx/pull/8242 +- Added support for arbitrary custom inventory plugin configuration: https://github.com/ansible/awx/issues/5150 +- Added an optional setting to disable the auto-creation of organizations and teams on successful SAML login. - https://github.com/ansible/awx/pull/8069 +- Added a number of optimizations to AWX's callback receiver to improve the speed of stdout processing for simultaneous playbooks runs - https://github.com/ansible/awx/pull/8193 https://github.com/ansible/awx/pull/8191 +- Added the ability to use `!include` and `!import` constructors when constructing YAML for use with the AWX CLI - https://github.com/ansible/awx/issues/8135 +- Fixed a bug that prevented certain users from being able to edit approval nodes in Workflows - https://github.com/ansible/awx/pull/8253 +- Fixed a bug that broke password prompting for credentials in certain cases - https://github.com/ansible/awx/issues/8202 +- Fixed a bug which can cause PostgreSQL deadlocks when running many parallel playbooks against large shared inventories - https://github.com/ansible/awx/issues/8145 +- Fixed a bug which can cause delays in AWX's task manager when large numbers of simultaneous jobs are scheduled - https://github.com/ansible/awx/issues/7655 +- Fixed a bug which can cause certain scheduled jobs - those that run every X minute(s) or hour(s) - to fail to run at the proper time - https://github.com/ansible/awx/issues/8071 +- Fixed a performance issue for playbooks that store large amounts of data using the `set_stats` module - https://github.com/ansible/awx/issues/8006 +- Fixed a bug related to AWX's handling of the auth_path argument for the HashiVault KeyValue credential plugin - https://github.com/ansible/awx/pull/7991 +- Fixed a bug that broke support for Remote Archive SCM Type project syncs on platforms that utilize Python2 - https://github.com/ansible/awx/pull/8057 +- Updated to the latest version of Django Rest Framework to address CVE-2020-25626 +- Updated to the latest version of Django to address CVE-2020-24583 and CVE-2020-24584 +- Updated to the latest verson of channels_redis to address a bug that slowly causes Daphne processes to leak memory over time - https://github.com/django/channels_redis/issues/212 + +## 14.1.0 (Aug 25, 2020) +- AWX images can now be built on ARM64 - https://github.com/ansible/awx/pull/7607 +- Added the Remote Archive SCM Type to support using immutable artifacts and releases (such as tarballs and zip files) as projects - https://github.com/ansible/awx/issues/7954 +- Deprecated official support for Mercurial-based project updates - https://github.com/ansible/awx/issues/7932 +- Added resource import/export support to the official AWX collection - https://github.com/ansible/awx/issues/7329 +- Added the ability to import YAML-based resources (instead of just JSON) when using the AWX CLI - https://github.com/ansible/awx/pull/7808 +- Users upgrading from older versions of AWX may encounter an issue that causes their postgres container to restart in a loop (https://github.com/ansible/awx/issues/7854) - if you encounter this, bring your containers down and then back up (e.g., `docker-compose down && docker-compose up -d`) after upgrading to 14.1.0. +- Updated the AWX CLI to export labels associated with Workflow Job Templates - https://github.com/ansible/awx/pull/7847 +- Updated to the latest python-ldap to address a bug - https://github.com/ansible/awx/issues/7868 +- Upgraded git-python to fix a bug that caused workflows to sometimes fail - https://github.com/ansible/awx/issues/6119 +- Worked around a bug in the channels_redis library that slowly causes Daphne processes to leak memory over time - https://github.com/django/channels_redis/issues/212 +- Fixed a bug in the AWX CLI that prevented Workflow nodes from importing properly - https://github.com/ansible/awx/issues/7793 +- Fixed a bug in the awx.awx collection release process that templated the wrong version - https://github.com/ansible/awx/issues/7870 +- Fixed a bug that caused errors rendering stdout that contained UTF-16 surrogate pairs - https://github.com/ansible/awx/pull/7918 + +## 14.0.0 (Aug 6, 2020) +- As part of our commitment to inclusivity in open source, we recently took some time to audit AWX's source code and user interface and replace certain terminology with more inclusive language. Strictly speaking, this isn't a bug or a feature, but we think it's important and worth calling attention to: + * https://github.com/ansible/awx/commit/78229f58715fbfbf88177e54031f532543b57acc + * https://www.redhat.com/en/blog/making-open-source-more-inclusive-eradicating-problematic-language +- Installing roles and collections via requirements.yml as part of Project Updates now requires at least Ansible 2.9 - https://github.com/ansible/awx/issues/7769 +- Deprecated the use of the `PRIMARY_GALAXY_USERNAME` and `PRIMARY_GALAXY_PASSWORD` settings. We recommend using tokens to access Galaxy or Automation Hub. +- Added local caching for downloaded roles and collections so they are not re-downloaded on nodes where they are up to date with the project - https://github.com/ansible/awx/issues/5518 +- Added the ability to associate K8S/OpenShift credentials to Job Template for playbook interaction with the `community.kubernetes` collection - https://github.com/ansible/awx/issues/5735 +- Added the ability to include HTML in the Custom Login Info presented on the login page - https://github.com/ansible/awx/issues/7600 +- Fixed https://access.redhat.com/security/cve/cve-2020-14327 - Server-side request forgery on credentials +- Fixed https://access.redhat.com/security/cve/cve-2020-14328 - Server-side request forgery on webhooks +- Fixed https://access.redhat.com/security/cve/cve-2020-14329 - Sensitive data exposure on labels +- Fixed https://access.redhat.com/security/cve/cve-2020-14337 - Named URLs allow for testing the presence or absence of objects +- Fixed a number of bugs in the user interface related to an upgrade of jQuery: + * https://github.com/ansible/awx/issues/7530 + * https://github.com/ansible/awx/issues/7546 + * https://github.com/ansible/awx/issues/7534 + * https://github.com/ansible/awx/issues/7606 +- Fixed a bug that caused the `-f yaml` flag of the AWX CLI to not print properly formatted YAML - https://github.com/ansible/awx/issues/7795 +- Fixed a bug in the installer that caused errors when `docker_registry_password` was set - https://github.com/ansible/awx/issues/7695 +- Fixed a permissions error that prevented certain users from starting AWX services - https://github.com/ansible/awx/issues/7545 +- Fixed a bug that allows superusers to run unsafe Jinja code when defining custom Credential Types - https://github.com/ansible/awx/pull/7584/ +- Fixed a bug that prevented users from creating (or editing) custom Credential Types containing boolean fields - https://github.com/ansible/awx/issues/7483 +- Fixed a bug that prevented users with postgres usernames containing uppercase letters from restoring backups succesfully - https://github.com/ansible/awx/pull/7519 +- Fixed a bug which allowed the creation (in the Tower API) of Groups and Hosts with the same name - https://github.com/ansible/awx/issues/4680 + +## 13.0.0 (Jun 23, 2020) +- Added import and export commands to the official AWX CLI, replacing send and receive from the old tower-cli (https://github.com/ansible/awx/pull/6125). +- Removed scripts as a means of running inventory updates of built-in types (https://github.com/ansible/awx/pull/6911) +- Ansible 2.8 is now partially unsupported; some inventory source types are known to no longer work. +- Fixed an issue where the vmware inventory source ssl_verify source variable was not recognized (https://github.com/ansible/awx/pull/7360) +- Fixed a bug that caused redis' listen socket to have too-permissive file permissions (https://github.com/ansible/awx/pull/7317) +- Fixed a bug that caused rsyslogd's configuration file to have world-readable file permissions, potentially leaking secrets (CVE-2020-10782) + +## 12.0.0 (Jun 9, 2020) +- Removed memcached as a dependency of AWX (https://github.com/ansible/awx/pull/7240) +- Moved to a single container image build instead of separate awx_web and awx_task images. The container image is just `awx` (https://github.com/ansible/awx/pull/7228) +- Official AWX container image builds now use a two-stage container build process that notably reduces the size of our published images (https://github.com/ansible/awx/pull/7017) +- Removed support for HipChat notifications ([EoL announcement](https://www.atlassian.com/partnerships/slack/faq#faq-98b17ca3-247f-423b-9a78-70a91681eff0)); all previously-created HipChat notification templates will be deleted due to this removal. +- Fixed a bug which broke AWX installations with oc version 4.3 (https://github.com/ansible/awx/pull/6948/) +- Fixed a performance issue that caused notable delay of stdout processing for playbooks run against large numbers of hosts (https://github.com/ansible/awx/issues/6991) +- Fixed a bug that caused CyberArk AIM credential plugin looks to hang forever in some environments (https://github.com/ansible/awx/issues/6986) +- Fixed a bug that caused ANY/ALL converage settings not to properly save when editing approval nodes in the UI (https://github.com/ansible/awx/issues/6998) +- Fixed a bug that broke support for the satellite6_group_prefix source variable (https://github.com/ansible/awx/issues/7031) +- Fixed a bug that prevented changes to workflow node convergence settings when approval nodes were in use (https://github.com/ansible/awx/issues/7063) +- Fixed a bug that caused notifications to fail on newer version of Mattermost (https://github.com/ansible/awx/issues/7264) +- Fixed a bug (by upgrading to 0.8.1 of the foreman collection) that prevented host_filters from working properly with Foreman-based inventory (https://github.com/ansible/awx/issues/7225) +- Fixed a bug that prevented the usage of the Conjur credential plugin with secrets that contain spaces (https://github.com/ansible/awx/issues/7191) +- Fixed a bug in awx-manage run_wsbroadcast --status in kubernetes (https://github.com/ansible/awx/pull/7009) +- Fixed a bug that broke notification toggles for system jobs in the UI (https://github.com/ansible/awx/pull/7042) +- Fixed a bug that broke local pip installs of awxkit (https://github.com/ansible/awx/issues/7107) +- Fixed a bug that prevented PagerDuty notifications from sending for workflow job template approvals (https://github.com/ansible/awx/issues/7094) +- Fixed a bug that broke external log aggregation support for URL paths that include the = character (such as the tokens for SumoLogic) (https://github.com/ansible/awx/issues/7139) +- Fixed a bug that prevented organization admins from removing labels from workflow job templates (https://github.com/ansible/awx/pull/7143) + +## 11.2.0 (Apr 29, 2020) + +- Inventory updates now use collection-based plugins by default (in Ansible 2.9+): + - amazon.aws.aws_ec2 + - community.vmware.vmware_vm_inventory + - azure.azcollection.azure_rm + - google.cloud.gcp_compute + - theforeman.foreman.foreman + - openstack.cloud.openstack + - ovirt.ovirt_collection.ovirt + - awx.awx.tower +- Added support for Approle and LDAP/AD mechanisms to the Hashicorp Vault credential plugin (https://github.com/ansible/awx/issues/5076) +- Added Project (Domain Name) support for the OpenStack Keystone v3 API (https://github.com/ansible/awx/issues/6831) +- Added a new setting for raising log verbosity for rsyslogd (https://github.com/ansible/awx/pull/6818) +- Added the ability to monitor stdout in the CLI for running jobs and workflow jobs (https://github.com/ansible/awx/issues/6165) +- Fixed a bug which prevented the AWX CLI from properly installing with newer versions of pip (https://github.com/ansible/awx/issues/6870) +- Fixed a bug which broke AWX's external logging support when configured with HTTPS endpoints that utilize self-signed certificates (https://github.com/ansible/awx/issues/6851) +- Fixed a local docker installer bug that mistakenly attempted to upgrade PostgreSQL when an external pg_hostname is specified (https://github.com/ansible/awx/pull/5398) +- Fixed a race condition that caused task container crashes when pods are quickly brought down and back up (https://github.com/ansible/awx/issues/6750) +- Fixed a bug that caused 404 errors when attempting to view the second page of the workflow approvals view (https://github.com/ansible/awx/issues/6803) +- Fixed a bug that prevented the use of ANSIBLE_SSH_ARGS for ad-hoc-commands (https://github.com/ansible/awx/pull/6811) +- Fixed a bug that broke AWX installs/upgrades on Red Hat OpenShift (https://github.com/ansible/awx/issues/6791) + + +## 11.1.0 (Apr 22, 2020) +- Changed rsyslogd to persist queued events to disk (to prevent a risk of out-of-memory errors) (https://github.com/ansible/awx/issues/6746) +- Added the ability to configure the destination and maximum disk size of rsyslogd spool (in the event of a log aggregator outage) (https://github.com/ansible/awx/pull/6763) +- Added the ability to discover playbooks in project clones from symlinked directories (https://github.com/ansible/awx/pull/6773) +- Fixed a bug that caused certain log aggregator settings to break logging integration (https://github.com/ansible/awx/issues/6760) +- Fixed a bug that caused playbook execution in container groups to sometimes unexpectedly deadlock (https://github.com/ansible/awx/issues/6692) +- Improved stability of the new redis clustering implementation (https://github.com/ansible/awx/pull/6739 https://github.com/ansible/awx/pull/6720) +- Improved stability of the new rsyslogd-based logging implementation (https://github.com/ansible/awx/pull/6796) + +## 11.0.0 (Apr 16, 2020) +- As of AWX 11.0.0, Kubernetes-based deployments use a Deployment rather than a StatefulSet. +- Reimplemented external logging support using rsyslogd to improve reliability and address a number of issues (https://github.com/ansible/awx/issues/5155) +- Changed activity stream logs to include summary fields for related objects (https://github.com/ansible/awx/issues/1761) +- Added code to more gracefully attempt to reconnect to redis if it restarts/becomes unavailable (https://github.com/ansible/awx/pull/6670) +- Fixed a bug that caused REFRESH_TOKEN_EXPIRE_SECONDS to not properly be respected for OAuth2.0 refresh tokens generated by AWX (https://github.com/ansible/awx/issues/6630) +- Fixed a bug that broke schedules containing RRULES with very old DTSTART dates (https://github.com/ansible/awx/pull/6550) +- Fixed a bug that broke installs on older versions of Ansible packaged with certain Linux distributions (https://github.com/ansible/awx/issues/5501) +- Fixed a bug that caused the activity stream to sometimes report the incorrect actor when associating user membership on SAML login (https://github.com/ansible/awx/pull/6525) +- Fixed a bug in AWX's Grafana notification support when annotation tags are omitted (https://github.com/ansible/awx/issues/6580) +- Fixed a bug that prevented some users from searching for Source Control credentials in the AWX user interface (https://github.com/ansible/awx/issues/6600) +- Fixed a bug that prevented disassociating orphaned users from credentials (https://github.com/ansible/awx/pull/6554) +- Updated Twisted to address CVE-2020-10108 and CVE-2020-10109. + +## 10.0.0 (Mar 30, 2020) +- As of AWX 10.0.0, the official AWX CLI no longer supports Python 2 (it requires at least Python 3.6) (https://github.com/ansible/awx/pull/6327) +- AWX no longer relies on RabbitMQ; Redis is added as a new dependency (https://github.com/ansible/awx/issues/5443) +- Altered AWX's event tables to allow more than ~2 billion total events (https://github.com/ansible/awx/issues/6010) +- Improved the performance (time to execute, and memory consumption) of the periodic job cleanup system job (https://github.com/ansible/awx/pull/6166) +- Updated Job Templates so they now have an explicit Organization field (it is no longer inferred from the associated Project) (https://github.com/ansible/awx/issues/3903) +- Updated social-auth-core to address an upcoming GitHub API deprecation (https://github.com/ansible/awx/issues/5970) +- Updated to ansible-runner 1.4.6 to address various bugs. +- Updated Django to address CVE-2020-9402 +- Updated pyyaml version to address CVE-2017-18342 +- Fixed a bug which prevented the new `scm_branch` field from being used in custom notification templates (https://github.com/ansible/awx/issues/6258) +- Fixed a race condition that sometimes causes success/failure notifications to include an incomplete list of hosts (https://github.com/ansible/awx/pull/6290) +- Fixed a bug that can cause certain setting pages to lose unsaved form edits when a playbook is launched (https://github.com/ansible/awx/issues/5265) +- Fixed a bug that can prevent the "Use TLS/SSL" field from properly saving when editing email notification templates (https://github.com/ansible/awx/issues/6383) +- Fixed a race condition that sometimes broke event/stdout processing for jobs launched in container groups (https://github.com/ansible/awx/issues/6280) + +## 9.3.0 (Mar 12, 2020) +- Added the ability to specify an OAuth2 token description in the AWX CLI (https://github.com/ansible/awx/issues/6122) +- Added support for K8S service account annotations to the installer (https://github.com/ansible/awx/pull/6007) +- Added support for K8S imagePullSecrets to the installer (https://github.com/ansible/awx/pull/5989) +- Launching jobs (and workflows) using the --monitor flag in the AWX CLI now returns a non-zero exit code on job failure (https://github.com/ansible/awx/issues/5920) +- Improved UI performance for various job views when many simultaneous users are logged into AWX (https://github.com/ansible/awx/issues/5883) +- Updated to the latest version of Django to address a few open CVEs (https://github.com/ansible/awx/pull/6080) +- Fixed a critical bug which can cause AWX to hang and stop launching playbooks after a periodic of time (https://github.com/ansible/awx/issues/5617) +- Fixed a bug which caused delays in project update stdout for certain large SCM clones (as of Ansible 2.9+) (https://github.com/ansible/awx/pull/6254) +- Fixed a bug which caused certain smart inventory filters to mistakenly return duplicate hosts (https://github.com/ansible/awx/pull/5972) +- Fixed an unclear server error when creating smart inventories with the AWX collection (https://github.com/ansible/awx/issues/6250) +- Fixed a bug that broke Grafana notification support (https://github.com/ansible/awx/issues/6137) +- Fixed a UI bug which prevent users with read access to an organization from editing credentials for that organization (https://github.com/ansible/awx/pull/6241) +- Fixed a bug which prevent workflow approval records from recording a `started` and `elapsed` date (https://github.com/ansible/awx/issues/6202) +- Fixed a bug which caused workflow nodes to have a confusing option for `verbosity` (https://github.com/ansible/awx/issues/6196) +- Fixed an RBAC bug which prevented projects and inventory schedules from being created by certain users in certain contexts (https://github.com/ansible/awx/issues/5717) +- Fixed a bug that caused `role_path` in a project's config to not be respected due to an error processing `/etc/ansible/ansible.cfg` (https://github.com/ansible/awx/pull/6038) +- Fixed a bug that broke inventory updates for installs with custom home directories for the awx user (https://github.com/ansible/awx/pull/6152) +- Fixed a bug that broke fact data collection when AWX encounters invalid/unexpected fact data (https://github.com/ansible/awx/issues/5935) + + +## 9.2.0 (Feb 12, 2020) +- Added the ability to configure the convergence behavior of workflow nodes https://github.com/ansible/awx/issues/3054 +- AWX now allows for a configurable global limit for fork count (per-job run). The default maximum is 200. https://github.com/ansible/awx/pull/5604 +- Added the ability to specify AZURE_PUBLIC_CLOUD (for e.g., Azure Government KeyVault support) for the Azure credential plugin https://github.com/ansible/awx/issues/5138 +- Added support for several additional parameters for Satellite dynamic inventory https://github.com/ansible/awx/pull/5598 +- Added a new field to jobs for tracking the date/time a job is cancelled https://github.com/ansible/awx/pull/5610 +- Made a series of additional optimizations to the callback receiver to further improve stdout write speed for running playbooks https://github.com/ansible/awx/pull/5677 https://github.com/ansible/awx/pull/5739 +- Updated AWX to be compatible with Helm 3.x (https://github.com/ansible/awx/pull/5776) +- Optimized AWX's job dependency/scheduling code to drastically improve processing time in scenarios where there are many pending jobs scheduled simultaneously https://github.com/ansible/awx/issues/5154 +- Fixed a bug which could cause SCM authentication details (basic auth passwords) to be reported to external loggers in certain failure scenarios (e.g., when a git clone fails and ansible itself prints an error message to stdout) https://github.com/ansible/awx/pull/5812 +- Fixed a k8s installer bug that caused installs to fail in certain situations https://github.com/ansible/awx/issues/5574 +- Fixed a number of issues that caused analytics gathering and reporting to run more often than necessary https://github.com/ansible/awx/pull/5721 +- Fixed a bug in the AWX CLI that prevented JSON-type settings from saving properly https://github.com/ansible/awx/issues/5528 +- Improved support for fetching custom virtualenv dependencies when AWX is installed behind a proxy https://github.com/ansible/awx/pull/5805 +- Updated the bundled version of openstacksdk to address a known issue https://github.com/ansible/awx/issues/5821 +- Updated the bundled vmware_inventory plugin to the latest version to address a bug https://github.com/ansible/awx/pull/5668 +- Fixed a bug that can cause inventory updates to fail to properly save their output when run within a workflow https://github.com/ansible/awx/pull/5666 +- Removed a number of pre-computed fields from the Host and Group models to improve AWX performance. As part of this change, inventory group UIs throughout the interface no longer display status icons https://github.com/ansible/awx/pull/5448 + +## 9.1.1 (Jan 14, 2020) + +- Fixed a bug that caused database migrations on Kubernetes installs to hang https://github.com/ansible/awx/pull/5579 +- Upgraded Python-level app dependencies in AWX virtual environment https://github.com/ansible/awx/pull/5407 +- Running jobs no longer block associated inventory updates https://github.com/ansible/awx/pull/5519 +- Fixed invalid_response SAML error https://github.com/ansible/awx/pull/5577 +- Optimized the callback receiver to drastically improve the write speed of stdout for parallel jobs (https://github.com/ansible/awx/pull/5618) + +## 9.1.0 (Dec 17, 2019) +- Added a command to generate a new SECRET_KEY and rekey the secrets in the database +- Removed project update locking when jobs using it are running +- Fixed slow queries for /api/v2/instances and /api/v2/instance_groups when smart inventories are used +- Fixed a partial password disclosure when special characters existed in the RabbitMQ password (CVE-2019-19342) +- Fixed hang in error handling for source control checkouts +- Fixed an error on subsequent job runs that override the branch of a project on an instance that did not have a prior project checkout +- Fixed an issue where jobs launched in isolated or container groups would incorrectly timeout +- Fixed an incorrect link to instance groups documentation in the user interface +- Fixed editing of inventory on Workflow templates +- Fixed multiple issues with OAuth2 token cleanup system jobs +- Fixed a bug that broke email notifications for workflow approval/deny https://github.com/ansible/awx/issues/5401 +- Updated SAML implementation to automatically login if authorization already exists +- Updated AngularJS to 1.7.9 for CVE-2019-10768 + +## 9.0.1 (Nov 4, 2019) + +- Fixed a bug in the installer that broke certain types of k8s installs https://github.com/ansible/awx/issues/5205 + +## 9.0.0 (Oct 31, 2019) + +- Updated AWX images to use centos:8 as the parent image. +- Updated to ansible-runner 1.4.4 to address various bugs. +- Added oc and kubectl to the AWX images to support new container-based execution introduced in 8.0.0. +- Added some optimizations to speed up the deletion of large Inventory Groups. +- Fixed a bug that broke webhook launches for Job Templates that define a survey (https://github.com/ansible/awx/issues/5062). +- Fixed a bug in the CLI which incorrectly parsed launch time arguments for `awx job_templates launch` and `awx workflow_job_templates launch` (https://github.com/ansible/awx/issues/5093). +- Fixed a bug that caused inventory updates using "sourced from a project" to stop working (https://github.com/ansible/awx/issues/4750). +- Fixed a bug that caused Slack notifications to sometimes show the wrong bot avatar (https://github.com/ansible/awx/pull/5125). +- Fixed a bug that prevented the use of digits in AWX's URL settings (https://github.com/ansible/awx/issues/5081). + +## 8.0.0 (Oct 21, 2019) + +- The Ansible Tower Ansible modules have been migrated to a new official Ansible AWX collection: https://galaxy.ansible.com/awx/AWX + Please note that this functionality is only supported in Ansible 2.9+ +- AWX now supports the ability to launch jobs from external webhooks (GitHub and GitLab integration are supported). +- AWX now supports Container Groups, a new feature that allows you to schedule and run playbooks on single-use kubernetes pods on-demand. +- AWX now supports sending notifications when Workflow steps are approved, denied, or time out. +- AWX now records the user who approved or denied Workflow steps. +- AWX now supports fetching Ansible Collections from private galaxy servers. +- AWX now checks the user's ansible.cfg for paths where role/collections may live when running project updates. +- AWX now uses PostgreSQL 10 by default. +- AWX now warns more loudly about underlying AMQP connectivity issues (https://github.com/ansible/awx/pull/4857). +- Added a few optimizations to drastically improve dashboard performance for larger AWX installs (installs with several hundred thousand jobs or more). +- Updated to the latest version of Ansible's VMWare inventory script (which adds support for vmware_guest_facts). +- Deprecated /api/v2/inventory_scripts/ (this endpoint - and the Custom Inventory Script feature - will be removed in a future release of AWX). +- Fixed a bug which prevented Organization Admins from removing users from their own Organization (https://github.com/ansible/awx/issues/2979) +- Fixed a bug which sometimes caused cluster nodes to fail to re-join with a cryptic error, "No instance found with the current cluster host id" (https://github.com/ansible/awx/issues/4294) +- Fixed a bug that prevented the use of launch-time passphrases when using credential plugins (https://github.com/ansible/awx/pull/4807) +- Fixed a bug that caused notifications assigned at the Organization level not to take effect for Workflows in that Organization (https://github.com/ansible/awx/issues/4712) +- Fixed a bug which caused a notable amount of CPU overhead on RabbitMQ health checks (https://github.com/ansible/awx/pull/5009) +- Fixed a bug which sometimes caused the key to stop functioning in -
No JSON data returned by the module
diff --git a/awx/ui/client/features/output/host-event/host-event-modal.partial.html b/awx/ui/client/features/output/host-event/host-event-modal.partial.html deleted file mode 100644 index 47676df8423a..000000000000 --- a/awx/ui/client/features/output/host-event/host-event-modal.partial.html +++ /dev/null @@ -1,72 +0,0 @@ - diff --git a/awx/ui/client/features/output/host-event/host-event-stderr.partial.html b/awx/ui/client/features/output/host-event/host-event-stderr.partial.html deleted file mode 100644 index e775d1768199..000000000000 --- a/awx/ui/client/features/output/host-event/host-event-stderr.partial.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
-
-
1
-
-
-
- diff --git a/awx/ui/client/features/output/host-event/host-event-stdout.partial.html b/awx/ui/client/features/output/host-event/host-event-stdout.partial.html deleted file mode 100644 index 96df87b16330..000000000000 --- a/awx/ui/client/features/output/host-event/host-event-stdout.partial.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
-
-
1
-
-
-
- diff --git a/awx/ui/client/features/output/host-event/host-event.controller.js b/awx/ui/client/features/output/host-event/host-event.controller.js deleted file mode 100644 index 280bf518183a..000000000000 --- a/awx/ui/client/features/output/host-event/host-event.controller.js +++ /dev/null @@ -1,170 +0,0 @@ -function HostEventsController ( - $scope, - $state, - HostEventService, - hostEvent -) { - $scope.processEventStatus = HostEventService.processEventStatus; - $scope.processResults = processResults; - $scope.isActiveState = isActiveState; - $scope.getActiveHostIndex = getActiveHostIndex; - $scope.closeHostEvent = closeHostEvent; - - function init () { - hostEvent.event_name = hostEvent.event; - $scope.event = _.cloneDeep(hostEvent); - - // grab standard out & standard error if present from the host - // event's 'res' object, for things like Ansible modules. Small - // wrinkle in this implementation is that the stdout/stderr tabs - // should be shown if the `res` object has stdout/stderr keys, even - // if they're a blank string. The presence of these keys is - // potentially significant to a user. - if (_.has(hostEvent.event_data, 'task_action')) { - $scope.module_name = hostEvent.event_data.task_action; - } else if (!_.has(hostEvent.event_data, 'task_action')) { - $scope.module_name = 'No result found'; - } - - if (_.has(hostEvent.event_data, 'res.stdout')) { - if (hostEvent.event_data.res.stdout === '') { - $scope.stdout = ' '; - } else { - $scope.stdout = hostEvent.event_data.res.stdout; - } - } - - if (_.has(hostEvent.event_data, 'res.stderr')) { - if (hostEvent.event_data.res.stderr === '') { - $scope.stderr = ' '; - } else { - $scope.stderr = hostEvent.event_data.res.stderr; - } - } - - if (_.has(hostEvent.event_data, 'res')) { - $scope.json = hostEvent.event_data.res; - } - - if ($scope.module_name === 'debug' && - _.has(hostEvent.event_data, 'res.result.stdout')) { - $scope.stdout = hostEvent.event_data.res.result.stdout; - } - if ($scope.module_name === 'yum' && - _.has(hostEvent.event_data, 'res.results') && - _.isArray(hostEvent.event_data.res.results)) { - const event = hostEvent.event_data.res.results; - $scope.stdout = event[0];// eslint-disable-line prefer-destructuring - } - // instantiate Codemirror - if ($state.current.name === 'output.host-event.json') { - try { - if (_.has(hostEvent.event_data, 'res')) { - initCodeMirror( - 'HostEvent-codemirror', - JSON.stringify($scope.json, null, 4), - { name: 'javascript', json: true } - ); - resize(); - } else { - $scope.no_json = true; - } - } catch (err) { - // element with id HostEvent-codemirror is not the view - // controlled by this instance of HostEventController - } - } else if ($state.current.name === 'output.host-event.stdout') { - try { - resize(); - } catch (err) { - // element with id HostEvent-codemirror is not the view - // controlled by this instance of HostEventController - } - } else if ($state.current.name === 'output.host-event.stderr') { - try { - resize(); - } catch (err) { - // element with id HostEvent-codemirror is not the view - // controlled by this instance of HostEventController - } - } - $('#HostEvent').modal('show'); - $('.modal-content').resizable({ - minHeight: 523, - minWidth: 600 - }); - $('.modal-dialog').draggable({ - cancel: '.HostEvent-view--container' - }); - - function resize () { - if ($state.current.name === 'output.host-event.json') { - const editor = $('.CodeMirror')[0].CodeMirror; - const height = $('.modal-dialog').height() - $('.HostEvent-header').height() - $('.HostEvent-details').height() - $('.HostEvent-nav').height() - $('.HostEvent-controls').height() - 120; - editor.setSize('100%', height); - } else if ($state.current.name === 'output.host-event.stdout' || $state.current.name === 'output.host-event.stderr') { - const height = $('.modal-dialog').height() - $('.HostEvent-header').height() - $('.HostEvent-details').height() - $('.HostEvent-nav').height() - $('.HostEvent-controls').height() - 120; - $('.HostEvent-stdout').width('100%'); - $('.HostEvent-stdout').height(height); - $('.HostEvent-stdoutContainer').height(height); - $('.HostEvent-numberColumnPreload').height(height); - } - } - - $('.modal-dialog').on('resize', resize); - - $('#HostEvent').on('hidden.bs.modal', $scope.closeHostEvent); - } - - function processResults (value) { - if (typeof value === 'object') { - return false; - } - return true; - } - - function initCodeMirror (el, data, mode) { - const container = document.getElementById(el); - const options = {}; - options.lineNumbers = true; - options.mode = mode; - options.readOnly = true; - options.scrollbarStyle = null; - const editor = CodeMirror.fromTextArea(// eslint-disable-line no-undef - container, - options - ); - editor.setSize('100%', 200); - editor.getDoc().setValue(data); - } - - function isActiveState (name) { - return $state.current.name === name; - } - - function getActiveHostIndex () { - function hostResultfilter (obj) { - return obj.id === $scope.event.id; - } - const result = $scope.hostResults.filter(hostResultfilter); - return $scope.hostResults.indexOf(result[0]); - } - - function closeHostEvent () { - // Unbind the listener so it doesn't fire when we close the modal via navigation - $('#HostEvent').off('hidden.bs.modal'); - $('#HostEvent').modal('hide'); - $state.go('output'); - } - $scope.init = init; - $scope.init(); -} - -HostEventsController.$inject = [ - '$scope', - '$state', - 'HostEventService', - 'hostEvent', -]; - -module.exports = HostEventsController; diff --git a/awx/ui/client/features/output/host-event/host-event.route.js b/awx/ui/client/features/output/host-event/host-event.route.js deleted file mode 100644 index aba9273327a3..000000000000 --- a/awx/ui/client/features/output/host-event/host-event.route.js +++ /dev/null @@ -1,72 +0,0 @@ -const HostEventModalTemplate = require('~features/output/host-event/host-event-modal.partial.html'); -const HostEventCodeMirrorTemplate = require('~features/output/host-event/host-event-codemirror.partial.html'); -const HostEventStdoutTemplate = require('~features/output/host-event/host-event-stdout.partial.html'); -const HostEventStderrTemplate = require('~features/output/host-event/host-event-stderr.partial.html'); - -function exit () { - // close the modal - // using an onExit event to handle cases where the user navs away - // using the url bar / back and not modal "X" - $('#HostEvent').modal('hide'); - // hacky way to handle user browsing away via URL bar - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); -} - -function HostEventResolve (HostEventService, $stateParams) { - return HostEventService.getRelatedJobEvents($stateParams.id, $stateParams.type, { - id: $stateParams.eventId - }).then((response) => response.data.results[0]); -} - -HostEventResolve.$inject = [ - 'HostEventService', - '$stateParams', -]; - -const hostEventModal = { - name: 'output.host-event', - url: '/host-event/:eventId', - controller: 'HostEventsController', - templateUrl: HostEventModalTemplate, - abstract: false, - ncyBreadcrumb: { - skip: true - }, - resolve: { - hostEvent: HostEventResolve - }, - onExit: exit -}; - -const hostEventJson = { - name: 'output.host-event.json', - url: '/json', - controller: 'HostEventsController', - templateUrl: HostEventCodeMirrorTemplate, - ncyBreadcrumb: { - skip: true - }, -}; - -const hostEventStdout = { - name: 'output.host-event.stdout', - url: '/stdout', - controller: 'HostEventsController', - templateUrl: HostEventStdoutTemplate, - ncyBreadcrumb: { - skip: true - }, -}; - -const hostEventStderr = { - name: 'output.host-event.stderr', - url: '/stderr', - controller: 'HostEventsController', - templateUrl: HostEventStderrTemplate, - ncyBreadcrumb: { - skip: true - }, -}; - -export { hostEventJson, hostEventModal, hostEventStdout, hostEventStderr }; diff --git a/awx/ui/client/features/output/host-event/host-event.service.js b/awx/ui/client/features/output/host-event/host-event.service.js deleted file mode 100644 index 1e0588b329a9..000000000000 --- a/awx/ui/client/features/output/host-event/host-event.service.js +++ /dev/null @@ -1,92 +0,0 @@ -function HostEventService ( - Rest, - ProcessErrors, - GetBasePath, - $rootScope -) { - this.getUrl = (id, type, params) => { - const queryString = this.stringifyParams(params); - - let baseUrl; - let related; - - if (type === 'playbook') { - baseUrl = GetBasePath('jobs'); - related = 'job_events'; - } - - if (type === 'command') { - baseUrl = GetBasePath('ad_hoc_commands'); - related = 'events'; - } - - if (type === 'project') { - baseUrl = GetBasePath('project_updates'); - related = 'events'; - } - - return `${baseUrl}${id}/${related}/?${queryString}`; - }; - - // GET events related to a job run - // e.g. - // ?event=playbook_on_stats - // ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter - this.getRelatedJobEvents = (id, type, params) => { - const url = this.getUrl(id, type, params); - Rest.setUrl(url); - return Rest.get() - .then(response => response) - .catch(({ data, status }) => { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: `Call to ${url}. GET returned: ${status}` }); - }); - }; - - this.stringifyParams = params => { - function reduceFunction (result, value, key) { - return `${result}${key}=${value}&`; - } - return _.reduce(params, reduceFunction, ''); - }; - - // Generate a helper class for job_event statuses - // the stack for which status to display is - // unreachable > failed > changed > ok - // uses the API's runner events and convenience properties .failed .changed to determine status. - // see: job_event_callback.py for more filters to support - this.processEventStatus = event => { - const obj = {}; - if (event.event === 'runner_on_unreachable') { - obj.class = 'HostEvent-status--unreachable'; - obj.status = 'unreachable'; - } - // equiv to 'runner_on_error' && 'runner on failed' - if (event.failed) { - obj.class = 'HostEvent-status--failed'; - obj.status = 'failed'; - } - // catch the changed case before ok, because both can be true - if (event.changed) { - obj.class = 'HostEvent-status--changed'; - obj.status = 'changed'; - } - if (event.event === 'runner_on_ok' || event.event === 'runner_on_async_ok') { - obj.class = 'HostEvent-status--ok'; - obj.status = 'ok'; - } - if (event.event === 'runner_on_skipped') { - obj.class = 'HostEvent-status--skipped'; - obj.status = 'skipped'; - } - return obj; - }; -} - -HostEventService.$inject = [ - 'Rest', - 'ProcessErrors', - 'GetBasePath', - '$rootScope' -]; -export default HostEventService; diff --git a/awx/ui/client/features/output/host-event/index.js b/awx/ui/client/features/output/host-event/index.js deleted file mode 100644 index f00b0b36b4ce..000000000000 --- a/awx/ui/client/features/output/host-event/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import { - hostEventModal, - hostEventJson, - hostEventStdout, - hostEventStderr -} from './host-event.route'; -import controller from './host-event.controller'; -import service from './host-event.service'; - -const MODULE_NAME = 'hostEvents'; - -function hostEventRun ($stateExtender) { - $stateExtender.addState(hostEventModal); - $stateExtender.addState(hostEventJson); - $stateExtender.addState(hostEventStdout); - $stateExtender.addState(hostEventStderr); -} -hostEventRun.$inject = [ - '$stateExtender' -]; - -angular.module(MODULE_NAME, []) - .controller('HostEventsController', controller) - .service('HostEventService', service) - .run(hostEventRun); -export default MODULE_NAME; diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js deleted file mode 100644 index 935d0a7c7926..000000000000 --- a/awx/ui/client/features/output/index.controller.js +++ /dev/null @@ -1,363 +0,0 @@ -let $compile; -let $q; -let $scope; -let page; -let render; -let resource; -let scroll; -let engine; -let status; - -let vm; -let streaming; -let listeners = []; - -function JobsIndexController ( - _resource_, - _page_, - _scroll_, - _render_, - _engine_, - _$scope_, - _$compile_, - _$q_, - _status_, -) { - vm = this || {}; - - $compile = _$compile_; - $scope = _$scope_; - $q = _$q_; - resource = _resource_; - - page = _page_; - scroll = _scroll_; - render = _render_; - engine = _engine_; - status = _status_; - - // Development helper(s) - vm.clear = devClear; - - // Expand/collapse - vm.expanded = false; - vm.toggleExpanded = toggleExpanded; - - // Panel - vm.resource = resource; - vm.title = resource.model.get('name'); - - // Stdout Navigation - vm.scroll = { - showBackToTop: false, - home: scrollHome, - end: scrollEnd, - down: scrollPageDown, - up: scrollPageUp - }; - - render.requestAnimationFrame(() => init()); -} - -function init () { - status.init({ - resource, - }); - - page.init({ - resource, - }); - - render.init({ - compile: html => $compile(html)($scope), - isStreamActive: engine.isActive, - }); - - scroll.init({ - isAtRest: scrollIsAtRest, - previous, - next, - }); - - engine.init({ - page, - scroll, - resource, - onEventFrame (events) { - return shift().then(() => append(events, true)); - }, - onStart () { - status.setJobStatus('running'); - }, - onStop () { - stopListening(); - status.updateStats(); - status.dispatch(); - } - }); - - streaming = false; - return next().then(() => startListening()); -} - -function stopListening () { - listeners.forEach(deregister => deregister()); - listeners = []; -} - -function startListening () { - stopListening(); - listeners.push($scope.$on(resource.ws.events, (scope, data) => handleJobEvent(data))); - listeners.push($scope.$on(resource.ws.status, (scope, data) => handleStatusEvent(data))); -} - -function handleStatusEvent (data) { - status.pushStatusEvent(data); -} - -function handleJobEvent (data) { - streaming = streaming || attachToRunningJob(); - streaming.then(() => { - engine.pushJobEvent(data); - status.pushJobEvent(data); - }); -} - -function attachToRunningJob () { - if (!status.state.running) { - return $q.resolve(); - } - - return page.last() - .then(events => { - if (!events) { - return $q.resolve(); - } - - const minLine = 1 + Math.max(...events.map(event => event.end_line)); - - return render.clear() - .then(() => engine.setMinLine(minLine)); - }); -} - -function next () { - return page.next() - .then(events => { - if (!events) { - return $q.resolve(); - } - - return shift() - .then(() => append(events)) - .then(() => { - if (scroll.isMissing()) { - return next(); - } - - return $q.resolve(); - }); - }); -} - -function previous () { - const initialPosition = scroll.getScrollPosition(); - let postPopHeight; - - return page.previous() - .then(events => { - if (!events) { - return $q.resolve(); - } - - return pop() - .then(() => { - postPopHeight = scroll.getScrollHeight(); - - return prepend(events); - }) - .then(() => { - const currentHeight = scroll.getScrollHeight(); - scroll.setScrollPosition(currentHeight - postPopHeight + initialPosition); - }); - }); -} - -function append (events, eng) { - return render.append(events) - .then(count => { - page.updateLineCount(count, eng); - }); -} - -function prepend (events) { - return render.prepend(events) - .then(count => { - page.updateLineCount(count); - }); -} - -function pop () { - if (!page.isOverCapacity()) { - return $q.resolve(); - } - - const lines = page.trim(); - - return render.pop(lines); -} - -function shift () { - if (!page.isOverCapacity()) { - return $q.resolve(); - } - - const lines = page.trim(true); - - return render.shift(lines); -} - -function scrollHome () { - if (scroll.isPaused()) { - return $q.resolve(); - } - - scroll.pause(); - - return page.first() - .then(events => { - if (!events) { - return $q.resolve(); - } - - return render.clear() - .then(() => prepend(events)) - .then(() => { - scroll.resetScrollPosition(); - scroll.resume(); - }) - .then(() => { - if (scroll.isMissing()) { - return next(); - } - - return $q.resolve(); - }); - }); -} - -function scrollEnd () { - if (engine.isActive()) { - if (engine.isTransitioning()) { - return $q.resolve(); - } - - if (engine.isPaused()) { - engine.resume(); - } else { - engine.pause(); - } - - return $q.resolve(); - } else if (scroll.isPaused()) { - return $q.resolve(); - } - - scroll.pause(); - - return page.last() - .then(events => { - if (!events) { - return $q.resolve(); - } - - return render.clear() - .then(() => append(events)); - }) - .then(() => { - scroll.setScrollPosition(scroll.getScrollHeight()); - scroll.resume(); - }); -} - -function scrollPageUp () { - if (scroll.isPaused()) { - return; - } - - scroll.pageUp(); -} - -function scrollPageDown () { - if (scroll.isPaused()) { - return; - } - - scroll.pageDown(); -} - -function scrollIsAtRest (isAtRest) { - vm.scroll.showBackToTop = !isAtRest; -} - -function toggleExpanded () { - vm.expanded = !vm.expanded; -} - -function devClear () { - render.clear().then(() => init()); -} - -// function showHostDetails (id) { -// jobEvent.request('get', id) -// .then(() => { -// const title = jobEvent.get('host_name'); - -// vm.host = { -// menu: true, -// stdout: jobEvent.get('stdout') -// }; - -// $scope.jobs.modal.show(title); -// }); -// } - -// function toggle (uuid, menu) { -// const lines = $(`.child-of-${uuid}`); -// let icon = $(`#${uuid} .at-Stdout-toggle > i`); - -// if (menu || record[uuid].level === 1) { -// vm.isExpanded = !vm.isExpanded; -// } - -// if (record[uuid].children) { -// icon = icon.add($(`#${record[uuid].children.join(', #')}`) -// .find('.at-Stdout-toggle > i')); -// } - -// if (icon.hasClass('fa-angle-down')) { -// icon.addClass('fa-angle-right'); -// icon.removeClass('fa-angle-down'); - -// lines.addClass('hidden'); -// } else { -// icon.addClass('fa-angle-down'); -// icon.removeClass('fa-angle-right'); - -// lines.removeClass('hidden'); -// } -// } - -JobsIndexController.$inject = [ - 'resource', - 'JobPageService', - 'JobScrollService', - 'JobRenderService', - 'JobEventEngine', - '$scope', - '$compile', - '$q', - 'JobStatusService', -]; - -module.exports = JobsIndexController; diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js deleted file mode 100644 index be7bf49b33f2..000000000000 --- a/awx/ui/client/features/output/index.js +++ /dev/null @@ -1,265 +0,0 @@ -import atLibModels from '~models'; -import atLibComponents from '~components'; - -import Strings from '~features/output/jobs.strings'; -import Controller from '~features/output/index.controller'; -import PageService from '~features/output/page.service'; -import RenderService from '~features/output/render.service'; -import ScrollService from '~features/output/scroll.service'; -import EngineService from '~features/output/engine.service'; -import StatusService from '~features/output/status.service'; -import MessageService from '~features/output/message.service'; -import EventsApiService from '~features/output/api.events.service'; -import LegacyRedirect from '~features/output/legacy.route'; - -import DetailsComponent from '~features/output/details.component'; -import SearchComponent from '~features/output/search.component'; -import StatsComponent from '~features/output/stats.component'; -import HostEvent from './host-event/index'; - -const Template = require('~features/output/index.view.html'); - -const MODULE_NAME = 'at.features.output'; - -const PAGE_CACHE = true; -const PAGE_LIMIT = 5; -const PAGE_SIZE = 50; -const WS_PREFIX = 'ws'; - -function resolveResource ( - $state, - Job, - ProjectUpdate, - AdHocCommand, - SystemJob, - WorkflowJob, - InventoryUpdate, - $stateParams, - qs, - Wait, - eventsApi, -) { - const { id, type, handleErrors } = $stateParams; - const { job_event_search } = $stateParams; // eslint-disable-line camelcase - - const { name, key } = getWebSocketResource(type); - - let Resource; - let related = 'events'; - - switch (type) { - case 'project': - Resource = ProjectUpdate; - break; - case 'playbook': - Resource = Job; - related = 'job_events'; - break; - case 'command': - Resource = AdHocCommand; - break; - case 'system': - Resource = SystemJob; - break; - case 'inventory': - Resource = InventoryUpdate; - break; - // case 'workflow': - // todo: integrate workflow chart components into this view - // break; - default: - // Redirect - return null; - } - - const params = { - page_size: PAGE_SIZE, - order_by: 'start_line', - }; - - const config = { - params, - pageCache: PAGE_CACHE, - pageLimit: PAGE_LIMIT, - }; - - if (job_event_search) { // eslint-disable-line camelcase - const query = qs.encodeQuerysetObject(qs.decodeArr(job_event_search)); - Object.assign(config.params, query); - } - - let model; - - Wait('start'); - const resourcePromise = new Resource(['get', 'options'], [id, id]) - .then(job => { - const endpoint = `${job.get('url')}${related}/`; - eventsApi.init(endpoint, config.params); - - const promises = [job.getStats(), eventsApi.fetch()]; - - if (job.has('related.labels')) { - promises.push(job.extend('get', 'labels')); - } - - model = job; - return Promise.all(promises); - }) - .then(([stats, events]) => ({ - id, - type, - stats, - model, - events, - related, - ws: { - events: `${WS_PREFIX}-${key}-${id}`, - status: `${WS_PREFIX}-${name}`, - }, - page: { - cache: PAGE_CACHE, - size: PAGE_SIZE, - pageLimit: PAGE_LIMIT - } - })); - - if (!handleErrors) { - return resourcePromise - .finally(() => Wait('stop')); - } - - return resourcePromise - .catch(({ data, status }) => { - qs.error(data, status); - return $state.go($state.current, $state.params, { reload: true }); - }) - .finally(() => Wait('stop')); -} - -function resolveWebSocketConnection ($stateParams, SocketService) { - const { type, id } = $stateParams; - const { name, key } = getWebSocketResource(type); - - const state = { - data: { - socket: { - groups: { - [name]: ['status_changed', 'summary'], - [key]: [] - } - } - } - }; - - return SocketService.addStateResolve(state, id); -} - -function getWebSocketResource (type) { - let name; - let key; - - switch (type) { - case 'system': - name = 'jobs'; - key = 'system_job_events'; - break; - case 'project': - name = 'jobs'; - key = 'project_update_events'; - break; - case 'command': - name = 'jobs'; - key = 'ad_hoc_command_events'; - break; - case 'inventory': - name = 'jobs'; - key = 'inventory_update_events'; - break; - case 'playbook': - name = 'jobs'; - key = 'job_events'; - break; - default: - throw new Error('Unsupported WebSocket type'); - } - - return { name, key }; -} - -function JobsRun ($stateRegistry, strings) { - const parent = 'jobs'; - const ncyBreadcrumb = { parent, label: strings.get('state.BREADCRUMB_DEFAULT') }; - - const state = { - url: '/:type/:id?job_event_search', - name: 'output', - parent, - ncyBreadcrumb, - params: { - handleErrors: true, - }, - data: { - activityStream: false, - }, - views: { - '@': { - templateUrl: Template, - controller: Controller, - controllerAs: 'vm' - }, - }, - resolve: { - webSocketConnection: [ - '$stateParams', - 'SocketService', - resolveWebSocketConnection - ], - resource: [ - '$state', - 'JobModel', - 'ProjectUpdateModel', - 'AdHocCommandModel', - 'SystemJobModel', - 'WorkflowJobModel', - 'InventoryUpdateModel', - '$stateParams', - 'QuerySet', - 'Wait', - 'JobEventsApiService', - resolveResource - ], - breadcrumbLabel: [ - 'resource', - ({ model }) => { - ncyBreadcrumb.label = `${model.get('id')} - ${model.get('name')}`; - } - ], - }, - }; - - $stateRegistry.register(state); -} - -JobsRun.$inject = ['$stateRegistry', 'JobStrings']; - -angular - .module(MODULE_NAME, [ - atLibModels, - atLibComponents, - HostEvent - ]) - .service('JobStrings', Strings) - .service('JobPageService', PageService) - .service('JobScrollService', ScrollService) - .service('JobRenderService', RenderService) - .service('JobEventEngine', EngineService) - .service('JobStatusService', StatusService) - .service('JobMessageService', MessageService) - .service('JobEventsApiService', EventsApiService) - .component('atJobSearch', SearchComponent) - .component('atJobStats', StatsComponent) - .component('atJobDetails', DetailsComponent) - .run(JobsRun) - .run(LegacyRedirect); - -export default MODULE_NAME; diff --git a/awx/ui/client/features/output/index.view.html b/awx/ui/client/features/output/index.view.html deleted file mode 100644 index cb932fafd3b3..000000000000 --- a/awx/ui/client/features/output/index.view.html +++ /dev/null @@ -1,64 +0,0 @@ -
-
- - - - - - -
- {{ vm.title }} -
- - - - -
-
- -
- -
- -
-
- -
-
- -
-
- -
- -
-
- -
-            
-                
-                    
-                        
-                        
-                        
-                    
-                
-                
-            
 
-
- -
-
-

-

Back to Top

-
- -
-
-
-
diff --git a/awx/ui/client/features/output/jobs.strings.js b/awx/ui/client/features/output/jobs.strings.js deleted file mode 100644 index c581039172f9..000000000000 --- a/awx/ui/client/features/output/jobs.strings.js +++ /dev/null @@ -1,35 +0,0 @@ -function JobsStrings (BaseString) { - BaseString.call(this, 'jobs'); - - const { t } = this; - const ns = this.jobs; - - ns.state = { - BREADCRUMB_DEFAULT: t.s('RESULTS'), - }; - - ns.status = { - RUNNING: t.s('The host status bar will update when the job is complete.'), - UNAVAILABLE: t.s('Host status information for this job is unavailable.'), - }; - - ns.resourceTooltips = { - USER: t.s('View the User'), - SCHEDULE: t.s('View the Schedule'), - INVENTORY: t.s('View the Inventory'), - CREDENTIAL: t.s('View the Credential'), - JOB_TEMPLATE: t.s('View the Job Template'), - SOURCE_WORKFLOW_JOB: t.s('View the source Workflow Job'), - PROJECT: t.s('View the Project'), - PROJECT_UPDATE: t.s('View Project checkout results') - }; - - ns.expandCollapse = { - EXPAND: t.s('Expand Output'), - COLLAPSE: t.s('Collapse Output') - }; -} - -JobsStrings.$inject = ['BaseStringService']; - -export default JobsStrings; diff --git a/awx/ui/client/features/output/legacy.route.js b/awx/ui/client/features/output/legacy.route.js deleted file mode 100644 index 4abf991dbb64..000000000000 --- a/awx/ui/client/features/output/legacy.route.js +++ /dev/null @@ -1,55 +0,0 @@ -function LegacyRedirect ($stateRegistry) { - const destination = 'output'; - const routes = [ - { - name: 'legacyJobResult', - url: '/jobs/:id?job_event_search', - redirectTo: (trans) => { - const { - id, - job_event_search // eslint-disable-line camelcase - } = trans.params(); - - return { state: destination, params: { type: 'playbook', id, job_event_search } }; - } - }, - { - name: 'legacyAdHocJobStdout', - url: '/ad_hoc_commands/:id', - redirectTo: (trans) => { - const { id } = trans.params(); - return { state: destination, params: { type: 'command', id } }; - } - }, - { - name: 'legacyInventorySyncStdout', - url: '/inventory_sync/:id', - redirectTo: (trans) => { - const { id } = trans.params(); - return { state: destination, params: { type: 'inventory', id } }; - } - }, - { - name: 'legacyManagementJobStdout', - url: '/management_jobs/:id', - redirectTo: (trans) => { - const { id } = trans.params(); - return { state: destination, params: { type: 'system', id } }; - } - }, - { - name: 'legacyScmUpdateStdout', - url: '/scm_update/:id', - redirectTo: (trans) => { - const { id } = trans.params(); - return { state: destination, params: { type: 'project', id } }; - } - }, - ]; - - routes.forEach(state => $stateRegistry.register(state)); -} - -LegacyRedirect.$inject = ['$stateRegistry']; - -export default LegacyRedirect; diff --git a/awx/ui/client/features/output/message.service.js b/awx/ui/client/features/output/message.service.js deleted file mode 100644 index 7e15ff302fbd..000000000000 --- a/awx/ui/client/features/output/message.service.js +++ /dev/null @@ -1,41 +0,0 @@ -function MessageService () { - const listeners = {}; - const registry = {}; - - this.subscribe = (key, listener) => { - registry[key] = registry[key] || 0; - - listeners[key] = listeners[key] || {}; - listeners[key][registry[key]] = listener; - - const unsubscribe = this.createCallback(key, registry[key]); - - registry[key]++; - - return unsubscribe; - }; - - this.dispatch = (key, data) => { - if (!listeners[key]) { - return; - } - - const indices = Object.keys(listeners[key]); - - for (let i = 0; i < indices.length; i++) { - listeners[key][indices[i]](data); - } - }; - - this.createCallback = (key, index) => { - const callback = () => { - if (listeners[key]) { - delete listeners[key][index]; - } - }; - - return callback; - }; -} - -export default MessageService; diff --git a/awx/ui/client/features/output/page.service.js b/awx/ui/client/features/output/page.service.js deleted file mode 100644 index 854bda23b028..000000000000 --- a/awx/ui/client/features/output/page.service.js +++ /dev/null @@ -1,283 +0,0 @@ -function JobPageService ($q) { - this.init = ({ resource }) => { - this.resource = resource; - this.api = this.resource.events; - - this.page = { - limit: this.resource.page.pageLimit, - size: this.resource.page.size, - cache: [], - state: { - count: 0, - current: 0, - first: 0, - last: 0 - } - }; - - this.bookmark = { - pending: false, - set: false, - cache: [], - state: { - count: 0, - first: 0, - last: 0, - current: 0 - } - }; - - this.result = { - limit: this.page.limit * this.page.size, - count: 0 - }; - - this.buffer = { - count: 0 - }; - }; - - this.addPage = (number, events, push, reference) => { - const page = { number, events, lines: 0 }; - reference = reference || this.getActiveReference(); - - if (push) { - reference.cache.push(page); - reference.state.last = page.number; - reference.state.first = reference.cache[0].number; - } else { - reference.cache.unshift(page); - reference.state.first = page.number; - reference.state.last = reference.cache[reference.cache.length - 1].number; - } - - reference.state.current = page.number; - reference.state.count++; - }; - - this.addToBuffer = event => { - const reference = this.getReference(); - const index = reference.cache.length - 1; - let pageAdded = false; - - if (this.result.count % this.page.size === 0) { - this.addPage(reference.state.current + 1, [event], true, reference); - - if (this.isBookmarkPending()) { - this.setBookmark(); - } - - this.trimBuffer(); - - pageAdded = true; - } else { - reference.cache[index].events.push(event); - } - - this.buffer.count++; - this.result.count++; - - return pageAdded; - }; - - this.trimBuffer = () => { - const reference = this.getReference(); - const diff = reference.cache.length - this.page.limit; - - if (diff <= 0) { - return; - } - - for (let i = 0; i < diff; i++) { - if (reference.cache[i].events) { - this.buffer.count -= reference.cache[i].events.length; - reference.cache[i].events.splice(0, reference.cache[i].events.length); - } - } - }; - - this.isBufferFull = () => { - if (this.buffer.count === 2) { - return true; - } - - return false; - }; - - this.emptyBuffer = () => { - const reference = this.getReference(); - let data = []; - - for (let i = 0; i < reference.cache.length; i++) { - const count = reference.cache[i].events.length; - - if (count > 0) { - this.buffer.count -= count; - data = data.concat(reference.cache[i].events.splice(0, count)); - } - } - - return data; - }; - - this.emptyCache = number => { - const reference = this.getActiveReference(); - - number = number || reference.state.current; - - reference.state.first = number; - reference.state.current = number; - reference.state.last = number; - - reference.cache.splice(0, reference.cache.length); - }; - - this.isOverCapacity = () => { - const reference = this.getActiveReference(); - - return (reference.cache.length - this.page.limit) > 0; - }; - - this.trim = left => { - const reference = this.getActiveReference(); - const excess = reference.cache.length - this.page.limit; - - let ejected; - - if (left) { - ejected = reference.cache.splice(0, excess); - reference.state.first = reference.cache[0].number; - } else { - ejected = reference.cache.splice(-excess); - reference.state.last = reference.cache[reference.cache.length - 1].number; - } - - return ejected.reduce((total, page) => total + page.lines, 0); - }; - - this.isPageBookmarked = number => number >= this.page.bookmark.first && - number <= this.page.bookmark.last; - - this.updateLineCount = (lines, engine) => { - let reference; - - if (engine) { - reference = this.getReference(); - } else { - reference = this.getActiveReference(); - } - - const index = reference.cache.findIndex(item => item.number === reference.state.current); - - reference.cache[index].lines += lines; - }; - - this.isBookmarkPending = () => this.bookmark.pending; - this.isBookmarkSet = () => this.bookmark.set; - - this.setBookmark = () => { - if (this.isBookmarkSet()) { - return; - } - - if (!this.isBookmarkPending()) { - this.bookmark.pending = true; - - return; - } - - this.bookmark.state.first = this.page.state.first; - this.bookmark.state.last = this.page.state.last - 1; - this.bookmark.state.current = this.page.state.current - 1; - this.bookmark.cache = JSON.parse(JSON.stringify(this.page.cache)); - this.bookmark.set = true; - this.bookmark.pending = false; - }; - - this.removeBookmark = () => { - this.bookmark.set = false; - this.bookmark.pending = false; - this.bookmark.cache.splice(0, this.bookmark.cache.length); - this.bookmark.state.first = 0; - this.bookmark.state.last = 0; - this.bookmark.state.current = 0; - }; - - this.next = () => { - const reference = this.getActiveReference(); - const number = reference.state.last + 1; - - return this.api.getPage(number) - .then(data => { - if (!data || !data.results) { - return $q.resolve(); - } - - this.addPage(data.page, [], true); - - return data.results; - }); - }; - - this.previous = () => { - const reference = this.getActiveReference(); - - return this.api.getPage(reference.state.first - 1) - .then(data => { - if (!data || !data.results) { - return $q.resolve(); - } - - this.addPage(data.page, [], false); - - return data.results; - }); - }; - - this.last = () => this.api.last() - .then(data => { - if (!data || !data.results || !data.results.length > 0) { - return $q.resolve(); - } - - this.emptyCache(data.page); - this.addPage(data.page, [], true); - - return data.results; - }); - - this.first = () => this.api.first() - .then(data => { - if (!data || !data.results) { - return $q.resolve(); - } - - this.emptyCache(data.page); - this.addPage(data.page, [], false); - - return data.results; - }); - - this.getActiveReference = () => (this.isBookmarkSet() ? - this.getReference(true) : this.getReference()); - - this.getReference = (bookmark) => { - if (bookmark) { - return { - bookmark: true, - cache: this.bookmark.cache, - state: this.bookmark.state - }; - } - - return { - bookmark: false, - cache: this.page.cache, - state: this.page.state - }; - }; -} - -JobPageService.$inject = ['$q']; - -export default JobPageService; diff --git a/awx/ui/client/features/output/render.service.js b/awx/ui/client/features/output/render.service.js deleted file mode 100644 index 08a3498fd2cd..000000000000 --- a/awx/ui/client/features/output/render.service.js +++ /dev/null @@ -1,300 +0,0 @@ -import Ansi from 'ansi-to-html'; -import Entities from 'html-entities'; - -const ELEMENT_TBODY = '#atStdoutResultTable'; -const EVENT_START_TASK = 'playbook_on_task_start'; -const EVENT_START_PLAY = 'playbook_on_play_start'; -const EVENT_STATS_PLAY = 'playbook_on_stats'; - -const EVENT_GROUPS = [ - EVENT_START_TASK, - EVENT_START_PLAY -]; - -const TIME_EVENTS = [ - EVENT_START_TASK, - EVENT_START_PLAY, - EVENT_STATS_PLAY -]; - -const ansi = new Ansi(); -const entities = new Entities.AllHtmlEntities(); - -// https://github.com/chalk/ansi-regex -const pattern = [ - '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', - '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' -].join('|'); - -const re = new RegExp(pattern); -const hasAnsi = input => re.test(input); - -function JobRenderService ($q, $sce, $window) { - this.init = ({ compile, isStreamActive }) => { - this.parent = null; - this.record = {}; - this.el = $(ELEMENT_TBODY); - this.hooks = { isStreamActive, compile }; - }; - - this.sortByLineNumber = (a, b) => { - if (a.start_line > b.start_line) { - return 1; - } - - if (a.start_line < b.start_line) { - return -1; - } - - return 0; - }; - - this.transformEventGroup = events => { - let lines = 0; - let html = ''; - - events.sort(this.sortByLineNumber); - - events.forEach(event => { - const line = this.transformEvent(event); - - html += line.html; - lines += line.count; - }); - - return { html, lines }; - }; - - this.transformEvent = event => { - if (!event || !event.stdout) { - return { html: '', count: 0 }; - } - - const stdout = this.sanitize(event.stdout); - const lines = stdout.split('\r\n'); - - let count = lines.length; - let ln = event.start_line; - - const current = this.createRecord(ln, lines, event); - - const html = lines.reduce((concat, line, i) => { - ln++; - - const isLastLine = i === lines.length - 1; - - let row = this.createRow(current, ln, line); - - if (current && current.isTruncated && isLastLine) { - row += this.createRow(current); - count++; - } - - return `${concat}${row}`; - }, ''); - - return { html, count }; - }; - - this.isHostEvent = (event) => { - if (typeof event.host === 'number') { - return true; - } - - if (event.type === 'project_update_event' && - event.event !== 'runner_on_skipped' && - event.event_data.host) { - return true; - } - - return false; - }; - - this.createRecord = (ln, lines, event) => { - if (!event.uuid) { - return null; - } - - const info = { - id: event.id, - line: ln + 1, - uuid: event.uuid, - level: event.event_level, - start: event.start_line, - end: event.end_line, - isTruncated: (event.end_line - event.start_line) > lines.length, - isHost: this.isHostEvent(event), - }; - - if (event.parent_uuid) { - info.parents = this.getParentEvents(event.parent_uuid); - } - - if (info.isTruncated) { - info.truncatedAt = event.start_line + lines.length; - } - - if (EVENT_GROUPS.includes(event.event)) { - info.isParent = true; - - if (event.event_level === 1) { - this.parent = event.uuid; - } - - if (event.parent_uuid) { - if (this.record[event.parent_uuid]) { - if (this.record[event.parent_uuid].children && - !this.record[event.parent_uuid].children.includes(event.uuid)) { - this.record[event.parent_uuid].children.push(event.uuid); - } else { - this.record[event.parent_uuid].children = [event.uuid]; - } - } - } - } - - if (TIME_EVENTS.includes(event.event)) { - info.time = this.getTimestamp(event.created); - info.line++; - } - - this.record[event.uuid] = info; - - return info; - }; - - this.createRow = (current, ln, content) => { - let id = ''; - let timestamp = ''; - let tdToggle = ''; - let tdEvent = ''; - let classList = ''; - - content = content || ''; - - if (hasAnsi(content)) { - content = ansi.toHtml(content); - } - - if (current) { - if (!this.hooks.isStreamActive() && current.isParent && current.line === ln) { - id = current.uuid; - tdToggle = ``; - } - - if (current.isHost) { - tdEvent = `${content}`; - } - - if (current.time && current.line === ln) { - timestamp = `${current.time}`; - } - - if (current.parents) { - classList = current.parents.reduce((list, uuid) => `${list} child-of-${uuid}`, ''); - } - } - - if (!tdEvent) { - tdEvent = `${content}`; - } - - if (!tdToggle) { - tdToggle = ''; - } - - if (!ln) { - ln = '...'; - } - - return ` - - ${tdToggle} - ${ln} - ${tdEvent} - ${timestamp} - `; - }; - - this.getTimestamp = created => { - const date = new Date(created); - const hour = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours(); - const minute = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes(); - const second = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds(); - - return `${hour}:${minute}:${second}`; - }; - - this.getParentEvents = (uuid, list) => { - list = list || []; - - if (this.record[uuid]) { - list.push(uuid); - - if (this.record[uuid].parents) { - list = list.concat(this.record[uuid].parents); - } - } - - return list; - }; - - this.insert = (events, insert) => { - const result = this.transformEventGroup(events); - const html = this.trustHtml(result.html); - - return this.requestAnimationFrame(() => insert(html)) - .then(() => this.compile(html)) - .then(() => result.lines); - }; - - this.remove = elements => this.requestAnimationFrame(() => { - elements.remove(); - }); - - this.requestAnimationFrame = fn => $q(resolve => { - $window.requestAnimationFrame(() => { - if (fn) { - fn(); - } - - return resolve(); - }); - }); - - this.compile = html => { - html = $(this.el); - this.hooks.compile(html); - - return this.requestAnimationFrame(); - }; - - this.clear = () => { - const elements = this.el.children(); - return this.remove(elements); - }; - - this.shift = lines => { - const elements = this.el.children().slice(0, lines); - - return this.remove(elements); - }; - - this.pop = lines => { - const elements = this.el.children().slice(-lines); - - return this.remove(elements); - }; - - this.prepend = events => this.insert(events, html => this.el.prepend(html)); - - this.append = events => this.insert(events, html => this.el.append(html)); - - this.trustHtml = html => $sce.getTrustedHtml($sce.trustAsHtml(html)); - - this.sanitize = html => entities.encode(html); -} - -JobRenderService.$inject = ['$q', '$sce', '$window']; - -export default JobRenderService; diff --git a/awx/ui/client/features/output/scroll.service.js b/awx/ui/client/features/output/scroll.service.js deleted file mode 100644 index a568813ddc08..000000000000 --- a/awx/ui/client/features/output/scroll.service.js +++ /dev/null @@ -1,167 +0,0 @@ -const ELEMENT_CONTAINER = '.at-Stdout-container'; -const ELEMENT_TBODY = '#atStdoutResultTable'; -const DELAY = 100; -const THRESHOLD = 0.1; - -function JobScrollService ($q, $timeout) { - this.init = (hooks) => { - this.el = $(ELEMENT_CONTAINER); - this.timer = null; - - this.position = { - previous: 0, - current: 0 - }; - - this.hooks = { - isAtRest: hooks.isAtRest, - next: hooks.next, - previous: hooks.previous - }; - - this.state = { - locked: false, - paused: false, - top: true - }; - - this.el.scroll(this.listen); - }; - - this.listen = () => { - if (this.isPaused()) { - return; - } - - if (this.timer) { - $timeout.cancel(this.timer); - } - - this.timer = $timeout(this.register, DELAY); - }; - - this.register = () => { - this.pause(); - - const current = this.getScrollPosition(); - const downward = current > this.position.previous; - - let promise; - - if (downward && this.isBeyondThreshold(downward, current)) { - promise = this.hooks.next; - } else if (!downward && this.isBeyondThreshold(downward, current)) { - promise = this.hooks.previous; - } - - if (!promise) { - this.setScrollPosition(current); - this.isAtRest(); - this.resume(); - - return $q.resolve(); - } - - return promise() - .then(() => { - this.setScrollPosition(this.getScrollPosition()); - this.isAtRest(); - this.resume(); - }); - }; - - this.isBeyondThreshold = (downward, current) => { - const height = this.getScrollHeight(); - - if (downward) { - current += this.getViewableHeight(); - - if (current >= height || ((height - current) / height) < THRESHOLD) { - return true; - } - } else if (current <= 0 || (current / height) < THRESHOLD) { - return true; - } - - return false; - }; - - this.pageUp = () => { - if (this.isPaused()) { - return; - } - - const top = this.getScrollPosition(); - const height = this.getViewableHeight(); - - this.setScrollPosition(top - height); - }; - - this.pageDown = () => { - if (this.isPaused()) { - return; - } - - const top = this.getScrollPosition(); - const height = this.getViewableHeight(); - - this.setScrollPosition(top + height); - }; - - this.getScrollHeight = () => this.el[0].scrollHeight; - this.getViewableHeight = () => this.el[0].offsetHeight; - this.getScrollPosition = () => this.el[0].scrollTop; - - this.setScrollPosition = position => { - this.position.previous = this.position.current; - this.position.current = position; - this.el[0].scrollTop = position; - this.isAtRest(); - }; - - this.resetScrollPosition = () => { - this.position.previous = 0; - this.position.current = 0; - this.el[0].scrollTop = 0; - this.isAtRest(); - }; - - this.scrollToBottom = () => { - this.setScrollPosition(this.getScrollHeight()); - }; - - this.isAtRest = () => { - if (this.position.current === 0 && !this.state.top) { - this.state.top = true; - this.hooks.isAtRest(true); - } else if (this.position.current > 0 && this.state.top) { - this.state.top = false; - this.hooks.isAtRest(false); - } - }; - - this.resume = () => { - this.state.paused = false; - }; - - this.pause = () => { - this.state.paused = true; - }; - - this.isPaused = () => this.state.paused; - - this.lock = () => { - this.state.locked = true; - }; - - this.unlock = () => { - this.state.locked = false; - }; - - this.isLocked = () => this.state.locked; - this.isMissing = () => $(ELEMENT_TBODY)[0].clientHeight < this.getViewableHeight(); -} - -JobScrollService.$inject = ['$q', '$timeout']; - -export default JobScrollService; diff --git a/awx/ui/client/features/output/search.component.js b/awx/ui/client/features/output/search.component.js deleted file mode 100644 index b1f40efd3e2e..000000000000 --- a/awx/ui/client/features/output/search.component.js +++ /dev/null @@ -1,124 +0,0 @@ -const templateUrl = require('~features/output/search.partial.html'); - -const searchReloadOptions = { inherit: false, location: 'replace' }; -const searchKeyExamples = ['id:>1', 'task:set', 'created:>=2000-01-01']; -const searchKeyFields = ['changed', 'failed', 'host_name', 'stdout', 'task', 'role', 'playbook', 'play']; - -const PLACEHOLDER_RUNNING = 'CANNOT SEARCH RUNNING JOB'; -const PLACEHOLDER_DEFAULT = 'SEARCH'; -const REJECT_DEFAULT = 'Failed to update search results.'; -const REJECT_INVALID = 'Invalid search filter provided.'; - -let $state; -let qs; - -let vm; - -function toggleSearchKey () { - vm.key = !vm.key; -} - -function getCurrentQueryset () { - const { job_event_search } = $state.params; // eslint-disable-line camelcase - - return qs.decodeArr(job_event_search); -} - -function getSearchTags (queryset) { - return qs.createSearchTagsFromQueryset(queryset) - .filter(tag => !tag.startsWith('event')) - .filter(tag => !tag.startsWith('-event')) - .filter(tag => !tag.startsWith('page_size')) - .filter(tag => !tag.startsWith('order_by')); -} - -function reloadQueryset (queryset, rejection = REJECT_DEFAULT) { - const params = angular.copy($state.params); - const currentTags = vm.tags; - - params.handleErrors = false; - params.job_event_search = qs.encodeArr(queryset); - - vm.disabled = true; - vm.message = ''; - vm.tags = getSearchTags(queryset); - - return $state.transitionTo($state.current, params, searchReloadOptions) - .catch(() => { - vm.tags = currentTags; - vm.message = rejection; - vm.rejected = true; - vm.disabled = false; - }); -} - -function removeSearchTag (index) { - const searchTerm = vm.tags[index]; - - const currentQueryset = getCurrentQueryset(); - const modifiedQueryset = qs.removeTermsFromQueryset(currentQueryset, searchTerm); - - reloadQueryset(modifiedQueryset); -} - -function submitSearch () { - const currentQueryset = getCurrentQueryset(); - - const searchInputQueryset = qs.getSearchInputQueryset(vm.value); - const modifiedQueryset = qs.mergeQueryset(currentQueryset, searchInputQueryset); - - reloadQueryset(modifiedQueryset, REJECT_INVALID); -} - -function clearSearch () { - reloadQueryset(); -} - -function JobSearchController (_$state_, _qs_, { subscribe }) { - $state = _$state_; - qs = _qs_; - - vm = this || {}; - - vm.examples = searchKeyExamples; - vm.fields = searchKeyFields; - vm.relatedFields = []; - vm.placeholder = PLACEHOLDER_DEFAULT; - - vm.clearSearch = clearSearch; - vm.toggleSearchKey = toggleSearchKey; - vm.removeSearchTag = removeSearchTag; - vm.submitSearch = submitSearch; - - let unsubscribe; - - vm.$onInit = () => { - vm.value = ''; - vm.message = ''; - vm.key = false; - vm.rejected = false; - vm.disabled = true; - vm.tags = getSearchTags(getCurrentQueryset()); - - unsubscribe = subscribe(({ running }) => { - vm.disabled = running; - vm.placeholder = running ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT; - }); - }; - - vm.$onDestroy = () => { - unsubscribe(); - }; -} - -JobSearchController.$inject = [ - '$state', - 'QuerySet', - 'JobStatusService', -]; - -export default { - templateUrl, - controller: JobSearchController, - controllerAs: 'vm', -}; diff --git a/awx/ui/client/features/output/search.partial.html b/awx/ui/client/features/output/search.partial.html deleted file mode 100644 index c2093948156a..000000000000 --- a/awx/ui/client/features/output/search.partial.html +++ /dev/null @@ -1,64 +0,0 @@ - -
-
- - - - - - -
-

- {{ vm.message }} -

-
- -
-
-
{{ tag }}
-
- -
-
-
CLEAR ALL
-
- -
-
-
-
-
EXAMPLES:
- -
-
-
- FIELDS: - {{ field }}, -
-
- ADDITIONAL INFORMATION: - For additional information on advanced search search syntax please see the Ansible Tower - documentation. -
-
-
diff --git a/awx/ui/client/features/output/stats.component.js b/awx/ui/client/features/output/stats.component.js deleted file mode 100644 index a7a0ec61f34e..000000000000 --- a/awx/ui/client/features/output/stats.component.js +++ /dev/null @@ -1,74 +0,0 @@ -const templateUrl = require('~features/output/stats.partial.html'); - -let vm; - -function createStatsBarTooltip (key, count) { - const label = `${key}`; - const badge = `${count}`; - - return `${label}${badge}`; -} - -function JobStatsController (strings, { subscribe }) { - vm = this || {}; - - let unsubscribe; - - vm.tooltips = { - running: strings.get('status.RUNNING'), - unavailable: strings.get('status.UNAVAILABLE'), - }; - - vm.$onInit = () => { - vm.download = vm.resource.model.get('related.stdout'); - vm.toggleStdoutFullscreenTooltip = strings.get('expandCollapse.EXPAND'); - - unsubscribe = subscribe(({ running, elapsed, counts, stats, hosts }) => { - vm.plays = counts.plays; - vm.tasks = counts.tasks; - vm.hosts = counts.hosts; - vm.elapsed = elapsed; - vm.running = running; - vm.setHostStatusCounts(stats, hosts); - }); - }; - - vm.$onDestroy = () => { - unsubscribe(); - }; - - vm.setHostStatusCounts = (stats, counts) => { - Object.keys(counts).forEach(key => { - const count = counts[key]; - const statusBarElement = $(`.HostStatusBar-${key}`); - - statusBarElement.css('flex', `${count} 0 auto`); - - vm.tooltips[key] = createStatsBarTooltip(key, count); - }); - - vm.statsAreAvailable = stats; - }; - - vm.toggleExpanded = () => { - vm.expanded = !vm.expanded; - vm.toggleStdoutFullscreenTooltip = vm.expanded ? - strings.get('expandCollapse.COLLAPSE') : - strings.get('expandCollapse.EXPAND'); - }; -} - -JobStatsController.$inject = [ - 'JobStrings', - 'JobStatusService', -]; - -export default { - templateUrl, - controller: JobStatsController, - controllerAs: 'vm', - bindings: { - resource: '<', - expanded: '=', - }, -}; diff --git a/awx/ui/client/features/output/stats.partial.html b/awx/ui/client/features/output/stats.partial.html deleted file mode 100644 index c55ba4bc8d59..000000000000 --- a/awx/ui/client/features/output/stats.partial.html +++ /dev/null @@ -1,88 +0,0 @@ - -
- plays - ... - {{ vm.plays }} - - tasks - ... - {{ vm.tasks }} - - hosts - ... - {{ vm.hosts }} - - elapsed - ... - - {{ vm.elapsed * 1000 | duration: "hh:mm:ss" }} - - - - - - - -
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/awx/ui/client/features/output/status.service.js b/awx/ui/client/features/output/status.service.js deleted file mode 100644 index 29558c70df38..000000000000 --- a/awx/ui/client/features/output/status.service.js +++ /dev/null @@ -1,209 +0,0 @@ -const JOB_START = 'playbook_on_start'; -const JOB_END = 'playbook_on_stats'; -const PLAY_START = 'playbook_on_play_start'; -const TASK_START = 'playbook_on_task_start'; - -const HOST_STATUS_KEYS = ['dark', 'failures', 'changed', 'ok', 'skipped']; -const FINISHED = ['successful', 'failed', 'error']; - -function JobStatusService (moment, message) { - this.dispatch = () => message.dispatch('status', this.state); - this.subscribe = listener => message.subscribe('status', listener); - - this.init = ({ resource }) => { - const { model } = resource; - - this.created = model.get('created'); - this.job = model.get('id'); - this.jobType = model.get('type'); - this.project = model.get('project'); - - this.active = false; - this.latestTime = null; - this.counter = -1; - - this.state = { - running: false, - stats: false, - counts: { - plays: 0, - tasks: 0, - hosts: 0, - }, - hosts: {}, - status: model.get('status'), - elapsed: model.get('elapsed'), - started: model.get('started'), - finished: model.get('finished'), - scm: { - id: model.get('summary_fields.project_update.id'), - status: model.get('summary_fields.project_update.status') - }, - }; - - this.setStatsEvent(resource.stats); - this.updateStats(); - this.updateRunningState(); - - this.dispatch(); - }; - - this.pushStatusEvent = data => { - const isJobStatusEvent = (this.job === data.unified_job_id); - const isProjectStatusEvent = (this.project && (this.project === data.project_id)); - - if (isJobStatusEvent) { - this.setJobStatus(data.status); - this.dispatch(); - } else if (isProjectStatusEvent) { - this.setProjectStatus(data.status); - this.setProjectUpdateId(data.unified_job_id); - this.dispatch(); - } - }; - - this.pushJobEvent = data => { - const isLatest = ((!this.counter) || (data.counter > this.counter)); - - let changed = false; - - if (!this.active && !(data.event === JOB_END)) { - this.active = true; - this.setJobStatus('running'); - changed = true; - } - - if (isLatest) { - this.counter = data.counter; - this.latestTime = data.created; - this.setElapsed(moment(data.created).diff(this.created, 'seconds')); - changed = true; - } - - if (data.event === JOB_START) { - this.setStarted(this.state.started || data.created); - changed = true; - } - - if (data.event === PLAY_START) { - this.state.counts.plays++; - changed = true; - } - - if (data.event === TASK_START) { - this.state.counts.tasks++; - changed = true; - } - - if (data.event === JOB_END) { - this.setStatsEvent(data); - changed = true; - } - - if (changed) { - this.dispatch(); - } - }; - - this.isExpectingStatsEvent = () => (this.jobType === 'job') || - (this.jobType === 'project_update'); - - this.updateStats = () => { - this.updateHostCounts(); - - if (this.statsEvent) { - this.state.stats = true; - this.setFinished(this.statsEvent.created); - this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful'); - } - }; - - this.updateRunningState = () => { - this.state.running = (Boolean(this.state.started) && !this.state.finished) || - (this.state.status === 'running') || - (this.state.status === 'pending') || - (this.state.status === 'waiting'); - }; - - this.updateHostCounts = () => { - const countedHostNames = []; - - const counts = Object.assign(...HOST_STATUS_KEYS.map(key => ({ [key]: 0 }))); - - HOST_STATUS_KEYS.forEach(key => { - const hostData = _.get(this.statsEvent, ['event_data', key], {}); - - Object.keys(hostData).forEach(hostName => { - const isAlreadyCounted = (countedHostNames.indexOf(hostName) > -1); - const shouldBeCounted = ((!isAlreadyCounted) && hostData[hostName] > 0); - - if (shouldBeCounted) { - countedHostNames.push(hostName); - counts[key]++; - } - }); - }); - - this.state.counts.hosts = countedHostNames.length; - this.setHostStatusCounts(counts); - }; - - this.setJobStatus = status => { - this.state.status = status; - - if (!this.isExpectingStatsEvent() && _.includes(FINISHED, status)) { - if (this.latestTime) { - this.setFinished(this.latestTime); - if (!this.state.started && this.state.elapsed) { - this.setStarted(moment(this.latestTime) - .subtract(this.state.elapsed, 'seconds')); - } - } - } - - this.updateRunningState(); - }; - - this.setElapsed = elapsed => { - this.state.elapsed = elapsed; - }; - - this.setStarted = started => { - this.state.started = started; - this.updateRunningState(); - }; - - this.setProjectStatus = status => { - this.state.scm.status = status; - }; - - this.setProjectUpdateId = id => { - this.state.scm.id = id; - }; - - this.setFinished = time => { - this.state.finished = time; - this.updateRunningState(); - }; - - this.setStatsEvent = data => { - this.statsEvent = data; - }; - - this.setHostStatusCounts = counts => { - this.state.hosts = counts; - }; - - this.resetCounts = () => { - this.state.counts.plays = 0; - this.state.counts.tasks = 0; - this.state.counts.hosts = 0; - }; -} - -JobStatusService.$inject = [ - 'moment', - 'JobMessageService', -]; - -export default JobStatusService; diff --git a/awx/ui/client/features/templates/index.controller.js b/awx/ui/client/features/templates/index.controller.js deleted file mode 100644 index c8592550701d..000000000000 --- a/awx/ui/client/features/templates/index.controller.js +++ /dev/null @@ -1,19 +0,0 @@ -function IndexTemplatesController ($scope, strings, dataset) { - let vm = this; - vm.strings = strings; - vm.count = dataset.data.count; - - $scope.$on('updateDataset', (e, { count }) => { - if (count) { - vm.count = count; - } - }); -} - -IndexTemplatesController.$inject = [ - '$scope', - 'TemplatesStrings', - 'Dataset' -]; - -export default IndexTemplatesController; diff --git a/awx/ui/client/features/templates/index.js b/awx/ui/client/features/templates/index.js deleted file mode 100644 index fd0a49b45a01..000000000000 --- a/awx/ui/client/features/templates/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import TemplatesStrings from './templates.strings'; - -const MODULE_NAME = 'at.features.templates'; - -angular - .module(MODULE_NAME, []) - .service('TemplatesStrings', TemplatesStrings); - -export default MODULE_NAME; diff --git a/awx/ui/client/features/templates/index.view.html b/awx/ui/client/features/templates/index.view.html deleted file mode 100644 index 346ab0c0f137..000000000000 --- a/awx/ui/client/features/templates/index.view.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
- -
- - {{:: vm.strings.get('list.PANEL_TITLE') }} -
- {{ vm.count }} -
-
-
-
- - {{:: vm.strings.get('list.PANEL_TITLE') }} -
- {{ vm.count }} -
-
-
-
-
diff --git a/awx/ui/client/features/templates/routes/organizationsTemplatesList.route.js b/awx/ui/client/features/templates/routes/organizationsTemplatesList.route.js deleted file mode 100644 index 3bdd705f1edc..000000000000 --- a/awx/ui/client/features/templates/routes/organizationsTemplatesList.route.js +++ /dev/null @@ -1,65 +0,0 @@ -import { N_ } from '../../../src/i18n'; -import templatesListController from '../templatesList.controller'; -import indexController from '../index.controller'; - -const indexTemplate = require('~features/templates/index.view.html'); -const templatesListTemplate = require('~features/templates/templatesList.view.html'); - -export default { - url: "/:organization_id/job_templates", - name: 'organizations.job_templates', - params: { - template_search: { - dynamic: true, - value: { - type: 'workflow_job_template,job_template', - }, - } - }, - ncyBreadcrumb: { - label: N_("JOB TEMPLATES") - }, - views: { - 'form': { - templateUrl: indexTemplate, - controller: indexController, - controllerAs: 'vm' - }, - 'templatesList@organizations.job_templates': { - controller: templatesListController, - templateUrl: templatesListTemplate, - controllerAs: 'vm', - } - }, - resolve: { - resolvedModels: [ - 'JobTemplateModel', - 'WorkflowJobTemplateModel', - (JobTemplate, WorkflowJobTemplate) => { - const models = [ - new JobTemplate(['options']), - new WorkflowJobTemplate(['options']), - ]; - return Promise.all(models); - }, - ], - Dataset: [ - '$stateParams', - 'Wait', - 'GetBasePath', - 'QuerySet', - ($stateParams, Wait, GetBasePath, qs) => { - const searchPath = GetBasePath('unified_job_templates'); - - const searchParam = _.assign($stateParams.template_search, { - or__project__organization: $stateParams.organization_id, - or__jobtemplate__inventory__organization: $stateParams.organization_id, - }); - - Wait('start'); - return qs.search(searchPath, searchParam) - .finally(() => Wait('stop')); - } - ], - } -}; diff --git a/awx/ui/client/features/templates/routes/portalModeTemplatesList.route.js b/awx/ui/client/features/templates/routes/portalModeTemplatesList.route.js deleted file mode 100644 index 55187b5a9874..000000000000 --- a/awx/ui/client/features/templates/routes/portalModeTemplatesList.route.js +++ /dev/null @@ -1,79 +0,0 @@ -import { templateUrl } from '../../../src/shared/template-url/template-url.factory'; -import { N_ } from '../../../src/i18n'; -import templatesListController from '../templatesList.controller'; - -const templatesListTemplate = require('~features/templates/templatesList.view.html'); - -export default { - name: 'portalMode', - url: '/portal', - reloadOnSearch: true, - ncyBreadcrumb: { - label: N_('MY VIEW') - }, - data: { - socket: { - "groups": { - "jobs": ["status_changed"] - } - } - }, - params: { - template_search: { - dynamic: true, - value: { - type: 'workflow_job_template,job_template', - }, - } - }, - searchPrefix: 'template', - views: { - '@': { - templateUrl: templateUrl('portal-mode/portal-mode-layout'), - controller: ['$scope', '$state', - function($scope, $state) { - - $scope.filterUser = function() { - $state.go('portalMode.myJobs'); - }; - - $scope.filterAll = function() { - $state.go('portalMode.allJobs'); - }; - } - ] - }, - 'templates@portalMode': { - templateUrl: templatesListTemplate, - controller: templatesListController, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: [ - 'JobTemplateModel', - 'WorkflowJobTemplateModel', - (JobTemplate, WorkflowJobTemplate) => { - const models = [ - new JobTemplate(['options']), - new WorkflowJobTemplate(['options']), - ]; - return Promise.all(models); - }, - ], - Dataset: [ - '$stateParams', - 'Wait', - 'GetBasePath', - 'QuerySet', - ($stateParams, Wait, GetBasePath, qs) => { - const searchParam = $stateParams.template_search; - const searchPath = GetBasePath('unified_job_templates'); - - Wait('start'); - return qs.search(searchPath, searchParam) - .finally(() => Wait('stop')); - } - ], - } -}; diff --git a/awx/ui/client/features/templates/routes/projectsTemplatesList.route.js b/awx/ui/client/features/templates/routes/projectsTemplatesList.route.js deleted file mode 100644 index 8f6d916dbc3f..000000000000 --- a/awx/ui/client/features/templates/routes/projectsTemplatesList.route.js +++ /dev/null @@ -1,56 +0,0 @@ -import { N_ } from '../../../src/i18n'; -import templatesListController from '../templatesList.controller'; - -const templatesListTemplate = require('~features/templates/templatesList.view.html'); - -export default { - url: "/templates", - name: 'projects.edit.templates', - params: { - template_search: { - dynamic: true, - value: { - type: 'workflow_job_template,job_template', - }, - } - }, - ncyBreadcrumb: { - label: N_("JOB TEMPLATES") - }, - views: { - 'related': { - controller: templatesListController, - templateUrl: templatesListTemplate, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: [ - 'JobTemplateModel', - 'WorkflowJobTemplateModel', - (JobTemplate, WorkflowJobTemplate) => { - const models = [ - new JobTemplate(['options']), - new WorkflowJobTemplate(['options']), - ]; - return Promise.all(models); - }, - ], - Dataset: [ - '$stateParams', - 'Wait', - 'GetBasePath', - 'QuerySet', - ($stateParams, Wait, GetBasePath, qs) => { - const searchPath = GetBasePath('unified_job_templates'); - - const searchParam = _.assign($stateParams.template_search, { - jobtemplate__project: $stateParams.project_id }); - - Wait('start'); - return qs.search(searchPath, searchParam) - .finally(() => Wait('stop')); - } - ], - } -}; diff --git a/awx/ui/client/features/templates/routes/templatesList.route.js b/awx/ui/client/features/templates/routes/templatesList.route.js deleted file mode 100644 index 8a912776cc48..000000000000 --- a/awx/ui/client/features/templates/routes/templatesList.route.js +++ /dev/null @@ -1,71 +0,0 @@ -import { N_ } from '../../../src/i18n'; -import templatesListController from '../templatesList.controller'; -import indexController from '../index.controller'; - -const indexTemplate = require('~features/templates/index.view.html'); -const templatesListTemplate = require('~features/templates/templatesList.view.html'); - -export default { - name: 'templates', - route: '/templates', - ncyBreadcrumb: { - label: N_("TEMPLATES") - }, - data: { - activityStream: true, - activityStreamTarget: 'template', - socket: { - "groups": { - "jobs": ["status_changed"] - } - } - }, - params: { - template_search: { - dynamic: true, - value: { - type: 'workflow_job_template,job_template', - }, - } - }, - searchPrefix: 'template', - views: { - '@': { - templateUrl: indexTemplate, - controller: indexController, - controllerAs: 'vm' - }, - 'templatesList@templates': { - controller: templatesListController, - templateUrl: templatesListTemplate, - controllerAs: 'vm', - } - }, - resolve: { - resolvedModels: [ - 'JobTemplateModel', - 'WorkflowJobTemplateModel', - (JobTemplate, WorkflowJobTemplate) => { - const models = [ - new JobTemplate(['options']), - new WorkflowJobTemplate(['options']), - ]; - return Promise.all(models); - }, - ], - Dataset: [ - '$stateParams', - 'Wait', - 'GetBasePath', - 'QuerySet', - ($stateParams, Wait, GetBasePath, qs) => { - const searchParam = $stateParams.template_search; - const searchPath = GetBasePath('unified_job_templates'); - - Wait('start'); - return qs.search(searchPath, searchParam) - .finally(() => Wait('stop')); - } - ], - } -}; diff --git a/awx/ui/client/features/templates/templates.strings.js b/awx/ui/client/features/templates/templates.strings.js deleted file mode 100644 index 3bb2d38b665c..000000000000 --- a/awx/ui/client/features/templates/templates.strings.js +++ /dev/null @@ -1,102 +0,0 @@ -function TemplatesStrings (BaseString) { - BaseString.call(this, 'templates'); - - const { t } = this; - const ns = this.templates; - - ns.state = { - LIST_BREADCRUMB_LABEL: t.s('TEMPLATES') - }; - - ns.list = { - PANEL_TITLE: t.s('TEMPLATES'), - ADD_DD_JT_LABEL: t.s('Job Template'), - ADD_DD_WF_LABEL: t.s('Workflow Template'), - ROW_ITEM_LABEL_ACTIVITY: t.s('Activity'), - ROW_ITEM_LABEL_INVENTORY: t.s('Inventory'), - ROW_ITEM_LABEL_PROJECT: t.s('Project'), - ROW_ITEM_LABEL_CREDENTIALS: t.s('Credentials'), - ROW_ITEM_LABEL_MODIFIED: t.s('Last Modified'), - ROW_ITEM_LABEL_RAN: t.s('Last Ran'), - }; - - ns.prompt = { - INVENTORY: t.s('Inventory'), - CREDENTIAL: t.s('Credential'), - OTHER_PROMPTS: t.s('Other Prompts'), - SURVEY: t.s('Survey'), - PREVIEW: t.s('Preview'), - LAUNCH: t.s('LAUNCH'), - CONFIRM: t.s('CONFIRM'), - SELECTED: t.s('SELECTED'), - NO_CREDENTIALS_SELECTED: t.s('No credentials selected'), - NO_INVENTORY_SELECTED: t.s('No inventory selected'), - REVERT: t.s('REVERT'), - CREDENTIAL_TYPE: t.s('Credential Type'), - CREDENTIAL_PASSWORD_WARNING: t.s('Credentials that require passwords on launch are not permitted for template schedules and workflow nodes. The following credentials must be removed or replaced to proceed:'), - PASSWORDS_REQUIRED_HELP: t.s('Launching this job requires the passwords listed below. Enter and confirm each password before continuing.'), - PLEASE_ENTER_PASSWORD: t.s('Please enter a password.'), - credential_passwords: { - SSH_PASSWORD: t.s('SSH Password'), - PRIVATE_KEY_PASSPHRASE: t.s('Private Key Passphrase'), - PRIVILEGE_ESCALATION_PASSWORD: t.s('Privilege Escalation Password'), - VAULT_PASSWORD: t.s('Vault Password') - }, - SHOW_CHANGES: t.s('Show Changes'), - SKIP_TAGS: t.s('Skip Tags'), - JOB_TAGS: t.s('Job Tags'), - LIMIT: t.s('Limit'), - JOB_TYPE: t.s('Job Type'), - VERBOSITY: t.s('Verbosity'), - CHOOSE_JOB_TYPE: t.s('Choose a job type'), - CHOOSE_VERBOSITY: t.s('Choose a verbosity'), - EXTRA_VARIABLES: t.s('Extra Variables'), - EXTRA_VARIABLES_HELP: t.s('

Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON.

JSON:
{
"somevar": "somevalue",
"password": "magic"
}
YAML:
---
somevar: somevalue
password: magic
'), - PLEASE_ENTER_ANSWER: t.s('Please enter an answer.'), - PLEASE_SELECT_VALUE: t.s('Please select a value'), - VALID_INTEGER: t.s('Please enter an answer that is a valid integer.'), - VALID_DECIMAL: t.s('Please enter an answer that is a decimal number.'), - PLAYBOOK_RUN: t.s('Playbook Run'), - CHECK: t.s('Check'), - NO_CREDS_MATCHING_TYPE: t.s('No Credentials Matching This Type Have Been Created'), - CREDENTIAL_TYPE_MISSING: typeLabel => t.s('This job template has a default {{typeLabel}} credential which must be included or replaced before proceeding.', { typeLabel }) - }; - - ns.alert = { - MISSING_PARAMETER: t.s('Template parameter is missing.'), - NO_PERMISSION: t.s('You do not have permission to perform this action.'), - UNKNOWN_COPY: t.s('Unable to determine this template\'s type while copying.'), - UNKNOWN_DELETE: t.s('Unable to determine this template\'s type while deleting.'), - UNKNOWN_EDIT: t.s('Unable to determine this template\'s type while editing.'), - UNKNOWN_LAUNCH: t.s('Unable to determine this template\'s type while launching.'), - UNKNOWN_SCHEDULE: t.s('Unable to determine this template\'s type while scheduling.'), - }; - - ns.actions = { - COPY_WORKFLOW: t.s('Copy Workflow') - }; - - ns.error = { - HEADER: this.error.HEADER, - CALL: this.error.CALL, - EDIT: t.s('Unable to edit template.'), - DELETE: t.s('Unable to delete template.'), - LAUNCH: t.s('Unable to launch template.'), - UNKNOWN: t.s('Unable to determine template type.'), - SCHEDULE: t.s('Unable to schedule job.'), - COPY: t.s('Unable to copy template.'), - INVALID: t.s('Resources are missing from this template.') - }; - - ns.warnings = { - WORKFLOW_RESTRICTED_COPY: t.s('You do not have access to all resources used by this workflow. Resources that you don\'t have access to will not be copied and will result in an incomplete workflow.') - }; - - ns.workflows = { - INVALID_JOB_TEMPLATE: t.s('This Job Template is missing a default inventory or project. This must be addressed in the Job Template form before this node can be saved.') - }; -} - -TemplatesStrings.$inject = ['BaseStringService']; - -export default TemplatesStrings; diff --git a/awx/ui/client/features/templates/templatesList.controller.js b/awx/ui/client/features/templates/templatesList.controller.js deleted file mode 100644 index 5ad7388fd462..000000000000 --- a/awx/ui/client/features/templates/templatesList.controller.js +++ /dev/null @@ -1,361 +0,0 @@ -/** *********************************************** - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - ************************************************ */ -const JOB_TEMPLATE_ALIASES = ['job_template', 'Job Template']; -const WORKFLOW_TEMPLATE_ALIASES = ['workflow_job_template', 'Workflow Job Template']; - -const isJobTemplate = ({ type }) => JOB_TEMPLATE_ALIASES.indexOf(type) > -1; -const isWorkflowTemplate = ({ type }) => WORKFLOW_TEMPLATE_ALIASES.indexOf(type) > -1; -const mapChoices = choices => Object.assign(...choices.map(([k, v]) => ({[k]: v}))); - -function ListTemplatesController( - $filter, - $scope, - $state, - Alert, - Dataset, - ProcessErrors, - Prompt, - resolvedModels, - strings, - Wait, - qs, - GetBasePath -) { - const vm = this || {}; - const [jobTemplate, workflowTemplate] = resolvedModels; - - const choices = workflowTemplate.options('actions.GET.type.choices') - .concat(jobTemplate.options('actions.GET.type.choices')); - - let launchModalOpen = false; - let refreshAfterLaunchClose = false; - - vm.strings = strings; - vm.templateTypes = mapChoices(choices); - vm.activeId = parseInt($state.params.job_template_id || $state.params.workflow_template_id); - vm.invalidTooltip = { - popover: { - text: strings.get('error.INVALID'), - on: 'mouseenter', - icon: 'fa-exclamation', - position: 'right', - arrowHeight: 15 - } - }; - - $scope.canAddJobTemplate = jobTemplate.options('actions.POST'); - $scope.canAddWorkflowJobTemplate = workflowTemplate.options('actions.POST'); - $scope.canAdd = ($scope.canAddJobTemplate || $scope.canAddWorkflowJobTemplate); - - // smart-search - $scope.list = { - iterator: 'template', - name: 'templates' - }; - $scope.collection = { - iterator: 'template', - basePath: 'unified_job_templates' - }; - $scope.template_dataset = Dataset.data; - $scope.templates = Dataset.data.results; - $scope.$on('updateDataset', (e, dataset) => { - $scope.template_dataset = dataset; - $scope.templates = dataset.results; - }); - - $scope.$on(`ws-jobs`, () => { - if (!launchModalOpen) { - refreshTemplates(); - } else { - refreshAfterLaunchClose = true; - } - }); - - $scope.$on('launchModalOpen', (evt, isOpen) => { - evt.stopPropagation(); - if (!isOpen && refreshAfterLaunchClose) { - refreshAfterLaunchClose = false; - refreshTemplates(); - } - launchModalOpen = isOpen; - }); - - vm.isInvalid = (template) => { - if(isJobTemplate(template)) { - return template.project === null || (template.inventory === null && template.ask_inventory_on_launch === false); - } else { - return false; - } - }; - - vm.scheduleTemplate = template => { - if (!template) { - Alert(strings.get('error.SCHEDULE'), strings.get('alert.MISSING_PARAMETER')); - return; - } - - if (isJobTemplate(template)) { - $state.go('templates.editJobTemplate.schedules', { job_template_id: template.id }); - } else if (isWorkflowTemplate(template)) { - $state.go('templates.editWorkflowJobTemplate.schedules', { workflow_job_template_id: template.id }); - } else { - Alert(strings.get('error.UNKNOWN'), strings.get('alert.UNKNOWN_SCHEDULE')); - } - }; - - vm.deleteTemplate = template => { - if (!template) { - Alert(strings.get('error.DELETE'), strings.get('alert.MISSING_PARAMETER')); - return; - } - - if (isWorkflowTemplate(template)) { - displayWorkflowTemplateDeletePrompt(template); - } else if (isJobTemplate(template)) { - jobTemplate.getDependentResourceCounts(template.id) - .then(counts => displayJobTemplateDeletePrompt(template, counts)); - } else { - Alert(strings.get('error.UNKNOWN'), strings.get('alert.UNKNOWN_DELETE')); - } - }; - - vm.copyTemplate = template => { - if (!template) { - Alert(strings.get('error.COPY'), strings.get('alert.MISSING_PARAMETER')); - return; - } - - if (isJobTemplate(template)) { - copyJobTemplate(template); - } else if (isWorkflowTemplate(template)) { - copyWorkflowTemplate(template); - } else { - Alert(strings.get('error.UNKNOWN'), strings.get('alert.UNKNOWN_COPY')); - } - }; - - vm.getModified = template => { - const modified = _.get(template, 'modified'); - - if (!modified) { - return undefined; - } - - let html = $filter('longDate')(modified); - - const { username, id } = _.get(template, 'summary_fields.modified_by', {}); - - if (username && id) { - html += ` by ${$filter('sanitize')(username)}`; - } - - return html; - }; - - vm.getLastRan = template => { - const lastJobRun = _.get(template, 'last_job_run'); - - if (!lastJobRun) { - return undefined; - } - - let html = $filter('longDate')(lastJobRun); - - // TODO: uncomment and update when last job run user is returned by api - // const { username, id } = _.get(template, 'summary_fields.last_job_run_by', {}); - - // if (username && id) { - // html += ` by ${$filter('sanitize')(username)}`; - //} - - return html; - }; - - function refreshTemplates() { - let path = GetBasePath('unified_job_templates'); - qs.search(path, $state.params.template_search) - .then(function(searchResponse) { - $scope.template_dataset = searchResponse.data; - $scope.templates = $scope.template_dataset.results; - }); - } - - function createErrorHandler(path, action) { - return ({ data, status }) => { - const hdr = strings.get('error.HEADER'); - const msg = strings.get('error.CALL', { path, action, status }); - ProcessErrors($scope, data, status, null, { hdr, msg }); - }; - } - - function copyJobTemplate(template) { - Wait('start'); - jobTemplate - .create('get', template.id) - .then(model => model.copy()) - .then(({ id }) => { - const params = { job_template_id: id }; - $state.go('templates.editJobTemplate', params, { reload: true }); - }) - .catch(createErrorHandler('copy job template', 'POST')) - .finally(() => Wait('stop')); - } - - function copyWorkflowTemplate(template) { - Wait('start'); - workflowTemplate - .create('get', template.id) - .then(model => model.extend('get', 'copy')) - .then(model => { - const action = () => { - $('#prompt-modal').modal('hide'); - Wait('start'); - model.copy() - .then(({ id }) => { - const params = { workflow_job_template_id: id }; - $state.go('templates.editWorkflowJobTemplate', params, { reload: true }); - }) - .catch(createErrorHandler('copy workflow', 'POST')) - .finally(() => Wait('stop')); - }; - - if (model.get('related.copy.can_copy_without_user_input')) { - action(); - } else if (model.get('related.copy.can_copy')) { - Prompt({ - action, - actionText: strings.get('COPY'), - body: buildWorkflowCopyPromptHTML(model.get('related.copy')), - class: 'Modal-primaryButton', - hdr: strings.get('actions.COPY_WORKFLOW'), - }); - } else { - Alert(strings.get('error.COPY'), strings.get('alert.NO_PERMISSION')); - } - }) - .catch(createErrorHandler('copy workflow', 'GET')) - .finally(() => Wait('stop')); - } - - function handleSuccessfulDelete(template) { - const { page } = _.get($state.params, 'template_search'); - let reloadListStateParams = null; - - if ($scope.templates.length === 1 && !_.isEmpty(page) && page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - const pageNumber = (parseInt(reloadListStateParams.template_search.page, 0) - 1); - reloadListStateParams.template_search.page = pageNumber.toString(); - } - - if (parseInt($state.params.job_template_id, 0) === template.id) { - $state.go('templates', reloadListStateParams, { reload: true }); - } else if (parseInt($state.params.workflow_job_template_id, 0) === template.id) { - $state.go('templates', reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, { reload: true }); - } - } - - function displayJobTemplateDeletePrompt(template, counts) { - Prompt({ - action() { - $('#prompt-modal').modal('hide'); - Wait('start'); - jobTemplate - .request('delete', template.id) - .then(() => handleSuccessfulDelete(template)) - .catch(createErrorHandler('delete template', 'DELETE')) - .finally(() => Wait('stop')); - }, - hdr: strings.get('DELETE'), - resourceName: $filter('sanitize')(template.name), - body: buildJobTemplateDeletePromptHTML(counts), - }); - } - - function displayWorkflowTemplateDeletePrompt(template) { - Prompt({ - action() { - $('#prompt-modal').modal('hide'); - Wait('start'); - workflowTemplate - .request('delete', template.id) - .then(() => handleSuccessfulDelete(template)) - .catch(createErrorHandler('delete template', 'DELETE')) - .finally(() => Wait('stop')); - }, - hdr: strings.get('DELETE'), - resourceName: $filter('sanitize')(template.name), - body: strings.get('deleteResource.CONFIRM', 'workflow template'), - }); - } - - function buildJobTemplateDeletePromptHTML(counts) { - const buildCount = count => `${count}`; - const buildLabel = label => ` - ${$filter('sanitize')(label)}`; - const buildCountLabel = ({ count, label }) => `
- ${buildLabel(label)}${buildCount(count)}
`; - - const displayedCounts = counts.filter(({ count }) => count > 0); - - const html = ` - ${displayedCounts.length ? strings.get('deleteResource.USED_BY', 'job template') : ''} - ${strings.get('deleteResource.CONFIRM', 'job template')} - ${displayedCounts.map(buildCountLabel).join('')} - `; - - return html; - } - - function buildWorkflowCopyPromptHTML(data) { - const pull = (data, param) => _.get(data, param, []).map($filter('sanitize')); - - const credentials = pull(data, 'credentials_unable_to_copy'); - const inventories = pull(data, 'inventories_unable_to_copy'); - const templates = pull(data, 'templates_unable_to_copy'); - - const html = ` -
- ${strings.get('warnings.WORKFLOW_RESTRICTED_COPY')} -
-
- ${templates.length ? `
Unified Job Templates
    ` : ''} - ${templates.map(item => `
  • ${item}
  • `).join('')} - ${templates.length ? `
` : ''} -
-
- ${credentials.length ? `
Credentials
    ` : ''} - ${credentials.map(item => `
  • ${item}
  • `).join('')} - ${credentials.length ? `
` : ''} -
-
- ${inventories.length ? `
Inventories
    ` : ''} - ${inventories.map(item => `
  • ${item}
  • `).join('')} - ${inventories.length ? `
` : ''} -
- `; - - return html; - } -} - -ListTemplatesController.$inject = [ - '$filter', - '$scope', - '$state', - 'Alert', - 'Dataset', - 'ProcessErrors', - 'Prompt', - 'resolvedModels', - 'TemplatesStrings', - 'Wait', - 'QuerySet', - 'GetBasePath' -]; - -export default ListTemplatesController; diff --git a/awx/ui/client/features/templates/templatesList.view.html b/awx/ui/client/features/templates/templatesList.view.html deleted file mode 100644 index 5a00912663d5..000000000000 --- a/awx/ui/client/features/templates/templatesList.view.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - -
-
-
- - -
diff --git a/awx/ui/client/features/users/index.js b/awx/ui/client/features/users/index.js deleted file mode 100644 index b8f6a8052ff7..000000000000 --- a/awx/ui/client/features/users/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import atFeaturesUsersTokens from '~features/users/tokens'; - -const MODULE_NAME = 'at.features.users'; - -angular - .module(MODULE_NAME, [atFeaturesUsersTokens]); - -export default MODULE_NAME; diff --git a/awx/ui/client/features/users/tokens/_index.less b/awx/ui/client/features/users/tokens/_index.less deleted file mode 100644 index f1052b5fa684..000000000000 --- a/awx/ui/client/features/users/tokens/_index.less +++ /dev/null @@ -1,9 +0,0 @@ -/** @define TokenModal */ -.TokenModal { - display: flex; -} - -.TokenModal-label { - font-weight: bold; - width: 130px; -} diff --git a/awx/ui/client/features/users/tokens/index.js b/awx/ui/client/features/users/tokens/index.js deleted file mode 100644 index 6d635b572d0b..000000000000 --- a/awx/ui/client/features/users/tokens/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import TokensStrings from './tokens.strings'; - -const MODULE_NAME = 'at.features.users.tokens'; - -angular - .module(MODULE_NAME, []) - .service('TokensStrings', TokensStrings); - -export default MODULE_NAME; diff --git a/awx/ui/client/features/users/tokens/tokens.strings.js b/awx/ui/client/features/users/tokens/tokens.strings.js deleted file mode 100644 index 27b9450992a4..000000000000 --- a/awx/ui/client/features/users/tokens/tokens.strings.js +++ /dev/null @@ -1,46 +0,0 @@ -function TokensStrings (BaseString) { - BaseString.call(this, 'tokens'); - - const { t } = this; - const ns = this.tokens; - - ns.state = { - LIST_BREADCRUMB_LABEL: t.s('TOKENS'), - ADD_BREADCRUMB_LABEL: t.s('CREATE TOKEN'), - USER_LIST_BREADCRUMB_LABEL: t.s('TOKENS') - }; - - ns.tab = { - DETAILS: t.s('Details') - }; - - ns.add = { - PANEL_TITLE: t.s('CREATE TOKEN'), - APP_PLACEHOLDER: t.s('SELECT AN APPLICATION'), - SCOPE_HELP_TEXT: t.s('Specify a scope for the token\'s access'), - TOKEN_MODAL_HEADER: t.s('TOKEN INFORMATION'), - TOKEN_LABEL: t.s('TOKEN'), - REFRESH_TOKEN_LABEL: t.s('REFRESH TOKEN'), - TOKEN_EXPIRES_LABEL: t.s('EXPIRES'), - ERROR_HEADER: t.s('COULD NOT CREATE TOKEN'), - ERROR_BODY_LABEL: t.s('Returned status:'), - LAST_USED_LABEL: t.s('by'), - DELETE_ACTION_LABEL: t.s('DELETE'), - SCOPE_PLACEHOLDER: t.s('Select a scope'), - SCOPE_READ_LABEL: t.s('Read'), - SCOPE_WRITE_LABEL: t.s('Write') - }; - - ns.list = { - ROW_ITEM_LABEL_DESCRIPTION: t.s('DESCRIPTION'), - ROW_ITEM_LABEL_EXPIRED: t.s('EXPIRATION'), - ROW_ITEM_LABEL_USED: t.s('LAST USED'), - ROW_ITEM_LABEL_SCOPE: t.s('SCOPE'), - ROW_ITEM_LABEL_APPLICATION: t.s('APPLICATION'), - HEADER: appName => t.s('{{ appName }} Token', { appName }), - }; -} - -TokensStrings.$inject = ['BaseStringService']; - -export default TokensStrings; diff --git a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js b/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js deleted file mode 100644 index 13197ca11dbc..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js +++ /dev/null @@ -1,69 +0,0 @@ -export default { - name: 'users.edit.tokens.add.application', - url: '/application?selected', - searchPrefix: 'application', - params: { - application_search: { - value: { - page_size: 5, - order_by: 'name' - }, - dynamic: true, - squash: '' - } - }, - data: { - basePath: 'applications', - formChildState: true - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'application@users.edit.tokens.add': { - templateProvider: (ListDefinition, generateList) => { - const html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - - return `${html}`; - } - } - }, - resolve: { - ListDefinition: [() => ({ - name: 'applications', - iterator: 'application', - hover: true, - index: false, - fields: { - name: { - key: true, - label: 'Name', - columnClass: 'col-lg-4 col-md-6 col-sm-8 col-xs-8', - awToolTip: '{{application.description | sanitize}}', - dataPlacement: 'top' - }, - }, - actions: { - }, - fieldActions: { - } - })], - Dataset: ['QuerySet', 'GetBasePath', '$stateParams', 'ListDefinition', - (qs, GetBasePath, $stateParams, list) => qs.search( - GetBasePath('applications'), - $stateParams[`${list.iterator}_search`] - ) - ] - }, - onExit ($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - } -}; diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.controller.js b/awx/ui/client/features/users/tokens/users-tokens-add.controller.js deleted file mode 100644 index 1421077b1c20..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-add.controller.js +++ /dev/null @@ -1,111 +0,0 @@ -function AddTokensController ( - models, $state, strings, Rest, Alert, Wait, GetBasePath, - $filter, ProcessErrors -) { - const vm = this || {}; - const { application } = models; - - vm.mode = 'add'; - vm.strings = strings; - vm.panelTitle = strings.get('add.PANEL_TITLE'); - - vm.form = {}; - - vm.form.application = { - type: 'field', - label: 'Application', - id: 'application' - }; - vm.form.description = { - type: 'String', - label: 'Description', - id: 'description' - }; - - vm.form.application._resource = 'application'; - vm.form.application._route = 'users.edit.tokens.add.application'; - vm.form.application._model = application; - vm.form.application._placeholder = strings.get('add.APP_PLACEHOLDER'); - vm.form.application.required = true; - - vm.form.description.required = false; - - vm.form.scope = { - choices: [ - '', - 'read', - 'write' - ], - help_text: strings.get('add.SCOPE_HELP_TEXT'), - id: 'scope', - label: 'Scope', - required: true, - _component: 'at-input-select', - _data: [ - strings.get('add.SCOPE_PLACEHOLDER'), - strings.get('add.SCOPE_READ_LABEL'), - strings.get('add.SCOPE_WRITE_LABEL') - ], - _exp: 'choice for (index, choice) in state._data', - _format: 'array' - }; - - vm.form.save = payload => { - Rest.setUrl(`${GetBasePath('users')}${$state.params.user_id}/authorized_tokens`); - return Rest.post(payload) - .then(({ data }) => { - Alert(strings.get('add.TOKEN_MODAL_HEADER'), ` -
-
- ${strings.get('add.TOKEN_LABEL')} -
-
- ${data.token} -
-
-
-
- ${strings.get('add.REFRESH_TOKEN_LABEL')} -
-
- ${data.refresh_token} -
-
-
-
- ${strings.get('add.TOKEN_EXPIRES_LABEL')} -
-
- ${$filter('longDate')(data.expires)} -
-
- `, null, null, null, null, null, true); - Wait('stop'); - }) - .catch(({ data, status }) => { - ProcessErrors(null, data, status, null, { - hdr: strings.get('add.ERROR_HEADER'), - msg: `${strings.get('add.ERROR_BODY_LABEL')} ${status}` - }); - Wait('stop'); - }); - }; - - vm.form.onSaveSuccess = () => { - $state.go('^', { user_id: $state.params.user_id }, { reload: true }); - }; -} - -AddTokensController.$inject = [ - 'resolvedModels', - '$state', - 'TokensStrings', - 'Rest', - 'Alert', - 'Wait', - 'GetBasePath', - '$filter', - 'ProcessErrors' -]; - -export default AddTokensController; diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html b/awx/ui/client/features/users/tokens/users-tokens-add.partial.html deleted file mode 100644 index 21f5a8be04db..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html +++ /dev/null @@ -1,18 +0,0 @@ - - - {{ vm.panelTitle }} - - - - - - - - - - - - - - - diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.route.js b/awx/ui/client/features/users/tokens/users-tokens-add.route.js deleted file mode 100644 index 56effe199164..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-add.route.js +++ /dev/null @@ -1,42 +0,0 @@ -import { N_ } from '../../../src/i18n'; -import AddController from './users-tokens-add.controller'; - -const addTemplate = require('~features/users/tokens/users-tokens-add.partial.html'); - -function TokensDetailResolve ($q, Application) { - const promises = {}; - - promises.application = new Application('options'); - - return $q.all(promises); -} - -TokensDetailResolve.$inject = [ - '$q', - 'ApplicationModel' -]; - -export default { - url: '/add-token', - name: 'users.edit.tokens.add', - params: { - }, - data: { - activityStream: true, - activityStreamTarget: 'o_auth2_access_token', - noActivityStreamID: true - }, - ncyBreadcrumb: { - label: N_('CREATE TOKEN') - }, - views: { - 'preFormView@users.edit': { - templateUrl: addTemplate, - controller: AddController, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: TokensDetailResolve - } -}; diff --git a/awx/ui/client/features/users/tokens/users-tokens-list.controller.js b/awx/ui/client/features/users/tokens/users-tokens-list.controller.js deleted file mode 100644 index 056a77792aae..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-list.controller.js +++ /dev/null @@ -1,129 +0,0 @@ -/** *********************************************** - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - ************************************************ */ -function ListTokensController ( - $filter, - $scope, - $state, - Dataset, - strings, - ProcessErrors, - Rest, - GetBasePath, - Prompt, - Wait -) { - const vm = this || {}; - - vm.strings = strings; - vm.activeId = $state.params.token_id; - - $scope.canAdd = true; - - // smart-search - const name = 'tokens'; - const iterator = 'token'; - const key = 'token_dataset'; - - $scope.list = { iterator, name, basePath: 'tokens' }; - $scope.collection = { iterator }; - $scope[key] = Dataset.data; - vm.tokensCount = Dataset.data.count; - $scope[name] = Dataset.data.results; - $scope.$on('updateDataset', (e, dataset) => { - $scope[key] = dataset; - $scope[name] = dataset.results; - vm.tokensCount = dataset.count; - }); - - vm.getScopeString = str => { - if (str === 'Read') { - return vm.strings.get('add.SCOPE_READ_LABEL'); - } else if (str === 'Write') { - return vm.strings.get('add.SCOPE_WRITE_LABEL'); - } - - return undefined; - }; - - vm.getLastUsed = token => { - const lastUsed = _.get(token, 'last_used'); - - if (!lastUsed) { - return undefined; - } - - let html = $filter('longDate')(lastUsed); - - const { username, id } = _.get(token, 'summary_fields.last_used', {}); - - if (username && id) { - html += ` ${strings.get('add.LAST_USED_LABEL')} ${$filter('sanitize')(username)}`; - } - - return html; - }; - - vm.deleteToken = (tok) => { - const action = () => { - $('#prompt-modal').modal('hide'); - Wait('start'); - Rest.setUrl(`${GetBasePath('tokens')}${tok.id}`); - Rest.destroy() - .then(() => { - let reloadListStateParams = null; - - if ($scope.tokens.length === 1 && $state.params.token_search && - !_.isEmpty($state.params.token_search.page) && - $state.params.token_search.page !== '1') { - const page = `${(parseInt(reloadListStateParams - .token_search.page, 10) - 1)}`; - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.token_search.page = page; - } - - if (parseInt($state.params.token_id, 10) === tok.id) { - $state.go('^', reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, { reload: true }); - } - }) - .catch(({ data, status }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${GetBasePath('tokens')}${tok.id}`, status }) - }); - }) - .finally(() => { - Wait('stop'); - }); - }; - - const deleteModalBody = `
${strings.get('deleteResource.CONFIRM', 'token')}
`; - - Prompt({ - hdr: strings.get('deleteResource.HEADER'), - resourceName: strings.get('list.HEADER', tok.summary_fields.application.name), - body: deleteModalBody, - action, - actionText: strings.get('add.DELETE_ACTION_LABEL') - }); - }; -} - -ListTokensController.$inject = [ - '$filter', - '$scope', - '$state', - 'Dataset', - 'TokensStrings', - 'ProcessErrors', - 'Rest', - 'GetBasePath', - 'Prompt', - 'Wait' -]; - -export default ListTokensController; diff --git a/awx/ui/client/features/users/tokens/users-tokens-list.partial.html b/awx/ui/client/features/users/tokens/users-tokens-list.partial.html deleted file mode 100644 index b92d24811a3c..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-list.partial.html +++ /dev/null @@ -1,57 +0,0 @@ -
- - -
- -
-
- - - -
- - - - - - - - - - - - -
-
- - -
-
-
diff --git a/awx/ui/client/features/users/tokens/users-tokens-list.route.js b/awx/ui/client/features/users/tokens/users-tokens-list.route.js deleted file mode 100644 index d262bbe94498..000000000000 --- a/awx/ui/client/features/users/tokens/users-tokens-list.route.js +++ /dev/null @@ -1,51 +0,0 @@ -import { N_ } from '../../../src/i18n'; - -import ListController from './users-tokens-list.controller'; - -const listTemplate = require('~features/users/tokens/users-tokens-list.partial.html'); - -export default { - url: '/tokens', - name: 'users.edit.tokens', - ncyBreadcrumb: { - label: N_('TOKENS') - }, - views: { - related: { - templateUrl: listTemplate, - controller: ListController, - controllerAs: 'vm' - } - }, - data: { - activityStream: true, - activityStreamTarget: 'o_auth2_access_token', - noActivityStreamID: true - }, - searchPrefix: 'token', - params: { - token_search: { - value: { - page_size: 5, - order_by: 'application' - } - } - }, - resolve: { - Dataset: [ - '$stateParams', - 'Wait', - 'GetBasePath', - 'QuerySet', - ($stateParams, Wait, GetBasePath, qs) => { - const searchParam = $stateParams.token_search; - const searchPath = `${GetBasePath('users')}${$stateParams.user_id}/tokens`; - Wait('start'); - return qs.search(searchPath, searchParam) - .finally(() => { - Wait('stop'); - }); - } - ], - } -}; diff --git a/awx/ui/client/index.template.ejs b/awx/ui/client/index.template.ejs deleted file mode 100644 index c8d4e0d75898..000000000000 --- a/awx/ui/client/index.template.ejs +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - <% htmlWebpackPlugin.files.css.forEach(file => {%> - - <% }) %> - <% htmlWebpackPlugin.files.js.forEach(file => {%> - - <% }) %> - - - -
- - - -
-
-
-
- - - - - - - - - - - - - - - - -
-
-

working...

-
-
-
- - - diff --git a/awx/ui/client/installing.template.ejs b/awx/ui/client/installing.template.ejs deleted file mode 100644 index 432c42b48b57..000000000000 --- a/awx/ui/client/installing.template.ejs +++ /dev/null @@ -1,34 +0,0 @@ - - - - {% load staticfiles %} - - - - - - - <% htmlWebpackPlugin.files.css.forEach(file => {%> - - <% }) %> - <% htmlWebpackPlugin.files.js.forEach(file => {%> - - <% }) %> - - - -
- - is Upgrading - - -

is currently upgrading.

-

This page will refresh when complete.

-
-
- - \ No newline at end of file diff --git a/awx/ui/client/legacy/styles/angular-scheduler.less b/awx/ui/client/legacy/styles/angular-scheduler.less deleted file mode 100644 index 2dfe0aefe325..000000000000 --- a/awx/ui/client/legacy/styles/angular-scheduler.less +++ /dev/null @@ -1,224 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2015 Ansible, Inc. - * - * Styling for angular-scheduler - * - */ - - /* - #schedules-form-container -inventory group add/edit dialog - */ - -#schedules-tab { - position: relative; - top: 0; - left: 0; -} - -#schedules-overlay { - display: none; - position: absolute; - top: 0; - left: 0; - z-index: 100; - background-color: @black; - opacity: 0; -} - -#schedules-list { - overflow-x: hidden; - overflow-y: auto; -} - -#schedules-form-container { - position: absolute; - top: 0; - left: 0; - display: none; - border: 1px solid #e5e5e5; - border-radius: 4px; - box-shadow: 3px 3px 6px 0 #666; - padding: 0 10px 15px 8px; - background-color: @white; - z-index: 200; -} - -#schedules-title { - border-bottom: 1px solid #e5e5e5; - padding-bottom: 8px; - margin-bottom: 10px; - margin-top: 0; - h4 { - display: inline-block; - margin: 0; - } - button { - display: inline-block; - } -} - -#schedules-form-container-body { - overflow-x: hidden; - overflow-y: auto; -} - -#schedules-form .form-group { - margin-bottom: 15px; -} - -#schedules-buttons { - height: 46px; - padding-top: 10px; - text-align: right; - border-top: 1px solid #A6C9E2; - margin-top: 5px; - a { - margin-right: 8px; - font-size: 12px; - } -} - -#schedules-detail { - display: none; -} - -#scheduler-modal-dialog, #schedules-form-container { - display: none; - overflow-x: hidden; - overflow-y: auto; - padding-top: 25px; - - form { - width: 100%; - } - - .sublabel { - font-weight: normal; - } - - #occurrence-label { - display: inline-block; - } - - .occurrence-list { - border: 1px solid @well-border; - padding: 8px 10px; - border-radius: 4px; - background-color: @well; - list-style: none; - margin-bottom: 5px; - } - - #date-choice { - display: inline-block; - margin-left: 15px; - font-size: 12px; - - .label-inline { - display: inline-block; - vertical-align: middle; - } - input { - margin-bottom: 2px; - height: 11px; - width: 10px; - } - .label-inline:first-child { - padding-bottom: 2px; - margin-right: 10px; - } - .label-inline:nth-child(3) { - margin-right: 10px; - } - } - - .ui-widget input { - font-size: 12px; - font-weight: normal; - text-align: center; - } - .scheduler-time-spinner { - width: 40px; - height: 24px; - } - .scheduler-spinner { - width: 50px; - height: 24px; - } - .fmt-help { - font-size: 12px; - font-weight: normal; - color: #999; - padding-left: 10px; - } - .error { - color: #dd1b16; - font-size: 12px; - margin-bottom: 0; - margin-top: 0; - padding-top: 3px; - } - .error-pull-up { - position: relative; - top: -20px; - } - .red-text { - color: #dd1b16; - } - .help-text { - font-size: 12px; - font-weight: normal; - color: #999; - margin-top: 5px; - } - .inline-label { - margin-left: 10px; - } - .radio-inline input[type="radio"]{ - margin-top: 2px; - margin-left: -15px; - } - #scheduler-buttons { - margin-top: 20px; - } - .no-label { - padding-top: 25px; - } - .padding-top-slim { - padding-top: 5px; - } - .option-pad-left { - padding-left: 15px; - } - .option-pad-top { - padding-top: 15px; - } - .option-pad-bottom { - padding-bottom: 15px; - } - #monthlyOccurrence, #monthlyWeekDay { - margin-top: 5px; - } - select { - width: 100%; - } - .occurrence-list { - border: 1px solid @well-border; - padding: 8px 10px; - border-radius: 4px; - background-color: @well; - list-style: none; - margin-bottom: 5px; - } - - #weekdaySelect .btn-default:hover, - #weekdaySelect .btn-default:focus { - background-color: #fff; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - } - - #weekdaySelect .btn-default.active:hover { - background-color: #e0e0e0; - } -} diff --git a/awx/ui/client/legacy/styles/animations.less b/awx/ui/client/legacy/styles/animations.less deleted file mode 100644 index 98a5a1f6f8ee..000000000000 --- a/awx/ui/client/legacy/styles/animations.less +++ /dev/null @@ -1,27 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * animations.css - * - * custom animation mixins for ansible-ui - * - */ - - -.pulsate(@duration: 1.5s) { - -webkit-animation:pulsate @duration linear infinite alternate; - -moz-animation:pulsate @duration linear infinite alternate; - animation:pulsate @duration linear infinite alternate; -} -@-webkit-keyframes pulsate { - 0% { -moz-transform: scale(.3); opacity: .2; } - 100% { -moz-transform: scale(1.1); opacity: 1; } -} -@-webkit-keyframes pulsate { - 0% { -webkit-transform: scale(.3); opacity: .2; } - 100% { -webkit-transform: scale(1.1); opacity: 1; } -} -@keyframes pulsate { - 0% { -webkit-transform: scale(.3); transform:scale(.3); opacity: .2;} - 100% { -webkit-transform: scale(1.1); transform:scale(1.1); opacity: 1;} -} diff --git a/awx/ui/client/legacy/styles/ansible-ui.less b/awx/ui/client/legacy/styles/ansible-ui.less deleted file mode 100644 index 6349dfbd616c..000000000000 --- a/awx/ui/client/legacy/styles/ansible-ui.less +++ /dev/null @@ -1,2347 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * ansible-ui.css - * - * custom styles for ansible-ui - * - */ - -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 400; - src: url(/static/assets/OpenSans-Regular.ttf); -} - -@font-face { - font-family: 'Open Sans'; - font-style: bold; - font-weight: 600; - src: url(/static/assets/OpenSans-Bold.ttf); -} - -/* Bootstrap fix that's causing a right margin to appear - whenver a modal is opened */ -body.modal-open { - margin-right: 0; -} - -/* Helper Classes */ -.pad-right-sm { padding-right: 10px; } -.pad-left-md { padding-left: 30px; } -.pad-left-sm { padding-left: 10px; } -.pad-left-lg { padding-left: 50px; } -.normal-weight { font-weight: normal; } -.small-text { font-size: 12px; font-weight: normal; } -.no-bullets { list-style: none; } -.nowrap { white-space: nowrap; } -.capitalize { text-transform: capitalize; } -.grey-txt { color: @grey; } -.text-center { text-align: center !important; } -.cursor-pointer { cursor: pointer } - -.red-txt, -a.red-txt:visited, -a.red-txt:hover, -a.red-txt:active { - color: @red; -} - -/* Used on inventory groups/hosts lists for long names */ -.ellipsis { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -blockquote { - font-size: 14px; -} - -.group-name { - display: inline-block; - width: 85%; -} - -a { - color: @blue-link; - text-decoration: none; -} - -a:hover, -a:focus { - color: @blue-dark; - text-decoration: none; -} -.btn{ - text-transform: uppercase; -} -/* Old style TB default button with grey background */ -.btn-grey { - color: @default-data-txt; - background-color: @d7grey; - border-color: @d7grey; -} - -.btn-grey:hover { - background-color: @default-bg; -} - -#cowsay { - padding-left: 30px; - max-width: 340px; - background-color: white; - border-style: none; -} - - -#about-modal-titlelogo{ - margin-bottom: 10px; - width: 160px; - height: 53px; -} - -#copyright-text{ - margin-top: 10px; - margin-bottom: 10px; -} - -/* Make buttons appear to be disabled, but allow mouse events */ -.btn-disabled { - opacity: 1; - -webkit-box-shadow: none; - box-shadow: none; -} - -.btn-disabled { - cursor: not-allowed; -} - -/* Bring primary (blue) buttons in line with link colors */ -.btn-primary { - background-color: @default-link; -} - -.btn-primary:hover { - background-color: @default-link-hov; -} - -/* List Actions column */ -.actions { - a { - font-size: 18px; - } - a:last-child { - margin-right: 0; - } - a:hover { - cursor: pointer; - } - .dropdown .caret { - border-top-color: @blue-link; - } -} - -// removing all the pesky outlines on buttons/links/etc. -a:focus, -a:active, -button:focus, -button:active, -i:focus, -i:active, -.btn:focus, -.btn:active:focus { - outline: 0; -} - -.jqstooltip{ - background-color: black !important; - border-radius:4px; - border: 1px solid black; -} - -.smart-status-tooltip{ - font-size: 12px; - font-family: 'Open Sans'; - background-color: black; - border-radius:4px; - span { - padding: 3px; - } -} - -.IdleModal-remainingSeconds{ - color: @default-err; -} - -#configure-schedules-tab { - position: relative; - top: 0; - left: 0; -} - -#configure-schedules-overlay { - display: none; - position: absolute; - top: 0; - left: 0; - z-index: 100; - background-color: @black; - opacity: 0; - } - -#configure-schedules-buttons{ - height: 46px; - padding-top: 10px; - text-align: right; - border-top: 1px solid @default-border; - margin-top: 5px; - a { - margin-right: 8px; - font-size: 12px; - } -} - -#configure-schedules-form-container { - position: absolute; - top: 0; - left: 0; - display: none; - border: 1px solid @default-border; - border-radius: 4px; - box-shadow: 3px 3px 6px 0 @default-dark; - padding: 0 10px 15px 8px; - background-color: @white; - z-index: 200; -} - -#configure-schedules-title { - border-bottom: 1px solid @default-border; - padding-bottom: 8px; - margin-bottom: 10px; - margin-top: 0; - h4 { - display: inline-block; - margin: 0; - } - button { - display: inline-block; - } -} - -#configure-schedules-list { - overflow-x: hidden; - overflow-y: auto; -} - -#configure-schedules-overlay { - display: none; - position: absolute; - top: 0; - left: 0; - z-index: 100; - background-color: @black; - opacity: 0; -} - -#configure-dialog, #configure-schedules-form-container { - display: none; - overflow-x: hidden; - overflow-y: auto; - padding-top: 25px; - - form { - width: 100%; - } - - .sublabel { - font-weight: normal; - } - - #occurrence-label { - display: inline-block; - } - - .occurrence-list { - border: 1px solid @well-border; - padding: 8px 10px; - border-radius: 4px; - background-color: @well; - list-style: none; - margin-bottom: 5px; - } - - #date-choice { - display: inline-block; - margin-left: 15px; - font-size: 12px; - - .label-inline { - display: inline-block; - vertical-align: middle; - } - input { - margin-bottom: 2px; - height: 11px; - width: 10px; - } - .label-inline:first-child { - padding-bottom: 2px; - margin-right: 10px; - } - .label-inline:nth-child(3) { - margin-right: 10px; - } - } -} -#home_groups_table .actions .cancel { padding-right: 3px; } - -.success-badge { - color: @default-bg; - background-color: @default-succ; -} - -.bold-text .checkbox-inline { - font-weight: bold; -} - -/* Disable textarea re-sizing as a general rule */ -textarea { - resize: none; -} - -textarea.allowresize { - resize: both; -} - -/* Working... spinner */ -.spinny { - display: none; - position: fixed; - z-index: 2000; - width: 138px; - height: 50px; - text-align:center; - color: @d7grey; - background-color: @black; - border: 1px solid @grey; - border-radius: 6px; - padding-top: 10px; - - p { - padding-top: 0px; - font-size: 18px; - text-align: right; - margin-right: 10px; - } - - i { - float: left; - margin-left: 10px; - } -} - -.subtitle { - font-size: 16px; -} - -.license-version { - font-size: 18px; - color: @grey-txt; -} - -// #license_eula{ -// white-space: nowrap; -// } - -.modal-dialog .ui-accordion .ui-accordion-content { - overflow: hidden; -} - -.overlay { - display: none; - position: absolute; - top: 0; - left: 0; - z-index: 1080; - background-color: @black; - opacity: 0; -} - -/* TB tooltip overrides */ - .popover-content { - width: 100%; - padding: 0; - - .table>tbody>tr>td { - padding-left: 0; - border-top: 1px solid @b7grey; - } - } - h3.popover-title, .popover-content, .popover-content blockquote, .popover-content a { - font-size: 12px; - } - .flyout { - margin-bottom: 0; - } - .flyout thead> tr> th, .flyout tbody> tr> td, .flyout tbody> tr> td> a { - font-size: 12px; - } - .flyout tbody > tr:last-child > td { - padding-bottom: 0; - } - .popover-title { - padding: 0 0 5px 0; - background-color: @default-interface-txt; - color: @default-bg; - font-weight: 600; - border-bottom: none; - text-transform: uppercase; - } - .popover { - z-index: 2000; - min-width: 200px; - max-width: 325px; - background-color: @default-interface-txt; - color: @default-bg; //white - text-align: left; - padding: 10px; - font-weight: 400; - - code { - color: @default-data-txt; - background-color: @default-white-button-bord; - line-height: 18px; - } - - a { - color: @default-warning; - &:hover { - color: @default-warning-hov; - } - } - - p { - font-weight: 400; - } - - p:last-child { - margin-bottom: 0; - } - } - .popover.right>.arrow:after { - border-right-color: @default-interface-txt; - } - .popover.left>.arrow:after { - border-left-color: @default-interface-txt; - } - .popover.bottom>.arrow:after { - border-bottom-color: @default-interface-txt; - } - .popover.top>.arrow:after { - border-top-color: @default-interface-txt; - } - .popover pre { - white-space: pre-wrap; - } - .popover-footer { - font-size: 12px; - margin-top: 10px; - text-align: right; - color: @grey; - .key { - color: @white; - background-color: @grey; - padding: 0 1px 1px 1px; - border-radius: 3px; - } - } - -.alert { - margin-top: 15px; - margin-bottom: 15px; -} - -hr { - border-color: @default-border; -} - -.help { - display: inline-block; -} - -.help-auto-off { - margin-top: 15px; - margin-bottom: 15px; - margin-left: 10px; - label { - font-weight: normal; - } -} - -/* help collapse */ - h4.panel-title { - font-size: 14px; - } - - .panel-heading:hover { - cursor: pointer; - } - - .panel-default>.panel-heading .collapse-help-icon { - color: @grey; - } - - .collapsible-help { - margin-top: 20px; - margin-bottom: 20px; - dl { - margin-left: 15px; - } - dt { - margin-top: 15px; - } - } - -/* -th.actions-column, -td.actions { - white-space: nowrap; -} -*/ - -.tab-content { - padding-top: 15px; -} - -.btn .caret { - border-top-color: @default-icon; -} - -.btn-light { - color: @default-data-txt; - background-color: @d7grey; - border-color: @d7grey; -} - -.refresh-grp { - display: inline-block; - text-align: right; - margin-left: 0; - margin-top: 0; - padding: 0; - line-height: normal; - - .refresh-msg { - font-size: 10px; - } -} - -.btn-light:hover { - color: @d7grey; - background-color: @default-icon; - border-color: @default-icon; -} - -/* Make a div or any element behave like pre. Use in conjunction with .mono-space */ -.pre { - white-space: pre; -} - - -dd { - margin-left: 15px; -} - -/* Use code-breakable in pop-over text to indent and wrap code segments */ - -.code-breakable { - padding-left: 10px; - word-wrap: break-word; -} - -.break { - word-break: break-all; -} - -.controls { - min-height: 15px; -} - -#navbar-container, .main-menu { - width: 100%; - background-color: @default-dark; -} - -.text-justify { - text-align: justify; -} - -.help-link, -.help-link:active, -.help-link:visited, -.ui-widget-content a.help-link, -.ui-widget-content a.help-link:active, -.ui-widget-content a.help-link:visited { - color: @default-icon; - text-decoration: none; -} - -.help-link:hover, -.ui-widget-content a.help-link:hover { - color: @default-interface-txt; - text-decoration: none; -} - -.login-header img { - width: 60%; -} - -.form-title { - display: inline-block; - width: 100%; - vertical-align: middle; - font-weight: bold; - padding-left: 15px; - margin-bottom: 10px; -} - -.form-cancel { - float: right; - margin-right: 10px; -} - -.form-title-hr { - margin-bottom: 20px; -} - -.form-horizontal .buttons { - margin-top: 25px; -} - -.label-text { - padding-right: 10px; -} - -.label-hint-text { - font-weight: normal; - color: @grey; -} -.label-hint-text:before { - /* for a line break before hintText */ - content: '\A'; - white-space: pre; -} - -#group_form #group_tabs { - margin-top: 25px; -} - -/* Outline required fields in Red when there is an error */ - .form-control.ng-dirty.ng-invalid, .form-control.ng-dirty.ng-invalid:focus { - border-color: @default-err; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(255, 88, 80, 0.6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(255, 88, 80, 0.6); - } - - .form-control.ng-dirty.ng-invalid + .select2 .select2-selection, - .form-control.ng-dirty.ng-invalid + .select2 .select2-selection:focus { - border-color: @default-err !important; - outline: 0 !important; - box-shadow: none !important; - } - - .form-control.ng-dirty.ng-pristine { - border-color: @b7grey; - box-shadow: none; - } - - .form-control.ng-dirty.ng-pristine:focus { - border-color: @default-link; - } -/* For some reason TB 3 RC1 does not provide an input-mini */ - -.input-mini { - height: 26px; - padding: 3px 8px; - font-size: 12px; - border-radius: 3px; -} - -.error { - font-size: 12px; - line-height: normal; - color: @red; -} - -.xsmall { - font-size: 12px; -} - -.note { - padding-top: 15px; - font-size: 12px; -} - -legend { - font-size: medium; - font-weight: bold; -} - -.navigation { - margin: 15px 0 15px 0; -} - -.footer-navigation { - margin: 10px 0 10px 0; -} - -.lookup-navigation { - margin: 15px 0 0 0; - /*padding-top: 20px;*/ - -} - -#lookup-modal-dialog { - overflow-x: hidden; - .instructions { - margin-top: 0; - margin-bottom: 20px; - } -} - -.related-footer { - margin: 10px 0 0 0; -} - -select.page-size { - width: 65px; - height: 24px; - font-size: 10px; -} - -.page-size-label { - margin-left: 15px; - font-size: 10.5px; - font-weight: normal; -} - -.accordion-heading { - font-weight: bold; - color: @blue-link; -} - -.accordion-heading i { - margin-right: 5px; -} - -.status-actions { - display: inline-block; - height: 25px; -} - -.status-spin { - display: inline-block; - margin-left: 15px; - font-size: 22px; - vertical-align: middle; -} - -/* Search Widget */ - - .search-widget label { - display: inline-block; - padding-right: 15px; - vertical-align: middle; - } - - #search-widget-spacer { - height: 20px; - } - -/* breadcrumbs */ -.nav-path { - padding: 5px 0 10px 0; - margin-right: 2px; - margin-bottom: 15px; - font-size: 14px; - font-weight: bold; - background-color: @default-no-items-bord; - border: 1px solid @d7grey; - border-radius: 6px; - box-shadow: 3px 3px 4px 0 @default-icon; - - .breadcrumb { - display: inline-block; - padding-bottom: 0; - padding-left: 0; - padding-right: 0; - margin-bottom: 0; - margin-left: 10px; - } - - .dropdown { - display: inline-block; - margin-right: 0; - paddding-right: 0; - - .toggle, .toggle:visited, .toggle:hover, .toggle:active { - color: @black; - } - - li a.active { - color: @grey; - } - - .crumb-icon { - font-size: 12px; - } - } -} - -.actions .dropdown { - display: inline-block; -} - -/* Display drop-down menus on hover. Remove margin between toggle link - and menu, allowing smooth mouse movement between toggle and menu - - http://stackoverflow.com/questions/8878033/how-to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click -*/ - -/* .dropdown-toggle:hover .dropdown-menu, .dropdown:hover .dropdown-menu { - display: block; - } - - .dropdown-menu li:hover { - visibility: visible; - } - - .dropdown-menu { - margin-top: 0; - z-index: 200; - } -*/ -/* end */ - -.greeting { - padding-right: 22px; -} - -.breadcrumb .active { - color: @black; -} - -.nav-tabs > li > a { - font-weight: bold; -} - -input[type="text"].field-mini-height { - height: 12px; - font-size: 10.5px; -} - -select.field-mini-height { - height: 22px; - font-size: 10.5px; -} - -.no-padding { - padding: 0; - margin: 0; -} - -input[type="checkbox"].checkbox-no-label { - margin-top: 10px; -} - -.radio-group { - .radio-inline + .radio-inline { - margin-left: 0; - } -} - -.checkbox-group { - .radio-inline + .radio-inline, - .checkbox-inline + .checkbox-inline { - margin-left: 0; - } - .checkbox-inline, .radio-inline { - margin-right: 10px; - } - - .checkbox-inline.stack-inline { - display: block; - } -} - -.checkbox-options { - font-weight: normal; -} - -/* Display list actions next to search widget */ -.list-actions { - display: flex; - height: 34px; - justify-content: flex-end; - margin-bottom: -34px; - text-align: right; - - .fa-lg { - vertical-align: -8%; - } -} - -.jqui-accordion { - .list-actions { - margin: 0; - } - /*.list-wrapper { - background-color: @well; - padding: 10px; - border-radius: 4px; - border: 1px solid @well-border; - }*/ - .ui-accordion-content { - padding-left: 15px; - padding-right: 15px; - } - .page-label { - margin-top: 5px; - } -} - -#home-list-actions { - margin-bottom: 15px; -} - -/* End Display list actions */ - - -/* Enable table-hover to work when table is in a well */ - -.table-hover tbody tr:hover > td, -.table-hover tbody tr:hover > th { - background-color: @default-bg; -} - -.table-hover-inverse tbody tr:hover > td, -.table-hover-inverse tbody tr:hover > th { - background-color: @active-color; -} - -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: @active-color; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr.success:hover > th { - background-color: @active-color; -} - -.table-summary thead > tr > th, -.table-summary tbody > tr > th, -.table-summary tfoot > tr > th, -.table-summary thead > tr > td, -.table-summary tbody > tr > td, -.table-summary tfoot > tr > td { - border-top: 1px solid @d7grey; -} - -.table-summary thead > tr > th { - border-bottom: 1px solid @d7grey; -} - -/* Table without row borders */ - -.table-no-border thead > tr > th, -.table-no-border tbody > tr > th, -.table-no-border tfoot > tr > th, -.table-no-border thead > tr > td, -.table-no-border tbody > tr > td, -.table-no-border tfoot > tr > td { - border-top: none; -} - -.table > tbody > tr > td{ - padding: 0.5em 0.6em; - &.actions{ - padding: 0px; - > a { - padding: 0.5em 0.6em; - display: inline-block; - } - } -} - -/* Less padding on .table-condensed */ -.table-condensed>tbody>tr>td:not(:last-child), -.table-condensed>thead>tr>th:not(:last-child) { - padding: 0.5em 20px 0.5em 0px; -} - -.table-condensed>tbody>tr>td:last-child, -.table-condensed>thead>tr>th:last-child { - padding: 0.5em 0px; -} - -.table.table-condensed.flyout { - thead>tr>th { - padding-left: 0; - border: none; - } -} - -/* Table info rows */ - -.loading-info { - color: @grey-txt; - font-weight: normal; - padding: 15px 0; -} - -/* Status Icons */ - - .license-expired, - .license-invalid, - .icon-failures-true, - .active-failures-true a, - .active-failures-true a:active, - .job-failed, - .job-error { - color: @default-err; - } - - .icon-failures-true a:hover { - color: @red; - } - - .job-failures-true { - padding-top: 5px; - color: @default-err; - } - - .job-event-status, - .license-status { - padding-top: 5px; - } - - - .job-new, - .license-valid, - .job-success, - .job-successful { - color: @green; - } - - .icon-host-all:before, - .icon-host-failed:before, - .icon-job-active:before, - .icon-job-running:before, - .icon-job-success:before, - .icon-job-successful:before, - .icon-job-changed:before, - .icon-job-ok:before, - .icon-job-OK:before, - .icon-job-failed:before, - .icon-job-skipped:before { - content: "\f111"; - } - - .icon-job-stopped:before, - .icon-job-error:before, - .icon-job-canceled:before, - .icon-job-stdout-download-tooltip:before, - .icon-job-unreachable:before, - .icon-job-failed:before { - content: "\f06a"; - } - - .icon-job-pending:before, - .icon-job-waiting:before, - .icon-job-new:before, - .icon-job-none:before, - .icon-job-no-matching-hosts:before { - content: "\f10c"; - } - - .icon-job-active, - .icon-job-running, - .icon-job-success, - .icon-job-successful, - .icon-job-ok, - .icon-job-OK { - color: @green; - } - - .icon-job-skipped { - color: @skipped; - } - - .icon-job-running { - .pulsate(); - } - - .icon-job-changed, - .job-changed { - color: @changed; - } - - .icon-host-failed, - .icon-job-stopped, - .icon-job-error, - .icon-job-failed, - .icon-job-stdout-download-tooltip, - .icon-job-canceled { - color: @red; - } - - .icon-host-all { - color: @at-blue; - } - - .icon-job-unreachable { - color: @unreachable; - } - - .icon-job-none, - .icon-job-pending, - .icon-job-waiting, - .icon-job-new, - .icon-job-no-matching-hosts { - color: @grey; - opacity: 0.45; - } - - .icon-schedule-enabled-true:before { - content: "\f04d"; - } - - .icon-schedule-enabled-false:before { - content: "\f04b"; - } - - .icon-socket-ok:before { - content: "\f111"; - color: @green; - } - .icon-socket-error:before { - content: "\f111"; - color: @red; - } - .icon-socket-connecting:before { - content: "\f042"; - color: @warning; - } - -/* job_events page */ - - #jobevents_table { - div.return-code { - display: inline-block; - margin-left: 10px; - } - textarea { - white-space: pre-wrap; - resize: vertical; - } - } - - #password-modal .alert-info { - margin-top: 0; - margin-bottom: 25px; - } - -/* Inventory job status badge */ - .failures-true { - background-color: @red; - color: @default-bg; - } - - .failures-false { - background-color: @green; - color: @default-bg; - } - -/* Cloud inventory status. i.e. inventory_source.status values */ - - .icon-cloud-na:before, - .icon-cloud-never:before, - .icon-cloud-updating:before, - .icon-cloud-running:before, - .icon-cloud-successful:before, - .icon-cloud-pending:before, - .icon-cloud-failed:before, - .icon-cloud-canceled:before, - .icon-cloud-error:before { - content: "\f0c2"; - } - - /*.icon-cloud-failed:before, - .icon-cloud-error:before { - content: "\f06a"; - }*/ - - .icon-cloud-na, - .icon-cloud-never, - a.icon-cloud-na:hover, - a.icon-cloud-never:hover { - color: @grey; - } - - .icon-cloud-updating, - .icon-cloud-running, - .icon-cloud-successful, - .icon-cloud-pending, - a.icon-cloud-updating:hover, - a.icon-cloud-successful:hover { - color: @green; - } - - .icon-cloud-failed, - .icon-cloud-error, - .icon-cloud-canceled, - a.icon-cloud-failed:hover { - color: @red; - } - - .icon-cloud-updating, - .icon-cloud-running, - .icon-cloud-pending { - .pulsate(); - } - - .icon-enabled-true:before { - content: "\f046"; - } - - .icon-enabled-true { - color: @green; - width: 14px; - - } - .icon-enabled-false:before { - content: "\f096"; - } - - .icon-enabled-false{ - color: @red; - width: 14px; - } - -/* Inventory cloud sourced? indicator */ - .icon-cloud-true:before { - content: "\f111"; - } - - .icon-cloud-false:before { - content: "\f111"; - } - - .error-color { - color:@red; - } - - .connecting-color { - color: @warning; - } - - .ok-color, - .icon-cloud-true { - color: @green; - } - - .icon-cloud-false { - color: @grey; - } -/* end */ - - .field-success { - color: @default-succ; - } - - .field-success input { - border-color: @default-succ; - } - - .field-failure { - color: @red; - } - - .field-failure input { - border-color: @red; - } - - .field-badge { - font-size: 12px; - margin-right: 3px; - } - - .license-warning, - .license-demo { - color: @warning; - } - - .job-detail-status { - display: inline-block; - margin-top: 5px; - font-size: 15px; - } - - /*.form-items .search-widget { - margin-top: 15px; - }*/ - - .form-items .item-count { - display: inline-block; - margin-top: 25px; - font-size: small; - } - - .child-event a { - color: @black; - cursor: default; - } - /* Padding levels used on job events and inventory groups */ - .level { display: inline-block; } - .level-1 { padding-left: 15px; } - .level-2 { padding-left: 30px; } - .level-3 { padding-left: 45px; } - .level-4 { padding-left: 60px; } - .level-5 { padding-left: 75px; } - .level-6 { padding-left: 90px; } - .level-7 { padding-left: 105px; } - .level-8 { padding-left: 120px; } - .level-9 { padding-left: 135px; } - .level-10 { padding-left: 150px; } - - .level-3-detail { - padding-left: 80px; - } - - #job_events .control-group { - margin-top: 0; - margin-bottom: 10px; - } - -/* End Jobs Page */ - - -/* license modal */ - #license-modal-dialog { - overflow-x: hidden; - - input[readonly], - textarea[readonly] { - background-color: @default-border; - border: 1px solid @default-icon; - } - - .fa-external-link { - color: @grey; - font-size: 10px; - } - - .free-button { - background-color: @default-err; - border: 1px solid @default-err; - color: @white; - } - .free-button:hover { - background-color: @default-err-hov; - border: 1px solid @default-err-hov; - color: @white; - } - } - -/* Inventory nav links */ - .navigation-links { - - padding: 0; - margin-top: -10px; - - a { - margin-right: 15px; - } - - a:last-child { - margin-right: 20px; - } - } - -/* Dashboard */ - #home #container1.col-lg-6, - #home #container3.col-lg-6 { - padding-right: 7px; - } - - #home #container2.col-lg-6, - #home #container4.col-lg-6 { - padding-left: 7px; - } - - -/* Inventory Edit */ - - #hosts-container.col-lg-6 { - padding-left: 7px; - padding-right: 17px; - } - - #groups-container .well, - #hosts-container .well { - padding: 8px; - margin-bottom: 0; - } - - #home_groups_table i[class*="icon-job-"] { - margin-left: 5px; - } - - .selected { - font-weight: bold; - color: @blue-dark; - } - - .inventory-title { - font-size: 16px; - font-weight: bold; - } - - .active-row { - background-color: @white; - border-bottom: 1px solid @default-tertiary-bg; - border-right: 1px solid @default-tertiary-bg; - } - - .node-toggle, .node-no-toggle { - /* also used on job evetns */ - float: none; - padding-top: 3px; - padding-left: 0; - margin-right: 5px; - margin-left: 0; - } - - .node-no-toggle { - opacity: .30; - } - - .draggable-clone { - opacity: .60; - font-weight: bold; - /*z-index: 2000; - overflow: visible; - whitespace: wrap; - text-overflow: clip;*/ - } - - .droppable-hover { - background-color: @info; - color: @info-color; - padding: 6px; - border: 1px solid @info-border; - border-radius: 4px; - /*overflow: visible; - whitespace: wrap; - text-overflow: clip;*/ - } - - #group-delete-dialog .help-container, - #password-modal .help-container { - .help-link, - .help-link:active, - .help-link:visited { - color: @blue-link; - } - - .help-link:hover { - color: @blue-dark; - } - } - - - .btn-danger { - background-color: @red; - border-color: @red-focus; - } - - .btn-danger:hover, - .btn-danger:focus, - .btn-danger:active { - border-color: @red-focus; - background-color: @red-focus; - } - -// ad hoc permission checkbox -.squeeze.form-group { - margin-bottom: 10px; -} - -.disabled { - color: @grey; -} - -a.disabled:hover { - color: @grey; - cursor: not-allowed; -} -a.btn-disabled:hover { - cursor: not-allowed; -} - -/* Variable Editing */ - .parse-selection { - display: inline-block; - margin: 5px 0 8px 0; - font-size: 12px; - line-height: normal; - } - - .parse-selection input { - margin-left: 5px; - } - - .parse-select .parse-label { - margin-left: 3px; - color: @field-input-text; - } - - .parse-label { - color: @field-input-text; - font-weight: normal; - } - - .external-editor-link { - display: inline-block; - margin-left: 20px; - } - -.slider { - display: inline-block; - width: 100px; - margin: 0 10px; - vertical-align: middle; -} - -/* Sort link styles */ - -.list-header-noSort:hover.list-header:hover{ - cursor: default; -} - -.list-header:hover { - cursor: pointer; -} - -.list-header i { - margin-left: 10px; -} - -.list-header .icon-sort { - color: @default-icon; -} - -.list-header .icon-sort-down, -.list-header .icon-sort-up { - color: @black; -} - -/* job_events syles */ - -#jobevents_table .actions i { - padding-top: 0; - margin-right: 0; -} - -tr td button i { - padding-top: 0; - margin-right: 0; -} - -.event-form { - margin-top: 10px; - margin-bottom: 5px; - - label { - font-weight: normal; - } -} - -.event-detail-host { - padding-top: 10px; - padding-bottom: 5px; -} - -.form-section-title { - width: 100%; - margin-top: 0; - margin-bottom: 10px; - font-weight: bold; - border-bottom: 1px solid @default-border; -} - -.modal-backdrop, -.modal-backdrop.fade.in { - opacity: 0.6; - filter: alpha(opacity=60); -} - -.modal-body .ui-accordion .ui-accordion-content { - padding: 10px; -} - -/* overrides to TB modal */ -.modal-content { - padding: 20px; -} - -.modal-header { - color: @default-interface-txt; - white-space: nowrap; - width: 90%; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - border: none; - padding: 0; -} - -.modal { - border: 1px solid @black; -} - -.modal .SmartSearch-bar { - width: 100%; -} - -#alert-modal, #alert-modal2 { - z-index: 2100; -} - -.close { - color: @grey; - opacity: .7; - filter: alpha(opacity=70); -} - -.modal-header h3 { - margin: 0; - text-rendering: optimizeLegibility; - font-size: 15px; - color: @default-interface-txt; - font-weight: bold; - line-height: normal; - font-family: 'Open Sans', helvetica; - text-transform: uppercase; -} - -.modal-body { - min-height: 120px; - padding: 20px 0; - - .alert { - padding: 10px; - margin: 0; - word-wrap: break-word; - } - .alert-danger { - background-color: @default-bg; - border: none; - color: @default-interface-txt; - } -} - -#prompt-modal .modal-body { - padding-bottom: 30px; -} - -.skinny-modal .modal-body { - padding: 5px 10px 0 10px; -} - -.modal-footer { - padding: 0; - border: none; - margin-top: 0; - display: flex; - justify-content: flex-end; - - .btn.btn-primary { - text-transform: uppercase; - background-color: @default-succ; - border-color: @default-succ; - padding: 5px 15px; - cursor: pointer; - - &:hover { - background-color: @default-succ-hov; - border-color: @default-succ-hov; - } - - &:disabled { - background-color: @default-succ-disabled; - border-color: @default-succ-disabled; - } - } - - .btn + .btn { - margin: 0; - } -} - -/* form navigation */ -.navigation-buttons { - height: 40px; -} - - -/* PW progress bar */ -.pw-progress { margin-top: 10px; - - li { - line-height: normal; - margin-bottom: 10px; - } - ul:last-child { - margin-top: 10px; - } - -} - -/* Home page */ - -.failed-column { - a:link, a:visited { - color: @red; - } - a:hover { - color: @red-hover; - } -} - -/* Help modal dialog */ - -#help-modal-dialog { - overflow: hidden; - padding: 10px; - - img { - margin-top: 15px; - margin-bottom: 15px; - border: 1px solid @grey; - box-shadow: 3px 3px 5px 0 @grey; - } - - .img-container, - .icon-container { - width: 100%; - text-align: center; - } - - .icon-container { - margin-top: 15px; - margin-bottom: 15px; - } - - .help-box { - width: 100%; - margin-top: 15px; - border-radius: 6px; - color: @grey-txt; - font-size: 14px; - } - - .fa-rss { - transform:rotate(-45deg); - } -} - -/* job stdout */ - - #pre-container { - overflow: auto; - width: 100%; - border-radius: 4px; - margin: 0; - } - - -/* ng-cloak directive */ - -[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { - display: none !important; -} - - -/* Socket testing page */ -#sockets { - .section-title { - font-weight: bold; - color: @blue-link; - margin-top: 30px; - } - #test-container .section-title { - margin-top: 20px; - } - .well { - padding: 9px; - } - .message-section { - height: 150px; - overflow: auto; - } - .events-section { - margin-top: 40px; - .section-title { - margin-top: 0; - } - } - #event-message-container { - height: 200px; - } -} - -/* Large desktop */ - -@media (min-width: 1200px) { - - .delete-btn { - /* Used on job and project page to make cancel and delete buttons have an equal width */ - width: 60px; - } - - .label-text { - text-align: right; - } - -} - -@media (min-width: 768px) and (max-width: 1199px) { - - .level-1, - .level-2, - .level-3, - .level-4, - .level-5, - .level-6, - .level-7, - .level-8, - .level-9, - .level-10, - .level-3-detail { - padding-left: 0; - } - - .label-text { - text-align: left; - } - - .group-name { - width: 80%; - } - - #groups-container.col-lg-6 { - padding-right: 15px; - } - - #hosts-container.col-lg-6 { - margin-top: 15px; - padding-left: 15px; - padding-right: 15px; - .well { - margin-bottom: 0; - } - } - -} - -/* Landscape phone to portrait tablet */ - -@media (max-width: 767px) { - - /* Job events */ - - .level-1, - .level-2, - .level-3, - .level-4, - .level-5, - .level-6, - .level-7, - .level-8, - .level-9, - .level-10, - .level-3-detail { - padding-left: 0; - } - - table { - word-wrap: break-word; - table-layout: fixed; - } - - th.actions-column, - td.actions { - white-space: normal; - } - - td.actions .btn { - width: 75px; - margin-bottom: 5px; - } - - .group-name { - width: 80%; - } - - .label-text { - text-align: left; - } - - .list-action-label { - display: none; - } - - #groups-container.col-lg-6 { - padding-right: 15px; - } - - #hosts-container.col-lg-6 { - margin-top: 15px; - padding-left: 15px; - padding-right: 15px; - } -} - -// lists.less uses 600px as the breakpoint, doing same for consistency -@media (max-width: 600px) { - .list-actions { - text-align: left; - margin-bottom: 20px; - } -} - -.nvtooltip { - border-radius: 4px; - - td.value { - padding-right: 0px; - } - - p { - padding: 3px 0px; - } - - & > table > thead > tr > td { - font-weight: 700; - - &:first-child { - padding-top: 0; - } - } - - & > table > tbody > tr:last-child > td { - padding-bottom: 0; - } -} - -.nvd3 g.nv-groups path.nv-line { - stroke-width: 3px; -} - -.stdout-panel-body { - background-color: @default-list-header-bg; -} - -.job-stdout-panel { - margin: 0 15px; -} - -.panel-title { - font-weight: bold; -} - -.show_input_button { - width: 73px; -} - -.red-text { - color: @red; -} - -.factDetailsNote { - margin-bottom: 10px; -} - -.inputSpacer { - margin-bottom: 25px; -} - -.cleanupStretcher { - margin: 0 -15px; -} - -.factDaysToKeepCompacter { - margin-bottom: 15px; -} - -.factDetailsHeader { - font-weight: bold; -} - -@media (max-width: 991px) { - .inputCompactMobile { - margin-bottom: 15px; - } -} - -#login-modal-body { - padding-bottom: 5px; -} - -.modal { - transition: all 0.3s ease-out !important; -} - -.modal.fade .modal-dialog { - transform: translate(0, 0); - margin: 100px auto; -} - -.modal-backdrop, .modal-backdrop.fade.in { - opacity: .25; -} - -.form-control { - border-color: @b7grey; - background-color: @fcgrey; - color: @default-data-txt; - transition: border-color 0.3s; - box-shadow: none; - font-size: 14px; - font-family: 'Open Sans', sans-serif; -} - -.form-control + .select2 .select2-selection { - border-color: @b7grey !important; - background-color: @fcgrey !important; - color: @default-data-txt !important; - transition: border-color 0.3s !important; - box-shadow: none !important; -} - -.select2-container { - margin-left: 2px; - margin-top: 2px; -} - -.form-control + .select2-container--disabled .select2-selection { - background-color: @ebgrey !important; -} - -.form-control:active, .form-control:focus { - box-shadow: none; - border-color: @default-link; -} - -.form-control:active + .select2 .select2-selection, .form-control:focus + .select2 .select2-selection { - box-shadow: none !important; - border-color: @default-link !important; -} - -.form-control.ng-dirty.ng-invalid, .form-control.ng-dirty.ng-invalid:focus { - box-shadow: none; -} - -.form-control.ng-dirty.ng-invalid + .select2 .select2-selection, .form-control.ng-dirty.ng-invalid:focus + .select2 .select2-selection { - box-shadow: none !important; -} - -.error { - opacity: 1; - transition: opacity 0.2s; -} - -.error.ng-hide-add { - display: none; -} - -.error.ng-hide { - opacity: 0; -} - -/* Overwrite select2 base styles for single/multiple selects so that match up with other form elements. Also overwrite disabled styles. */ -.select2-container--disabled,.select2-container--disabled .select2-selection--single,.select2-container--disabled .select2-selection--multiple { - cursor: not-allowed; - opacity: 100; - background-color: @ebgrey; - border-radius: 5px; -} - -.select2-container--default .select2-selection--single { - background-color: @fcgrey; - border: 1px solid @d7grey; - border-radius: 4px; -} - -.select2-container--default .select2-selection--multiple { - background-color: @field-secondary-bg; - border-radius: 4px; - border: 1px solid @d7grey; - cursor: text; - max-height: 135px; - overflow-y: auto; -} - -body.is-modalOpen { - overflow: hidden; -} - -input[type=file]:focus, input[type=radio]:focus, input[type=checkbox]:focus { - outline: 0 !important; -} - -.btn-success.disabled, .btn-success[disabled], fieldset[disabled] .btn-success, .btn-success.disabled:hover, .btn-success[disabled]:hover, fieldset[disabled] .btn-success:hover, .btn-success.disabled:focus, .btn-success[disabled]:focus, fieldset[disabled] .btn-success:focus, .btn-success.disabled:active, .btn-success[disabled]:active, fieldset[disabled] .btn-success:active, .btn-success.disabled.active, .btn-success[disabled].active, fieldset[disabled] .btn-success.active { - background-color: @d7grey; - color: @default-bg; - border: 0; -} - -.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success { - border-color: @default-succ; -} - -a { - color: @default-link; -} - -a:hover { - color: @default-link-hov; -} - -.form-control:active, .form-control:focus { - border-color: @default-link; -} - -.nv-axislabel { - font-weight: bold !important; - fill: @db-graph-axis-label !important; - font-family: 'Open Sans' !important; -} - -.nv-axis text { - fill: @db-graph-axis-label !important; - font-family: 'Open Sans' !important; -} - -.select2-container--default .select2-selection--multiple .select2-selection__choice { - cursor: default; - float: left; - margin-right: 5px; - margin-top: 5px; - padding-left: 0px; - border-left-width: 0px; - border-bottom-width: 0px; - border-top-width: 0px; - padding-right: 10px; - border-right-width: 0px; - background-color: @default-link; - color: @default-bg; - border-radius: 5px; - line-height: 21px; - font-size: 13px; - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-all; - white-space: normal; -} - -.select2-container--default .select2-selection--multiple .select2-selection__choice__remove { - cursor: pointer; - display: inline-block; - font-weight: bold; - margin-right: 8px !important; - padding: 0 6px; - color: @default-bg !important; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - background-color: @default-link; -} - -.select2-selection { - & > .select2-selection__arrow { - border-left: none; - } -} - -.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover { - background-color: @default-err; -} - -.dropdown-menu>li>a { - padding: 3px 10px; -} - -#scheduled-jobs-tab .List-header { - display: none; -} - -.ui-widget { - font-family: 'Open Sans'; -} - -.WorkflowBadge{ - background-color: @b7grey; - border-radius: 10px; - color: @default-bg; - display: inline-block; - font-family: 'Open Sans'; - font-weight: bold; - font-style: normal; - font-size: x-small; - height: 14px; - margin-left: 5px; - padding-left: 2px; - width: 14px; -} - -button[disabled], -html input[disabled] { - cursor: not-allowed; -} - -.CodeMirror { - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; -} - -.CodeMirror--disabled .CodeMirror.cm-s-default, -.CodeMirror--disabled .CodeMirror-line { - background-color: @default-no-items-bord; -} - -.CodeMirror--disabled .CodeMirror-gutter.CodeMirror-lint-markers, -.CodeMirror--disabled .CodeMirror-gutter.CodeMirror-linenumbers { - background-color: @default-list-header-bg; - color: @b7grey; -} - -.CodeMirror--disabled .CodeMirror-lines { - cursor: default; -} - -.CodeMirror--disabled .CodeMirror-cursors { - display: none; -} - -.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active { - border-color: @field-border; -} - -.btn-default { - background: @default-bg; - border-color: @b7grey; - color: @default-interface-txt; -} - -.select2-container--disabled .select2-selection, -.select2-container--disabled .select2-arrow { - background-color: @ebgrey; -} - -.btn.disabled,.btn[disabled],fieldset[disabled] .bt { - opacity: 0.65; -} - -.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled { - opacity: 1; - background-color: @ebgrey; -} - -input[disabled].ui-spinner-input { - background-color: @ebgrey; -} - -.CodeMirror-scroll { - margin-bottom: 0; - padding-bottom: 0; - margin-right: 0; - overflow: auto !important; - overflow-y: auto !important; - border-radius: 5px; -} - -.CodeMirror-lines { - margin-bottom: 20px; -} - -.btn-default { - border-color: @b7grey; -} - -.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default { - background-color: @f2grey; - border-color: @b7grey; - color: @default-interface-txt; -} - -.ui-dialog .ui-dialog-content { - background: @default-bg; -} - -html { height: 100%; } - -body { - font-family: 'Open Sans', sans-serif; - font-weight: 400; - color: @default-data-txt; - background-color: @default-secondary-bg; -} - -.container-fluid { - padding-left: 20px; - padding-right: 20px; -} - -#content-container { - padding-bottom: 0px; -} - -.Panel { - background-color: @panel-bg; - border-radius: 5px; - padding: 20px; - border: 1px solid @panel-border; - margin-top: 20px; -} - -.Panel--noBottomPadding { - padding-bottom: 0px; -} - -.Panel-hidden { - display: none; -} - -.btn { - text-transform: uppercase; -} - -.ui-spinner-input { - margin-top: .3em; - margin-bottom: .3em; -} diff --git a/awx/ui/client/legacy/styles/bootstrap-datepicker.less b/awx/ui/client/legacy/styles/bootstrap-datepicker.less deleted file mode 100644 index 452d8ac8360a..000000000000 --- a/awx/ui/client/legacy/styles/bootstrap-datepicker.less +++ /dev/null @@ -1,753 +0,0 @@ -/*! - * Datepicker for Bootstrap v1.4.0 (https://github.com/eternicode/bootstrap-datepicker) - * - * Copyright 2012 Stefan Petre - * Improvements by Andrew Rowls - * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - */ -.datepicker { - padding: 4px; - border-radius: 4px; - direction: ltr; -} -.datepicker-inline { - width: 220px; -} -.datepicker.datepicker-rtl { - direction: rtl; -} -.datepicker.datepicker-rtl table tr td span { - float: right; -} -.datepicker-dropdown { - top: 0; - left: 0; -} -.datepicker-dropdown:before { - content: ''; - display: none; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-top: 0; - border-bottom-color: rgba(0, 0, 0, 0.2); - position: absolute; -} -.datepicker-dropdown:after { - content: ''; - display: none; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-top: 0; - position: absolute; -} -.datepicker-dropdown.datepicker-orient-left:before { - left: 6px; -} -.datepicker-dropdown.datepicker-orient-left:after { - left: 7px; -} -.datepicker-dropdown.datepicker-orient-right:before { - right: 6px; -} -.datepicker-dropdown.datepicker-orient-right:after { - right: 7px; -} -.datepicker-dropdown.datepicker-orient-top:before { - top: -7px; -} -.datepicker-dropdown.datepicker-orient-top:after { - top: -6px; -} -.datepicker-dropdown.datepicker-orient-bottom:before { - bottom: -7px; - border-bottom: 0; - border-top: 7px solid #999; -} -.datepicker-dropdown.datepicker-orient-bottom:after { - bottom: -6px; - border-bottom: 0; - border-top: 6px solid #fff; -} -.datepicker > div { - display: none; -} -.datepicker.days .datepicker-days, -.datepicker.months .datepicker-months, -.datepicker.years .datepicker-years { - display: block; -} -.datepicker table { - margin: 0; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.datepicker .datepicker-days .table-condensed tr td, -.datepicker .datepicker-days .table-condensed tr th { - text-align: center; - width: 30px; - height: 30px; - border-radius: 4px; - border: none; - padding: 0.5em 0.7em; -} -.table-striped .datepicker table tr td, -.table-striped .datepicker table tr th { - background-color: transparent; -} -.datepicker table tr td.day:hover, -.datepicker table tr td.day.focused { - background: #eeeeee; - cursor: pointer; -} -.datepicker table tr td.old, -.datepicker table tr td.new { - color: #999999; -} -.datepicker table tr td.disabled, -.datepicker table tr td.disabled:hover { - background: none; - color: #999999; - cursor: default; -} -.datepicker table tr td.today, -.datepicker table tr td.today:hover, -.datepicker table tr td.today.disabled, -.datepicker table tr td.today.disabled:hover { - color: #000000; - background-color: #ffdb99; - border-color: #ffb733; -} -.datepicker table tr td.today:hover, -.datepicker table tr td.today:hover:hover, -.datepicker table tr td.today.disabled:hover, -.datepicker table tr td.today.disabled:hover:hover, -.datepicker table tr td.today:focus, -.datepicker table tr td.today:hover:focus, -.datepicker table tr td.today.disabled:focus, -.datepicker table tr td.today.disabled:hover:focus, -.datepicker table tr td.today:active, -.datepicker table tr td.today:hover:active, -.datepicker table tr td.today.disabled:active, -.datepicker table tr td.today.disabled:hover:active, -.datepicker table tr td.today.active, -.datepicker table tr td.today:hover.active, -.datepicker table tr td.today.disabled.active, -.datepicker table tr td.today.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.today, -.open .dropdown-toggle.datepicker table tr td.today:hover, -.open .dropdown-toggle.datepicker table tr td.today.disabled, -.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { - color: #000000; - background-color: #ffcd70; - border-color: #f59e00; -} -.datepicker table tr td.today:active, -.datepicker table tr td.today:hover:active, -.datepicker table tr td.today.disabled:active, -.datepicker table tr td.today.disabled:hover:active, -.datepicker table tr td.today.active, -.datepicker table tr td.today:hover.active, -.datepicker table tr td.today.disabled.active, -.datepicker table tr td.today.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.today, -.open .dropdown-toggle.datepicker table tr td.today:hover, -.open .dropdown-toggle.datepicker table tr td.today.disabled, -.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { - background-image: none; -} -.datepicker table tr td.today.disabled, -.datepicker table tr td.today:hover.disabled, -.datepicker table tr td.today.disabled.disabled, -.datepicker table tr td.today.disabled:hover.disabled, -.datepicker table tr td.today[disabled], -.datepicker table tr td.today:hover[disabled], -.datepicker table tr td.today.disabled[disabled], -.datepicker table tr td.today.disabled:hover[disabled], -fieldset[disabled] .datepicker table tr td.today, -fieldset[disabled] .datepicker table tr td.today:hover, -fieldset[disabled] .datepicker table tr td.today.disabled, -fieldset[disabled] .datepicker table tr td.today.disabled:hover, -.datepicker table tr td.today.disabled:hover, -.datepicker table tr td.today:hover.disabled:hover, -.datepicker table tr td.today.disabled.disabled:hover, -.datepicker table tr td.today.disabled:hover.disabled:hover, -.datepicker table tr td.today[disabled]:hover, -.datepicker table tr td.today:hover[disabled]:hover, -.datepicker table tr td.today.disabled[disabled]:hover, -.datepicker table tr td.today.disabled:hover[disabled]:hover, -fieldset[disabled] .datepicker table tr td.today:hover, -fieldset[disabled] .datepicker table tr td.today:hover:hover, -fieldset[disabled] .datepicker table tr td.today.disabled:hover, -fieldset[disabled] .datepicker table tr td.today.disabled:hover:hover, -.datepicker table tr td.today.disabled:focus, -.datepicker table tr td.today:hover.disabled:focus, -.datepicker table tr td.today.disabled.disabled:focus, -.datepicker table tr td.today.disabled:hover.disabled:focus, -.datepicker table tr td.today[disabled]:focus, -.datepicker table tr td.today:hover[disabled]:focus, -.datepicker table tr td.today.disabled[disabled]:focus, -.datepicker table tr td.today.disabled:hover[disabled]:focus, -fieldset[disabled] .datepicker table tr td.today:focus, -fieldset[disabled] .datepicker table tr td.today:hover:focus, -fieldset[disabled] .datepicker table tr td.today.disabled:focus, -fieldset[disabled] .datepicker table tr td.today.disabled:hover:focus, -.datepicker table tr td.today.disabled:active, -.datepicker table tr td.today:hover.disabled:active, -.datepicker table tr td.today.disabled.disabled:active, -.datepicker table tr td.today.disabled:hover.disabled:active, -.datepicker table tr td.today[disabled]:active, -.datepicker table tr td.today:hover[disabled]:active, -.datepicker table tr td.today.disabled[disabled]:active, -.datepicker table tr td.today.disabled:hover[disabled]:active, -fieldset[disabled] .datepicker table tr td.today:active, -fieldset[disabled] .datepicker table tr td.today:hover:active, -fieldset[disabled] .datepicker table tr td.today.disabled:active, -fieldset[disabled] .datepicker table tr td.today.disabled:hover:active, -.datepicker table tr td.today.disabled.active, -.datepicker table tr td.today:hover.disabled.active, -.datepicker table tr td.today.disabled.disabled.active, -.datepicker table tr td.today.disabled:hover.disabled.active, -.datepicker table tr td.today[disabled].active, -.datepicker table tr td.today:hover[disabled].active, -.datepicker table tr td.today.disabled[disabled].active, -.datepicker table tr td.today.disabled:hover[disabled].active, -fieldset[disabled] .datepicker table tr td.today.active, -fieldset[disabled] .datepicker table tr td.today:hover.active, -fieldset[disabled] .datepicker table tr td.today.disabled.active, -fieldset[disabled] .datepicker table tr td.today.disabled:hover.active { - background-color: #ffdb99; - border-color: #ffb733; -} -.datepicker table tr td.today:hover:hover { - color: #000; -} -.datepicker table tr td.today.active:hover { - color: #fff; -} -.datepicker table tr td.range, -.datepicker table tr td.range:hover, -.datepicker table tr td.range.disabled, -.datepicker table tr td.range.disabled:hover { - background: #eeeeee; - border-radius: 0; -} -.datepicker table tr td.range.today, -.datepicker table tr td.range.today:hover, -.datepicker table tr td.range.today.disabled, -.datepicker table tr td.range.today.disabled:hover { - color: #000000; - background-color: #f7ca77; - border-color: #f1a417; - border-radius: 0; -} -.datepicker table tr td.range.today:hover, -.datepicker table tr td.range.today:hover:hover, -.datepicker table tr td.range.today.disabled:hover, -.datepicker table tr td.range.today.disabled:hover:hover, -.datepicker table tr td.range.today:focus, -.datepicker table tr td.range.today:hover:focus, -.datepicker table tr td.range.today.disabled:focus, -.datepicker table tr td.range.today.disabled:hover:focus, -.datepicker table tr td.range.today:active, -.datepicker table tr td.range.today:hover:active, -.datepicker table tr td.range.today.disabled:active, -.datepicker table tr td.range.today.disabled:hover:active, -.datepicker table tr td.range.today.active, -.datepicker table tr td.range.today:hover.active, -.datepicker table tr td.range.today.disabled.active, -.datepicker table tr td.range.today.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.range.today, -.open .dropdown-toggle.datepicker table tr td.range.today:hover, -.open .dropdown-toggle.datepicker table tr td.range.today.disabled, -.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { - color: #000000; - background-color: #f4bb51; - border-color: #bf800c; -} -.datepicker table tr td.range.today:active, -.datepicker table tr td.range.today:hover:active, -.datepicker table tr td.range.today.disabled:active, -.datepicker table tr td.range.today.disabled:hover:active, -.datepicker table tr td.range.today.active, -.datepicker table tr td.range.today:hover.active, -.datepicker table tr td.range.today.disabled.active, -.datepicker table tr td.range.today.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.range.today, -.open .dropdown-toggle.datepicker table tr td.range.today:hover, -.open .dropdown-toggle.datepicker table tr td.range.today.disabled, -.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { - background-image: none; -} -.datepicker table tr td.range.today.disabled, -.datepicker table tr td.range.today:hover.disabled, -.datepicker table tr td.range.today.disabled.disabled, -.datepicker table tr td.range.today.disabled:hover.disabled, -.datepicker table tr td.range.today[disabled], -.datepicker table tr td.range.today:hover[disabled], -.datepicker table tr td.range.today.disabled[disabled], -.datepicker table tr td.range.today.disabled:hover[disabled], -fieldset[disabled] .datepicker table tr td.range.today, -fieldset[disabled] .datepicker table tr td.range.today:hover, -fieldset[disabled] .datepicker table tr td.range.today.disabled, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, -.datepicker table tr td.range.today.disabled:hover, -.datepicker table tr td.range.today:hover.disabled:hover, -.datepicker table tr td.range.today.disabled.disabled:hover, -.datepicker table tr td.range.today.disabled:hover.disabled:hover, -.datepicker table tr td.range.today[disabled]:hover, -.datepicker table tr td.range.today:hover[disabled]:hover, -.datepicker table tr td.range.today.disabled[disabled]:hover, -.datepicker table tr td.range.today.disabled:hover[disabled]:hover, -fieldset[disabled] .datepicker table tr td.range.today:hover, -fieldset[disabled] .datepicker table tr td.range.today:hover:hover, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:hover, -.datepicker table tr td.range.today.disabled:focus, -.datepicker table tr td.range.today:hover.disabled:focus, -.datepicker table tr td.range.today.disabled.disabled:focus, -.datepicker table tr td.range.today.disabled:hover.disabled:focus, -.datepicker table tr td.range.today[disabled]:focus, -.datepicker table tr td.range.today:hover[disabled]:focus, -.datepicker table tr td.range.today.disabled[disabled]:focus, -.datepicker table tr td.range.today.disabled:hover[disabled]:focus, -fieldset[disabled] .datepicker table tr td.range.today:focus, -fieldset[disabled] .datepicker table tr td.range.today:hover:focus, -fieldset[disabled] .datepicker table tr td.range.today.disabled:focus, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:focus, -.datepicker table tr td.range.today.disabled:active, -.datepicker table tr td.range.today:hover.disabled:active, -.datepicker table tr td.range.today.disabled.disabled:active, -.datepicker table tr td.range.today.disabled:hover.disabled:active, -.datepicker table tr td.range.today[disabled]:active, -.datepicker table tr td.range.today:hover[disabled]:active, -.datepicker table tr td.range.today.disabled[disabled]:active, -.datepicker table tr td.range.today.disabled:hover[disabled]:active, -fieldset[disabled] .datepicker table tr td.range.today:active, -fieldset[disabled] .datepicker table tr td.range.today:hover:active, -fieldset[disabled] .datepicker table tr td.range.today.disabled:active, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:active, -.datepicker table tr td.range.today.disabled.active, -.datepicker table tr td.range.today:hover.disabled.active, -.datepicker table tr td.range.today.disabled.disabled.active, -.datepicker table tr td.range.today.disabled:hover.disabled.active, -.datepicker table tr td.range.today[disabled].active, -.datepicker table tr td.range.today:hover[disabled].active, -.datepicker table tr td.range.today.disabled[disabled].active, -.datepicker table tr td.range.today.disabled:hover[disabled].active, -fieldset[disabled] .datepicker table tr td.range.today.active, -fieldset[disabled] .datepicker table tr td.range.today:hover.active, -fieldset[disabled] .datepicker table tr td.range.today.disabled.active, -fieldset[disabled] .datepicker table tr td.range.today.disabled:hover.active { - background-color: #f7ca77; - border-color: #f1a417; -} -.datepicker table tr td.selected, -.datepicker table tr td.selected:hover, -.datepicker table tr td.selected.disabled, -.datepicker table tr td.selected.disabled:hover { - color: #ffffff; - background-color: #999999; - border-color: #555555; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datepicker table tr td.selected:hover, -.datepicker table tr td.selected:hover:hover, -.datepicker table tr td.selected.disabled:hover, -.datepicker table tr td.selected.disabled:hover:hover, -.datepicker table tr td.selected:focus, -.datepicker table tr td.selected:hover:focus, -.datepicker table tr td.selected.disabled:focus, -.datepicker table tr td.selected.disabled:hover:focus, -.datepicker table tr td.selected:active, -.datepicker table tr td.selected:hover:active, -.datepicker table tr td.selected.disabled:active, -.datepicker table tr td.selected.disabled:hover:active, -.datepicker table tr td.selected.active, -.datepicker table tr td.selected:hover.active, -.datepicker table tr td.selected.disabled.active, -.datepicker table tr td.selected.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.selected, -.open .dropdown-toggle.datepicker table tr td.selected:hover, -.open .dropdown-toggle.datepicker table tr td.selected.disabled, -.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { - color: #ffffff; - background-color: #858585; - border-color: #373737; -} -.datepicker table tr td.selected:active, -.datepicker table tr td.selected:hover:active, -.datepicker table tr td.selected.disabled:active, -.datepicker table tr td.selected.disabled:hover:active, -.datepicker table tr td.selected.active, -.datepicker table tr td.selected:hover.active, -.datepicker table tr td.selected.disabled.active, -.datepicker table tr td.selected.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.selected, -.open .dropdown-toggle.datepicker table tr td.selected:hover, -.open .dropdown-toggle.datepicker table tr td.selected.disabled, -.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { - background-image: none; -} -.datepicker table tr td.selected.disabled, -.datepicker table tr td.selected:hover.disabled, -.datepicker table tr td.selected.disabled.disabled, -.datepicker table tr td.selected.disabled:hover.disabled, -.datepicker table tr td.selected[disabled], -.datepicker table tr td.selected:hover[disabled], -.datepicker table tr td.selected.disabled[disabled], -.datepicker table tr td.selected.disabled:hover[disabled], -fieldset[disabled] .datepicker table tr td.selected, -fieldset[disabled] .datepicker table tr td.selected:hover, -fieldset[disabled] .datepicker table tr td.selected.disabled, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover, -.datepicker table tr td.selected.disabled:hover, -.datepicker table tr td.selected:hover.disabled:hover, -.datepicker table tr td.selected.disabled.disabled:hover, -.datepicker table tr td.selected.disabled:hover.disabled:hover, -.datepicker table tr td.selected[disabled]:hover, -.datepicker table tr td.selected:hover[disabled]:hover, -.datepicker table tr td.selected.disabled[disabled]:hover, -.datepicker table tr td.selected.disabled:hover[disabled]:hover, -fieldset[disabled] .datepicker table tr td.selected:hover, -fieldset[disabled] .datepicker table tr td.selected:hover:hover, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover:hover, -.datepicker table tr td.selected.disabled:focus, -.datepicker table tr td.selected:hover.disabled:focus, -.datepicker table tr td.selected.disabled.disabled:focus, -.datepicker table tr td.selected.disabled:hover.disabled:focus, -.datepicker table tr td.selected[disabled]:focus, -.datepicker table tr td.selected:hover[disabled]:focus, -.datepicker table tr td.selected.disabled[disabled]:focus, -.datepicker table tr td.selected.disabled:hover[disabled]:focus, -fieldset[disabled] .datepicker table tr td.selected:focus, -fieldset[disabled] .datepicker table tr td.selected:hover:focus, -fieldset[disabled] .datepicker table tr td.selected.disabled:focus, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover:focus, -.datepicker table tr td.selected.disabled:active, -.datepicker table tr td.selected:hover.disabled:active, -.datepicker table tr td.selected.disabled.disabled:active, -.datepicker table tr td.selected.disabled:hover.disabled:active, -.datepicker table tr td.selected[disabled]:active, -.datepicker table tr td.selected:hover[disabled]:active, -.datepicker table tr td.selected.disabled[disabled]:active, -.datepicker table tr td.selected.disabled:hover[disabled]:active, -fieldset[disabled] .datepicker table tr td.selected:active, -fieldset[disabled] .datepicker table tr td.selected:hover:active, -fieldset[disabled] .datepicker table tr td.selected.disabled:active, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover:active, -.datepicker table tr td.selected.disabled.active, -.datepicker table tr td.selected:hover.disabled.active, -.datepicker table tr td.selected.disabled.disabled.active, -.datepicker table tr td.selected.disabled:hover.disabled.active, -.datepicker table tr td.selected[disabled].active, -.datepicker table tr td.selected:hover[disabled].active, -.datepicker table tr td.selected.disabled[disabled].active, -.datepicker table tr td.selected.disabled:hover[disabled].active, -fieldset[disabled] .datepicker table tr td.selected.active, -fieldset[disabled] .datepicker table tr td.selected:hover.active, -fieldset[disabled] .datepicker table tr td.selected.disabled.active, -fieldset[disabled] .datepicker table tr td.selected.disabled:hover.active { - background-color: #999999; - border-color: #555555; -} -.datepicker table tr td.active, -.datepicker table tr td.active:hover, -.datepicker table tr td.active.disabled, -.datepicker table tr td.active.disabled:hover { - color: #ffffff; - background-color: #428bca; - border-color: #357ebd; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datepicker table tr td.active:hover, -.datepicker table tr td.active:hover:hover, -.datepicker table tr td.active.disabled:hover, -.datepicker table tr td.active.disabled:hover:hover, -.datepicker table tr td.active:focus, -.datepicker table tr td.active:hover:focus, -.datepicker table tr td.active.disabled:focus, -.datepicker table tr td.active.disabled:hover:focus, -.datepicker table tr td.active:active, -.datepicker table tr td.active:hover:active, -.datepicker table tr td.active.disabled:active, -.datepicker table tr td.active.disabled:hover:active, -.datepicker table tr td.active.active, -.datepicker table tr td.active:hover.active, -.datepicker table tr td.active.disabled.active, -.datepicker table tr td.active.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.active, -.open .dropdown-toggle.datepicker table tr td.active:hover, -.open .dropdown-toggle.datepicker table tr td.active.disabled, -.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { - color: #ffffff; - background-color: #3276b1; - border-color: #285e8e; -} -.datepicker table tr td.active:active, -.datepicker table tr td.active:hover:active, -.datepicker table tr td.active.disabled:active, -.datepicker table tr td.active.disabled:hover:active, -.datepicker table tr td.active.active, -.datepicker table tr td.active:hover.active, -.datepicker table tr td.active.disabled.active, -.datepicker table tr td.active.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td.active, -.open .dropdown-toggle.datepicker table tr td.active:hover, -.open .dropdown-toggle.datepicker table tr td.active.disabled, -.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { - background-image: none; -} -.datepicker table tr td.active.disabled, -.datepicker table tr td.active:hover.disabled, -.datepicker table tr td.active.disabled.disabled, -.datepicker table tr td.active.disabled:hover.disabled, -.datepicker table tr td.active[disabled], -.datepicker table tr td.active:hover[disabled], -.datepicker table tr td.active.disabled[disabled], -.datepicker table tr td.active.disabled:hover[disabled], -fieldset[disabled] .datepicker table tr td.active, -fieldset[disabled] .datepicker table tr td.active:hover, -fieldset[disabled] .datepicker table tr td.active.disabled, -fieldset[disabled] .datepicker table tr td.active.disabled:hover, -.datepicker table tr td.active.disabled:hover, -.datepicker table tr td.active:hover.disabled:hover, -.datepicker table tr td.active.disabled.disabled:hover, -.datepicker table tr td.active.disabled:hover.disabled:hover, -.datepicker table tr td.active[disabled]:hover, -.datepicker table tr td.active:hover[disabled]:hover, -.datepicker table tr td.active.disabled[disabled]:hover, -.datepicker table tr td.active.disabled:hover[disabled]:hover, -fieldset[disabled] .datepicker table tr td.active:hover, -fieldset[disabled] .datepicker table tr td.active:hover:hover, -fieldset[disabled] .datepicker table tr td.active.disabled:hover, -fieldset[disabled] .datepicker table tr td.active.disabled:hover:hover, -.datepicker table tr td.active.disabled:focus, -.datepicker table tr td.active:hover.disabled:focus, -.datepicker table tr td.active.disabled.disabled:focus, -.datepicker table tr td.active.disabled:hover.disabled:focus, -.datepicker table tr td.active[disabled]:focus, -.datepicker table tr td.active:hover[disabled]:focus, -.datepicker table tr td.active.disabled[disabled]:focus, -.datepicker table tr td.active.disabled:hover[disabled]:focus, -fieldset[disabled] .datepicker table tr td.active:focus, -fieldset[disabled] .datepicker table tr td.active:hover:focus, -fieldset[disabled] .datepicker table tr td.active.disabled:focus, -fieldset[disabled] .datepicker table tr td.active.disabled:hover:focus, -.datepicker table tr td.active.disabled:active, -.datepicker table tr td.active:hover.disabled:active, -.datepicker table tr td.active.disabled.disabled:active, -.datepicker table tr td.active.disabled:hover.disabled:active, -.datepicker table tr td.active[disabled]:active, -.datepicker table tr td.active:hover[disabled]:active, -.datepicker table tr td.active.disabled[disabled]:active, -.datepicker table tr td.active.disabled:hover[disabled]:active, -fieldset[disabled] .datepicker table tr td.active:active, -fieldset[disabled] .datepicker table tr td.active:hover:active, -fieldset[disabled] .datepicker table tr td.active.disabled:active, -fieldset[disabled] .datepicker table tr td.active.disabled:hover:active, -.datepicker table tr td.active.disabled.active, -.datepicker table tr td.active:hover.disabled.active, -.datepicker table tr td.active.disabled.disabled.active, -.datepicker table tr td.active.disabled:hover.disabled.active, -.datepicker table tr td.active[disabled].active, -.datepicker table tr td.active:hover[disabled].active, -.datepicker table tr td.active.disabled[disabled].active, -.datepicker table tr td.active.disabled:hover[disabled].active, -fieldset[disabled] .datepicker table tr td.active.active, -fieldset[disabled] .datepicker table tr td.active:hover.active, -fieldset[disabled] .datepicker table tr td.active.disabled.active, -fieldset[disabled] .datepicker table tr td.active.disabled:hover.active { - background-color: #428bca; - border-color: #357ebd; -} -.datepicker table tr td span { - display: block; - width: 23%; - height: 54px; - line-height: 54px; - float: left; - margin: 1%; - cursor: pointer; - border-radius: 4px; -} -.datepicker table tr td span:hover { - background: #eeeeee; -} -.datepicker table tr td span.disabled, -.datepicker table tr td span.disabled:hover { - background: none; - color: #999999; - cursor: default; -} -.datepicker table tr td span.active, -.datepicker table tr td span.active:hover, -.datepicker table tr td span.active.disabled, -.datepicker table tr td span.active.disabled:hover { - color: #ffffff; - background-color: #428bca; - border-color: #357ebd; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datepicker table tr td span.active:hover, -.datepicker table tr td span.active:hover:hover, -.datepicker table tr td span.active.disabled:hover, -.datepicker table tr td span.active.disabled:hover:hover, -.datepicker table tr td span.active:focus, -.datepicker table tr td span.active:hover:focus, -.datepicker table tr td span.active.disabled:focus, -.datepicker table tr td span.active.disabled:hover:focus, -.datepicker table tr td span.active:active, -.datepicker table tr td span.active:hover:active, -.datepicker table tr td span.active.disabled:active, -.datepicker table tr td span.active.disabled:hover:active, -.datepicker table tr td span.active.active, -.datepicker table tr td span.active:hover.active, -.datepicker table tr td span.active.disabled.active, -.datepicker table tr td span.active.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td span.active, -.open .dropdown-toggle.datepicker table tr td span.active:hover, -.open .dropdown-toggle.datepicker table tr td span.active.disabled, -.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { - color: #ffffff; - background-color: #3276b1; - border-color: #285e8e; -} -.datepicker table tr td span.active:active, -.datepicker table tr td span.active:hover:active, -.datepicker table tr td span.active.disabled:active, -.datepicker table tr td span.active.disabled:hover:active, -.datepicker table tr td span.active.active, -.datepicker table tr td span.active:hover.active, -.datepicker table tr td span.active.disabled.active, -.datepicker table tr td span.active.disabled:hover.active, -.open .dropdown-toggle.datepicker table tr td span.active, -.open .dropdown-toggle.datepicker table tr td span.active:hover, -.open .dropdown-toggle.datepicker table tr td span.active.disabled, -.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { - background-image: none; -} -.datepicker table tr td span.active.disabled, -.datepicker table tr td span.active:hover.disabled, -.datepicker table tr td span.active.disabled.disabled, -.datepicker table tr td span.active.disabled:hover.disabled, -.datepicker table tr td span.active[disabled], -.datepicker table tr td span.active:hover[disabled], -.datepicker table tr td span.active.disabled[disabled], -.datepicker table tr td span.active.disabled:hover[disabled], -fieldset[disabled] .datepicker table tr td span.active, -fieldset[disabled] .datepicker table tr td span.active:hover, -fieldset[disabled] .datepicker table tr td span.active.disabled, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover, -.datepicker table tr td span.active.disabled:hover, -.datepicker table tr td span.active:hover.disabled:hover, -.datepicker table tr td span.active.disabled.disabled:hover, -.datepicker table tr td span.active.disabled:hover.disabled:hover, -.datepicker table tr td span.active[disabled]:hover, -.datepicker table tr td span.active:hover[disabled]:hover, -.datepicker table tr td span.active.disabled[disabled]:hover, -.datepicker table tr td span.active.disabled:hover[disabled]:hover, -fieldset[disabled] .datepicker table tr td span.active:hover, -fieldset[disabled] .datepicker table tr td span.active:hover:hover, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover, -.datepicker table tr td span.active.disabled:focus, -.datepicker table tr td span.active:hover.disabled:focus, -.datepicker table tr td span.active.disabled.disabled:focus, -.datepicker table tr td span.active.disabled:hover.disabled:focus, -.datepicker table tr td span.active[disabled]:focus, -.datepicker table tr td span.active:hover[disabled]:focus, -.datepicker table tr td span.active.disabled[disabled]:focus, -.datepicker table tr td span.active.disabled:hover[disabled]:focus, -fieldset[disabled] .datepicker table tr td span.active:focus, -fieldset[disabled] .datepicker table tr td span.active:hover:focus, -fieldset[disabled] .datepicker table tr td span.active.disabled:focus, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus, -.datepicker table tr td span.active.disabled:active, -.datepicker table tr td span.active:hover.disabled:active, -.datepicker table tr td span.active.disabled.disabled:active, -.datepicker table tr td span.active.disabled:hover.disabled:active, -.datepicker table tr td span.active[disabled]:active, -.datepicker table tr td span.active:hover[disabled]:active, -.datepicker table tr td span.active.disabled[disabled]:active, -.datepicker table tr td span.active.disabled:hover[disabled]:active, -fieldset[disabled] .datepicker table tr td span.active:active, -fieldset[disabled] .datepicker table tr td span.active:hover:active, -fieldset[disabled] .datepicker table tr td span.active.disabled:active, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover:active, -.datepicker table tr td span.active.disabled.active, -.datepicker table tr td span.active:hover.disabled.active, -.datepicker table tr td span.active.disabled.disabled.active, -.datepicker table tr td span.active.disabled:hover.disabled.active, -.datepicker table tr td span.active[disabled].active, -.datepicker table tr td span.active:hover[disabled].active, -.datepicker table tr td span.active.disabled[disabled].active, -.datepicker table tr td span.active.disabled:hover[disabled].active, -fieldset[disabled] .datepicker table tr td span.active.active, -fieldset[disabled] .datepicker table tr td span.active:hover.active, -fieldset[disabled] .datepicker table tr td span.active.disabled.active, -fieldset[disabled] .datepicker table tr td span.active.disabled:hover.active { - background-color: #428bca; - border-color: #357ebd; -} -.datepicker table tr td span.old, -.datepicker table tr td span.new { - color: #999999; -} -.datepicker .datepicker-switch { - width: 145px; -} -.datepicker thead tr:first-child th, -.datepicker tfoot tr th { - cursor: pointer; -} -.datepicker thead tr:first-child th:hover, -.datepicker tfoot tr th:hover { - background: #eeeeee; -} -.datepicker .cw { - font-size: 10px; - width: 12px; - padding: 0 2px 0 5px; - vertical-align: middle; -} -.datepicker thead tr:first-child .cw { - cursor: default; - background-color: transparent; -} -.input-group.date .input-group-addon { - cursor: pointer; -} -.input-daterange { - width: 100%; -} -.input-daterange input { - text-align: center; -} -.input-daterange input:first-child { - border-radius: 3px 0 0 3px; -} -.input-daterange input:last-child { - border-radius: 0 3px 3px 0; -} -.input-daterange .input-group-addon { - width: auto; - min-width: 16px; - padding: 4px 5px; - font-weight: normal; - line-height: 1.42857143; - text-align: center; - text-shadow: 0 1px 0 #fff; - vertical-align: middle; - background-color: #eeeeee; - border: solid #cccccc; - border-width: 1px 0; - margin-left: -5px; - margin-right: -5px; -} diff --git a/awx/ui/client/legacy/styles/codemirror.less b/awx/ui/client/legacy/styles/codemirror.less deleted file mode 100644 index 68317c844d79..000000000000 --- a/awx/ui/client/legacy/styles/codemirror.less +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * Overrides to angular-codemirror - * - * - */ - -.CodeMirror { - height: auto; - overflow-x: auto; - overflow-y: hidden; - border: 1px solid @b7grey; -} - -.CodeMirror, -.CodeMirror-activeline-background { - background-color: @default-secondary-bg; -} - -/* Make sure code editor dialog is always at top of stack */ -[aria-describedby=af-code-editor-modal].ui-front { - z-index: 2050; -} - -.CodeMirror-lint-tooltip { - z-index: 2060; -} - -.CodeMirror-gutters { - border-color: @d7grey; - background-color: @default-no-items-bord; -} - -.CodeMirror-lineNumber { - color: @default-icon; -} - -// Disabled -textarea[disabled="disabled"] + div[id*="-container"]{ - .CodeMirror { - cursor: not-allowed; - } - - .CodeMirror.cm-s-default, - .CodeMirror-line { - background-color: @ebgrey; - } - - .CodeMirror-gutters { - border-color: @b7grey; - } - - .CodeMirror-gutter.CodeMirror-lint-markers, - .CodeMirror-gutter.CodeMirror-linenumbers { - background-color: @default-bg; - color: @default-interface-txt; - } - - .CodeMirror-lines { - cursor: default; - } - - .CodeMirror-cursors { - display: none; - } -} diff --git a/awx/ui/client/legacy/styles/dashboard.less b/awx/ui/client/legacy/styles/dashboard.less deleted file mode 100644 index 2b1ee7c00e8c..000000000000 --- a/awx/ui/client/legacy/styles/dashboard.less +++ /dev/null @@ -1,114 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * dashboard.css - * - * custom styles for the new dashboard - * - */ - -.graph-wrapper { - width: 100%; -} - -.graph { - background-color: white; - // @include transition(width 2s ease-in-out, height 2s ease-in-out); - position: relative; - text-align: center; - width: 100%; - height: 100%; - margin: 0 auto; -} - -.job-status-graph, .host-count-graph{ - font: 10px sans-serif; -} - -.axis path, -.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - -.line { - fill: none; - stroke: steelblue; - stroke-width: 1.5px; -} - - -.dashboard-jobs-list-container { - border: 1px solid @grey; - border-radius: 4px; - padding: 5px; -} - -/* -.graph-container{ - border: 1px solid @grey; - border-radius: 4px; - padding: 5px; - margin-bottom: 15px; -} -due to the login screen showing on top of the dashboard, we're hiding the borders until after the user logs in*/ - -.count-container{ - border: 1px solid @grey; - border-radius: 4px; - margin-left: 0px; - margin-right: 0px; - margin-bottom: 15px; -} - -#replacementImg{ - align:center; - width: 100px; - height: 100px; - -} - -#dashboard-tab-content{ - padding-top: 5px; -} - -#dashboard-tab-content .search-row #active-jobs-search-container{ - height: 35px; -} - - -#dashboard-tab-content table{ - margin-bottom: 10px; -} - -.dashboard-jobs-list-container { - #jobs_table, - #schedules_table { - table-layout:fixed; - } - #jobs_table .name-column, - #schedules_table .name-column { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -#dash-jobs-list{ - padding-bottom: 15px; -} - - @media (min-width: 769px) { - .left-side { - padding-right: 7px; - } - - .right-side { - padding-left: 7px; - } -} - -.m, .n{ - cursor:pointer; -} diff --git a/awx/ui/client/legacy/styles/event-viewer.less b/awx/ui/client/legacy/styles/event-viewer.less deleted file mode 100644 index ac575b4c0352..000000000000 --- a/awx/ui/client/legacy/styles/event-viewer.less +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * event-viewer.less - * - * custom styles for EventViewer.js helper - * - */ - -#eventviewer-modal-dialog { - - textarea { - overflow: scroll; - } - pre { - overflow: scroll; - word-wrap: normal; - word-break: normal; - white-space: pre-wrap; - } -} - -table.eventviewer-status { - margin-top: 20px; - - .key { - width: 20%; - font-weight: bold; - } - .value i { - font-size: 12px; - } -} - -.nested-table { - border: none; - padding: 0; - table { - border-top: none; - border-bottom: none; - width: auto; - td { - vertical-align: top; - padding: 0 3px 3px 3px; - } - tr { - border-top: none; - border-bottom: 1px solid #ddd; - } - /*tr td:first-of-type { - width: auto; - }*/ - tr:last-of-type { - border-bottom: none; - } - .key { - font-weight: 400; - } - } -} \ No newline at end of file diff --git a/awx/ui/client/legacy/styles/fonts.less b/awx/ui/client/legacy/styles/fonts.less deleted file mode 100644 index e75c35f69973..000000000000 --- a/awx/ui/client/legacy/styles/fonts.less +++ /dev/null @@ -1,19 +0,0 @@ -.include-font(@family-name; @filename; @weight: normal; @style: normal) { - @font-face { - font-family: @family-name; - src: url("/static/assets/@{filename}.woff2") format('woff2'), - url("/static/assets/@{filename}.woff") format('woff'); - font-weight: @weight; - font-style: @style; - } -} - -.include-font('merriweather'; 'merriweather_light-webfont'; 200); -.include-font('merriweather'; 'merriweather-regular-webfont'); -.include-font('merriweather'; 'merriweather-bold-webfont'; bold); -.include-font('merriweather'; 'merriweather_ultrabold-webfont'; 800); -.include-font('merriweather'; 'merriweather-lightitalic-webfont'; 200; italic); -.include-font('merriweather'; 'merriweather-bolditalic-webfont'; bold; italic); -.include-font('merriweather'; 'merriweather-heavyitalic-webfont'; 800; italic); -.include-font('merriweather'; 'merriweather-italic-webfont'; normal; italic); - diff --git a/awx/ui/client/legacy/styles/forms.less b/awx/ui/client/legacy/styles/forms.less deleted file mode 100644 index e18c92cfb936..000000000000 --- a/awx/ui/client/legacy/styles/forms.less +++ /dev/null @@ -1,795 +0,0 @@ -/********************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * Forms.less - * - * custom styles for generated forms - * - */ - -.noselect { - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Chrome/Safari/Opera */ - -khtml-user-select: none; /* Konqueror */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ - user-select: none; /* Non-prefixed version, currently - not supported by any browser */ -} - -.Form { - display:flex; - flex-wrap:wrap; - flex-direction: row; -} - -.Form-header--fields { - flex: 1 1 auto; -} - -.Form-header-field { - margin-left: 10px; - flex: 1 1 auto; -} - -.Form-header { - display: flex; -} - -.Form-title { - flex: 0 1 auto; - color: @list-header-txt; - font-size: 14px; - font-weight: bold; - word-break: break-all; - max-width: 90%; - word-wrap: break-word; - margin-bottom: 20px; -} - -.Form-title--uppercase { - text-transform: uppercase; -} - -.Form-secondaryTitle { - color: @default-icon; - padding-bottom: 20px; - min-height: 40px; -} - -.Form-title--is_smartinventory, -.Form-title--is_superuser, -.Form-title--is_system_auditor, -.Form-title--is_ldap_user, -.Form-title--is_external_account, -.Form-title--roleType { - background-color: @default-list-header-bg; - border-radius: 5px; - color: @default-interface-txt; - font-size: 10px; - font-weight: 100; - height:15px; - margin-left: 10px; - margin-top: 2.25px; - padding: 0 10px; - text-transform: uppercase; -} - -.Form-exitHolder { - justify-content: flex-end; - display:flex; -} - -.Form-exit { - cursor:pointer; - padding:0px; - border: none; - height:20px; - font-size: 20px; - background-color:@default-bg; - color:@d7grey; - transition: color 0.2s; - line-height:1; -} - -.Form-exit:hover { - color:@default-icon; -} - -.Form-tabHolder { - display: flex; - min-height: 30px; - flex-wrap:wrap; -} - -.Form-tabHolder--licenseSelected { - margin-bottom: -20px; -} - -.Form-tabs { - flex: 1 0 auto; - display: flex; -} - -.Form-tab { - color: @btn-txt; - background-color: @btn-bg; - font-size: 12px; - border: 1px solid @b7grey; - height: 30px; - border-radius: 5px; - margin-right: 20px; - margin-bottom: 20px; - padding-left: 10px; - padding-right: 10px; - padding-bottom: 5px; - padding-top: 5px; - transition: background-color 0.2s; - text-transform: uppercase; - text-align: center; - white-space: nowrap; - .noselect; -} - -.Form-tab--notitle { - margin-bottom: 0px; -} - -.Form-tab:hover { - color: @btn-txt; - background-color: @btn-bg-hov; - cursor: pointer; -} - -.Form-tab:active { - color: @btn-txt-sel; - background-color: @btn-bg-sel; - cursor: pointer; -} - -.Form-tab:focus { - color: @btn-txt-sel; -} - -.Form-tab.is-selected { - color: @btn-txt-sel; - background-color: @default-icon; - border-color: @default-icon; -} - -.Form-tab--disabled { - opacity: 0.65; -} - -.Form-tab--disabled:hover { - color: @btn-txt; - background-color: @btn-bg; - cursor:not-allowed!important; -} - -.Form-tabSection { - display: none; - width: 0%; -} - -.Form-tabSection.is-selected { - width: 100%; - display: block; -} - -.Form-tabActions { - display: flex; -} - -.Form-formGroup { - flex: 1 0 auto; - margin-bottom: 20px; - width: 33%; - max-width: 33%; - padding-right: 30px; -} - -.Form-formGroup--fullWidth { - max-width: none !important; - width: 100% !important; - padding-right: 0px !important; -} - -.Form-formGroup--checkbox{ - display: flex; - margin-top: 10px; -} - -.Form-formGroup { - input.form-control { - background-color: @fcgrey; - border-color: @b7grey; - border-radius: 5px; - height: auto; - min-height: 30px; - padding: 0 10px; - } - - input.form-control[disabled], input.form-control[readonly], fieldset[disabled] input.form-control { - border-color: @b7grey; - background-color: @ebgrey; - } -} - -.Form-checkbox--stacked { - label { - display: block; - } -} - -.Form-checkbox--subCheckbox { - font-size: 10px; - color: @default-stdout-txt; - text-transform: uppercase; - margin-top: 2px; - - input { - margin-top: 2px; - } -} - -.Form-textUneditable { - .Form-textInput { - border: none; - padding: 0; - } -} - -.Form-subForm { - width: 100%; - margin-bottom: 15px; - display: flex; - flex-wrap: wrap; - flex-direction: row; - justify-content: flex-start; - position: relative; -} - -.Form-subForm:before { - content: ''; - left: -20px; - position: absolute; - width: 5px; - background-color: @b7grey; - height: 100%; -} - -.Form-subForm--title { - font-weight: bold; - text-transform: uppercase; - color: @default-interface-txt; - font-size: small; - width: 100%; - float: left; - margin-bottom: 10px; -} - -.Form-textAreaLabel { - width:100%; - order: 1; -} - -.Form-formGroup.Form-textAreaLabel { - max-width: 100%; -} - -.Form-textArea { - border-radius: 5px; - color: @field-input-text; - background-color: @field-secondary-bg; - width:100%!important; -} - -.Form-textInput { - height: 30px; - background-color: @field-secondary-bg; - border-radius: 5px; - border:1px solid @field-border; - color: @field-input-text; -} - -.Form-textInput:active { - border:1px solid @field-border-sel; -} - -.Form-monospace { - font-family: Menlo,Monaco,Consolas,"Courier New",monospace!important; -} - -.Form-alertblock { - margin: 0; - font-size: 12px; - width: 100%; - padding: 20px; - margin-bottom: 15px; - border-radius: 4px; - border: 1px solid @login-notice-border; - background-color: @login-notice-bg; - color: @login-notice-text; -} - -.Button-primary--hollow { - border: 1px solid @default-link; - color: @default-link; - background: @default-bg; -} -.Button-primary--hollow:hover { - color: @default-link-hov; - border: 1px solid @default-link-hov; -} - -.ui-spinner { - height: 30px; - background-color: @fcgrey !important; - border-radius: 5px; - border:1px solid @field-border !important; - color: @field-input-text; - width:100% -} - -.ui-spinner-input { - color: @field-input-text; - background-color: @fcgrey; -} - -.ui-spinner-input:focus { - outline: none; -} - -.ui-spinner-button { - border-left:1px solid @field-border!important; - background-color: @field-button-bg !important; -} - -.ui-spinner-button:hover { - background-color:@field-button-hov !important; - cursor: pointer!important; -} - -.Form-inputButton { - border-color: @d7grey; - color: @default-data-txt; -} - -.Form-numberInputButton { - color: @default-icon!important; - font-size: 14px; - display: block; -} - -.Form-dropDown { - min-height: 30px !important; - border-radius: 5px !important; - border:1px solid @field-border!important; - color: @field-input-text!important; -} - -.select2-selection__arrow { - border-left:1px solid @field-border; - border-bottom-right-radius: 5px; - border-top-right-radius: 5px; - width: 30px!important; - height: 28px!important; -} - -.select2-container--disabled .select2-selection__arrow { - background-color: @ebgrey !important; -} - -.select2-results__option { - color: @field-label !important; -} - -.select2-container--default .select2-results__option--highlighted[aria-selected] { - background-color: @field-button-hov !important; -} - -.select2-container--default .select2-results__option[aria-selected=true] { - background-color: @default-white-button-bord !important; -} - -.select2-container--default .select2-selection--single .select2-selection__arrow b { - border-color: @field-dropdown-icon transparent transparent transparent !important; -} - -.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b { - border-color: transparent transparent @field-dropdown-icon transparent!important; -} - -.select2-container--default.select2-container--open.select2-container--below .select2-selection--single { - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} - -.select2-dropdown { - border:1px solid @field-border; - z-index: 1030; -} - -.select2-container--open .select2-dropdown--below { - margin-top: -1px; - border-top: 1px solid @field-border; -} - -.Form-dropDown:focus { - outline: none!important; -} - -.Form-dropDown--scmType { - width: 100%; -} - -.Form-passwordButton { - height: 30px; - color: @default-interface-txt; - text-transform: uppercase; - line-height: 1; - padding-left: 7px; - padding-right: 7px; - background-color: @default-bg; - border:1px solid @b7grey; -} - -.Form-passwordButton:hover { - cursor: pointer; - background-color: @f2grey; - border: 1px solid @b7grey; - color: @field-lookup-btn-icon; -} - -.Form-passwordButton:focus { - border: 1px solid @field-border; - background-color: @field-lookup-btn-hov-bg; -} - -.Form-passwordButton:active { - border: 1px solid @field-border; - background-color: @field-lookup-btn-hov-bg; -} - -.Form-lookupButton { - height: auto; - width: 30px; - color: @field-lookup-btn-icon!important; - font-size: 16px; - background-color: @field-lookup-btn-bg; - display: flex; - align-items: center; - justify-content: center; - border:1px solid @field-border; -} - -.Form-lookupButton:hover { - cursor: pointer; - background-color: @field-lookup-btn-hov-bg; - color: @default-interface-txt; -} - -.Form-lookupButton:active, -.Form-lookupButton:focus { - border: 1px solid @field-border; -} - -.CodeMirror { - border-radius: 5px; - font-style: normal; - color: @field-input-text; -} - -.CodeMirror-gutters { - background-color:@code-mirror-gutter !important; -} - -input[type='radio'] { - -webkit-appearance:none; - width:14px; - height:14px; - border:1px solid @radio-bg; - border-radius:50%; - outline:none; - vertical-align: sub; -} - -input[type='radio']:focus { - outline:none; -} - -input[type='radio']:hover { - box-shadow:0 0 5px 0px @btn-bg-hov inset; -} - -input[type='radio']:before { - content:''; - display:block; - width:65%; - height:60%; - margin: 20% auto; - border-radius:50%; -} - -input[type='radio']:checked:before { - background:@radio-bg; - outline:none; -} - -.Form-inputLabelContainer { - width: 100%; - display: block !important; -} - -.Form-inputLabelContainer[for=variables], -.Form-inputLabelContainer--codeMirror { - width: auto; - display: inline-block !important; -} - -.Form-mixedInputGroup { - display: flex; - width: 100%; - - .form-control { - padding: 0 12px !important; - } - - .input-group-btn { - display: flex; - width: auto; - } -} - -.FormToggle {} -.FormToggle-container { - margin: 0 0 0 10px; - display: initial; - padding-bottom: 5px; - - label { - &:first-child { - border-right: none; - } - &:last-child { - border-left: none; - } - } - - input { - visibility: hidden; - position: absolute; - } - - .btn.btn-xs { - padding: 0px 10px; - } -} - -.Form-inputLabelContainer { - width: 100%; - display: block !important; -} - -.Form-inputLabelContainer[for=variables] { - width: 100%; - display: inline-block !important; -} - -.Form-inputLabel { - text-transform: uppercase; - color: @default-interface-txt; - font-weight: normal; - font-size: small; - padding-right:5px; - width: 100%; - .noselect; -} - -.Form-labelAction { - text-transform: uppercase; - font-weight: normal; - font-size: 0.8em; - padding-left:5px; - float: right; - margin-top: 3px; - .noselect; -} - -.Form-buttons { - height: 30px; - display: flex; - justify-content: flex-end; - - button:last-of-type { - margin-left: 20px; - } -} - -.Form-button { - margin-left: 4px; -} - -.Form-buttonDefault { - background-color: @default-bg; - color: @default-interface-txt; - border-color: @default-border; -} - -.Form-saveButton, .Form-launchButton { - background-color: @submit-button-bg; - color: @submit-button-text; - text-transform: uppercase; - transition: background-color 0.2s; - padding-left:15px; - padding-right: 15px; -} - -.Form-saveButton:disabled, .Form-launchButton:disabled { - background-color: @submit-button-bg-dis; -} - -.Form-saveButton--disabled { - background-color: @submit-button-bg-dis; - cursor: not-allowed; -} - -.Form-saveButton:hover, .Form-launchButton:hover { - background-color: @submit-button-bg-hov; - color: @submit-button-text; -} - -.Form-saveButton--disabled:hover { - background-color: @submit-button-bg-dis; -} - -.Form-cancelButton { - background-color: @default-bg; - color: @btn-txt; - text-transform: uppercase; - border-radius: 5px; - border: 1px solid @field-border; - transition: background-color 0.2s; - padding-left:15px; - padding-right: 15px; - margin-left: 20px; -} - -.Form-cancelButton:hover { - background-color: @btn-bg-hov; - color: @btn-txt; -} - -.Form-primaryButton { - background-color: @default-link; - color: @default-bg; - text-transform: uppercase; - padding-left:15px; - padding-right: 15px; - margin-right: 20px; - min-height: 30px; - margin-bottom: 20px; -} - -.Form-primaryButton:hover { - background-color: @default-link-hov; - color: @default-bg; -} - -.Form-primaryButton.Form-tab--disabled:hover { - background-color: @default-link; -} - -.Form-primaryButton--noMargin { - margin-right: 0px; -} - -.Form-formGroup--singleColumn { - width: 100% !important; - padding-right: 0px; - max-width: 100% !important; -} - -.Form-checkbox { - float: right; -} - -.Form-subCheckbox { - margin-top: 5px; - font-size: small; - color: @default-interface-txt; - .noselect; -} - -.Form-textInput--variableHeight { - height: inherit; - min-height: 30px; - max-height: 120px; - overflow-y: auto; -} - -.Form-variableHeightButtonGroup { - display: flex; - height: auto; - width: 30px; -} - -.Form-requiredAsterisk { - color: @red; -} - -@media only screen and (max-width: 650px) { - .Form-formGroup { - flex: 1 0 auto; - margin-bottom: 25px; - max-width: 100%; - width: 100%; - padding-right: 50px; - } -} - -@media (min-width: 651px) and (max-width: 900px) { - .Form-formGroup { - flex: 1 0 auto; - margin-bottom: 25px; - max-width: 50%; - width: 50%; - padding-right: 50px; - } -} - -.action_column { - float: right; -} - -.alert-info { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100px; - border-radius: 5px; - border: 1px solid @default-no-items-bord; - background-color: @default-no-items-bord; - color: @default-icon; - text-transform: uppercase; -} - -.alert-info--noTextTransform { - text-transform: none; -} - -.select2-results__option { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.select2-results__option:hover { - overflow-wrap: break-word; - white-space: normal; -} - -::-webkit-input-placeholder { /* Chrome/Opera/Safari */ - color: @b7grey; -} -::-moz-placeholder { /* Firefox 19+ */ - color: @b7grey; -} -:-ms-input-placeholder { /* IE 10+ */ - color: @b7grey; -} -:-moz-placeholder { /* Firefox 18- */ - color: @b7grey; -} - -.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - border-color: @b7grey; - background-color: @ebgrey; -} - -.Form-checkboxRow { - display: flex; - clear: left; -} diff --git a/awx/ui/client/legacy/styles/inventory-edit.less b/awx/ui/client/legacy/styles/inventory-edit.less deleted file mode 100644 index b608f854c323..000000000000 --- a/awx/ui/client/legacy/styles/inventory-edit.less +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * inventory-edit.less - * - * custom animation mixins for ansible-ui - * - */ -#inventory_edit { - #breadcrumbs .nav-path { - margin-bottom: 8px; - } - #hosts_table .actions{ - float: right; - } - #groups_table .actions{ - float:right; - } -} - -#group-copy-dialog, -#host-copy-dialog { - .highlight { - font-size: 16px; - font-weight: bold; - color: red; - padding-right: 5px; - } - .title { - font-weight: bold; - margin-bottom: 15px; - } - .well { - padding-left: 8px; - padding-right: 8px; - padding-top: 8px; - padding-bottom: 8px; - } - .page-row ul li a { - font-size: 12px; - } - .page-row .col-lg-8 { - width: 100%; - } - .page-row .col-md-8 { - width: 100%; - } -} - -#copy-group-radio-container .form-group { - margin-left: 20px; - margin-bottom: 10px; -} - -#copy-group-target-container .form-group { - margin-top: 10px; - margin-left: 20px; - margin-bottom: 15px; -} - -#group-list-container, -#hosts-container { - .page-row { - margin-top: 5px; - } -} diff --git a/awx/ui/client/legacy/styles/job-details.less b/awx/ui/client/legacy/styles/job-details.less deleted file mode 100644 index 5d79971bfc96..000000000000 --- a/awx/ui/client/legacy/styles/job-details.less +++ /dev/null @@ -1,567 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * job-details.less - * - * Styles for job details page - * - */ - - -@failed-hosts-color: @red; -@successful-hosts-color: @green; -@changed-hosts-color: @changed; -@skipped-hosts-color: @skipped; -@unreachable-hosts-color: @unreachable; - - -#host-events-modal-dialog { - overflow: hidden; - i[class*='icon-job'] { - font-size: 12px; - vertical-align: middle; - } - #search-form { - margin-left: 7px; - } - #host-events-search-name { - width: 200px; - padding-right: 15px; - } - #search-all-input-icons { - position: absolute; - right: 3px; - top: 3px; - a { - color: #a9a9a9; - } - a:hover { - color: @black; - } - } - #status-field { - margin-left: 15px; - } - #host-events-table { - margin-top: 15px; - } - #host-events { - height: 200px; - overflow: scroll; - tr:first-of-type { - border-top-color: @white; - td { - border-top-color: @white; - } - } - } - #fixed-table-header { - margin-bottom: 0; - } - #search-indicator { - margin-left: 15px; - } -} - -@media (max-width: 768px) { - #host-events-modal-dialog { - #search-form-input-icons { - position: absolute; - top: 30px; - left: 185px; - } - #status-field { - margin-left: 0; - } - .form-group { - margin-bottom: 15px; - } - } -} - -#jobs-detail { - - #play-help { - width: 1px; - height: 1px; - color: #fff; - } - - .job_summary { - .table { - margin-bottom: 0; - border: 1px solid @grey; - background-color: @white; - } - .table>tbody>tr>td { - border-top-color: @grey; - padding-bottom: 0; - } - .table>thead>tr>th { - border-bottom-color: @grey; - padding-bottom: 0; - height: 22px; - } - } - - .status-bar { - height: 16px; - overflow: hidden; - border-radius: 4px; - border: 1px solid @grey; - margin-top: 2px; - } - - .inner-bar { - display: inline-block; - overflow: hidden; - height: 16px; - text-align: center; - font-size: 12px; - font-weight: bold; - line-height: normal; - } - - .scroll-spinner { - display: none; - background-color: transparent; - color:#000; - float:right; - margin-right: 5px; - } - - #hostResultsMoreRows.scroll-spinner { - padding-top: 0; - position: relative; - top: 12px; - } - - #hostSummariesMoreRows.scroll-spinner { - margin-right: 0; - } - - .failed-hosts { - background-color: @failed-hosts-color; - } - .failed-hosts-color { - color: @failed-hosts-color; - } - .successful-hosts { - background-color: @successful-hosts-color; - } - .successful-hosts-color { - color: @successful-hosts-color; - } - .changed-hosts { - background-color: @changed-hosts-color; - } - .changed-hosts-color { - color: @changed-hosts-color; - } - .skipped-hosts, .no-matching-hosts { - background-color: @skipped-hosts-color; - } - .unreachable-hosts { - background-color: @unreachable-hosts-color; - } - .unreachable-hosts-color { - color: @unreachable-hosts-color; - } - - .job_well { - padding: 8px; - background-color: @white; - border: 1px solid @grey; - border-radius: 4px; - /*-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);*/ - } - - #hide-summary-button { - text-align: right; - margin-bottom: 15px; - } - - .section { - margin-bottom: 20px; - h5 { - margin-top: 0; - margin-bottom: 12px; - font-weight: bold; - } - } - - .section:last-child { - margin-bottom: 0; - } - - - #job_options { - height: 100px; - overflow-y: auto; - overflow-x: none; - } - - #job_plays, #job_tasks { - overflow-y: auto; - overflow-x: none; - } - - #breadcrumb-container { - padding-right: 15px; - .nav-path { - margin-bottom: 15px; - } - } - - #job-detail-container { - - .well { - overflow: hidden; - } - - #job-status-form { - label { - font-weight: bold; - } - .control-label { - padding-top: 0; - padding-right: 0; - text-align: left; - } - .form-group { - margin-bottom: 15px; - } - hr { - margin-top: 0; - } - .more-or-less { - font-size: 12px; - text-align: left; - margin-bottom: 15px; - } - #started-time, - #finished-time, - #elapsed-time { - display: inline-block; - } - #finished-time, - #elapsed-time { - padding-left: 15px; - } - } - - } - - #job-summary-container { - position: absolute; - top: 0; - right: 0; - padding-right: 15px; - padding-left: 7px; - width: 41.66666667%; - } - - .table-header { - font-weight: bold; - font-size: 12px; - .table>thead>tr>th { - border-bottom-color: @white; - } - .table { - margin-bottom: 0; - } - } - - .table-detail { - overflow-x: hidden; - overflow-y: auto; - background-color: @white; - min-height: 40px; - - .row { - border-top: 1px solid @grey; - } - .row:first-child { - border: none; - } - .loading-info { - padding-top: 5px; - padding-left: 3px; - } - .table { - margin-bottom: 0; - } - .table-condensed > tbody > tr > td { - padding-top: 0; - padding-bottom: 0; - } - } - - .status-column i { - font-size: 12px; - } - - #plays-table-header table, - #plays-table-detail table, - #tasks-table-detail table, - #tasks-table-header table, - #tasks-table-detail table { - table-layout:fixed; - } - - #plays-table-detail td, - #plays-table-header td, - #tasks-table-detail td, - #tasks-table-header td { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - #play-section { - .table-detail { - min-height: 40px; - } - } - - .title { - font-size: 14px; - font-weight: 600; - } - - .header { - width: 100%; - height: 28px; - padding-bottom: 5px; - - - .search-field { - display: inline-block; - position: relative; - float: right; - input { - width: 250px; - padding-right: 20px; - } - a { - position: absolute; - right: 3px; - top: 3px; - color: #a9a9a9; - } - a:hover { - color: @black; - } - } - } - - #summary-search-section { - .remove-left-padding { - padding-left: 0; - } - label { - text-align: left; - font-weight: normal; - padding-left: 0; - padding-right: 0; - padding-top: 6px; - } - #search_all_hosts_name { - width: 100%; - padding-left: 3px; - padding-right: 20px; - } - } - - #event-help-link { - margin-left: 3px; - font-size: 14px; - } - - .title-row { - margin-bottom: 15px; - margin-top: 20px; - } - - .search-form { - font-size: 12px; - .form-control { - font-size: 12px; - } - .form-group:nth-of-type(2) { - margin-left: 10px; - } - } - - .search-name { - .input-xs { - height: 25px; - } - } - - #search-all-input-icons { - position: absolute; - right: 3px; - top: 3px; - a { - color: #a9a9a9; - } - a:hover { - color: @black; - } - } - - label.small-label { - font-size: 12px; - } - - #task-hosts-section { - position: relative; - top: 0; - left: 0; - #hosts-table-header table { - table-layout: fixed; - } - #hosts-table-detail { - background-color: @white; - } - #hosts-table-detail table { - table-layout: fixed; - } - #hosts-table-detail td { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - - #hosts-summary-section { - .col-lg-4, .col-md-4, .col-sm-4, .col-xs-4 { - width: 33%; - } - .col-lg-2, .col-md-2, .col-sm-2, .col-xs-2 { - width: 16.5%; - } - .table-header { - font-size: 12px; - } - .table-detail { - height: 200px; - } - .name { - word-break: break-all; - } - .badge { - font-size: 12px; - } - .badge-column a { - width: 20%; - } - } - - // .legend-row { - // margin-bottom: 15px; - // } - - // .legend { - // display: inline-block; - // font-size: 12px; - // text-align: center; - // i { - // font-size: 10px; - // margin-left: 5px; - // } - // i:first-child { - // margin-left: 0; - // } - // } - - #graph-section { - position: relative; - .legend { - font-size: 12px; - font-family: 'Open Sans'; - } - rect { - stroke-width: 2; - } - .donut-tooltip { - display: none; - font-size: 12px; - font-family: 'Open Sans'; - left: 280px; - padding: 10px; - position: absolute; - text-align: center; - top: 85px; - width: 100px; - z-index: 10; - color: white; - background-color: black !important; - border-radius:4px; - border: 1px solid black; - } - } - - #graph-section svg{ - margin: 0 auto; - } - - path.slice{ - stroke-width:2px; - } - - polyline{ - opacity: .3; - stroke: black; - stroke-width: 2px; - fill: none; - } - - svg text.percent{ - fill:@black; - text-anchor:middle; - font-size:12px; - font-weight: bold; - } - - #pre-formatted-variables { - border-radius: 4px; - border: 1px solid @grey; - overflow: auto; - white-space: pre; - word-break: break-all; - word-wrap: break-word; - padding: 9.5px; - font-family: Fixed, monospace; - max-height: 200px; - } - - .footer-row { - height: 20px; - } - - .host_summary_row { - margin-top: 15px; - margin-bottom: -15px; - margin-left: 0; - } - - @media (max-width: 767px) { - #job-detail-container { - #job-status-form { - #finished-time, - #elapsed-time { - display: block; - } - #finished-time, - #elapsed-time { - padding-left: 0; - margin-left: 0; - padding-top: 15px; - } - } - } - } -} diff --git a/awx/ui/client/legacy/styles/jobs.less b/awx/ui/client/legacy/styles/jobs.less deleted file mode 100644 index 887a979d5acc..000000000000 --- a/awx/ui/client/legacy/styles/jobs.less +++ /dev/null @@ -1,99 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * jobs.less - * - * custom styles for the jobs pages - * - */ - -#jobs-page { - - .jobs-list-container { - border: 1px solid @grey; - border-radius: 4px; - padding: 5px; - } - - .job-list { - - i[class*="icon-job-"] { - font-size: 13px; - } - } - - #completed_jobs_table i[class*="icon-job-"] { - font-size: 13px; - } - - #completed_jobs_table, - #schedules_table, - #running_jobs_table, - #queued_jobs_table { - table-layout:fixed; - } - #completed_jobs_table .name-column, - #schedules_table .name-column, - #running_jobs_table .name-column, - #queued_jobs_table .name-column, - { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .title { - font-weight: bold; - margin-top: 5px; - margin-left: 3px; - } - - #breadcrumbs .nav-path { - background-color: @white; - } - - #breadcrumb-list.breadcrumb { - background-color: @white; - } - - .List-noItems { - margin-top: 0; - } - -} - -@media (min-width: 1201px) { - #jobs-page { - .left-side { - padding-right: 7px; - } - - .right-side { - padding-left: 7px; - } - - .bottom-row { - margin-top: 15px; - } - } -} - -@media (max-width: 1200px) { - #jobs-page .jobs-list-container { - margin-top: 15px; - } - #jobs .jobs-list-container.completed { - margin-top: 0; - } - .title{ - margin-bottom: 8px; - } - #jobs-page { - .left-side { - padding-right: 15px; - } - .right-side { - padding-left: 15px; - } - } -} diff --git a/awx/ui/client/legacy/styles/jquery-ui-overrides.less b/awx/ui/client/legacy/styles/jquery-ui-overrides.less deleted file mode 100644 index 8656b3693fef..000000000000 --- a/awx/ui/client/legacy/styles/jquery-ui-overrides.less +++ /dev/null @@ -1,227 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * jquery-ui-overrides.less - * - * Additions to the custom-theme to make things - * look closer to Twitter Bootstrap - * - */ -table.ui-datepicker-calendar { - background-color: @well; -} - -/* Modal dialog */ -.ui-dialog-title { - font-size: 15px; - color: @default-interface-txt; - font-weight: bold; - line-height: normal; - font-family: 'Open Sans', helvetica; - text-transform: uppercase; -} -.ui-dialog { - .close { - font-size: 18px; - font-weight: bold; - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - line-height: 1; - opacity: 1; - text-shadow: 0 1px 0 @white; - color:@d7grey; - } - .close:hover{ - color:@default-icon; - } - .ui-widget { - font-family: 'Open Sans', sans-serif; - } - .ui-widget-header { - border-radius: 0; - border: none; - } - .ui-dialog-titlebar { - padding-bottom: 0; - padding-top: 12px; - - button.close i { - font-size: 24px; - } - } - .ui-dialog-titlebar .ui-state-default { - background-image: none; - background-color: @white; - border-color: @white; - color: #A9A9A9; - } - .mono-space { - font-family: Fixed, monospace; - } - textarea.resizable { - resize: vertical; - } - .ui-resizable-se { - right: 5px; - bottom: 5px; - background-position: -80px -224px; - color: @black; - } - - button.btn.btn-primary, - button.btn.btn-default { - padding: 5px 15px; - font-size: 12px; - line-height: 1.5; - transition: background-color 0.2s; - font-size: 12px; - } - - button.btn.btn-primary { - text-transform: uppercase; - background-color: @default-succ; - border-color: @default-succ; - - &:hover { - background-color: @default-succ-hov; - border-color: @default-succ-hov; - } - - &:disabled { - background-color: @default-succ-disabled; - border-color: @default-succ-disabled; - } - } - - button.btn.btn-default { - text-transform: uppercase; - border-color: @b7grey; - color: @default-interface-txt; - } - - .ui-dialog-buttonpane.ui-widget-content { - border: none; - margin: 0; - padding-top: 0; - padding-right: 8px; - } - - .input-group-btn.dropdown, .List-pagination, .List-tableHeader { - font-family: 'Open Sans', sans-serif; - } - -} -.ui-dialog-buttonpane > .ui-dialog-buttonset { - button { - margin-left: 20px; - } -} - -.ui-dialog-buttonset { - text-transform: uppercase; - - button.btn.btn-default.ui-state-hover, - button.btn.btn-default.ui-state-active, - button.btn.btn-default.ui-state-focus { - font-weight: normal; - } - button.btn.btn-primary.ui-state-hover, - button.btn.btn-primary.ui-state-active, - button.btn.btn-primary.ui-state-focus { - background-image: none; - color: @white; - background-color: @blue-dark; - border-color: #285e8e; - text-decoration: none; - font-weight: normal; - } - max-height: 48px; -} - -.ui-widget-overlay.ui-front { - background-image: none; - background-color: #000; - opacity: .6; -} - -.ui-dialog-content.ui-widget-content { - padding-top: 20px; -} - -.ui-widget-content { - background-image: none; - background-color: @default-bg; - - a, - a:visited, - a:active { - color: @blue-link; - text-decoration: none; - } - - a:hover, - a:focus { - color: @blue-dark; - text-decoration: none; - } - - .red-txt, - a.red-txt:visited, - a.red-txt:hover, - a.red-txt:active { - color: @red; - } - - .dropdown-menu>li>a { - color: @default-interface-txt; - } - - .pagination .active { - a, a:visited, a:active { - color: @white; - } - } -} - -.ui-state-default { - background-image: none; - background-color: @white; - border: 1px solid @grey; -} - -.ui-accordion-header-active { - background-color: #E8E8E8; -} - -/*.ui-state-active { - background-image: none; - background-color: #f5f5f5; -}*/ - -.ui-widget-content { - border: 1px solid @grey; -} - -.ui-spinner a.ui-spinner-button { - border-left: 1px solid #A6C9E2; -} - -.ui-front { - z-index: 1100; -} - -.ui-accordion .ui-accordion-header { - margin-top: 1px; -} - -.ui-spinner.ui-state-disabled, -.ui-state-disabled .ui-spinner-button { - cursor: not-allowed !important; -} - -.ui-state-disabled .ui-spinner-button:hover { - background-color: @default-bg !important; -} - -.ui-state-disabled.ui-widget-content { - background-color: @ebgrey !important; -} diff --git a/awx/ui/client/legacy/styles/lists.less b/awx/ui/client/legacy/styles/lists.less deleted file mode 100644 index f7746f866442..000000000000 --- a/awx/ui/client/legacy/styles/lists.less +++ /dev/null @@ -1,571 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * lists.less - * - * custom styles for generated lists - * - */ - -table, tbody { - border-collapse: collapse; -} - -.List-well { - margin-top: 20px; -} - -.List-table{ - width: 100%; - margin-top: 20px; - table-layout: fixed; -} - -.List-tableHeader{ - height: 30px; - font-size: 14px; - font-weight: normal; - text-transform: uppercase; - color: @list-header-txt; - background-color: @list-header-bg; - padding-left: 15px; - padding-right: 15px; - border-bottom-width:0px!important; -} - -.List-tableHeader:first-of-type { - border-top-left-radius: 5px; -} - -.List-tableHeader:last-of-type { - border-top-right-radius: 5px; -} - -.List-tableHeader--info, .List-tableHeader--actions { - text-align: right; -} - -.List-tableHeader:not([ng-click]) { - cursor: default !important; -} - -.List-tableHeaderSort { - color: @list-header-icon; -} - -.List-tableRow { - height: 40px; - font-size: 14px; - color: @list-item; - border-bottom: 1px solid @default-border; -} - -.List-tableRow:last-of-type { - border-bottom: none; -} - -.List-tableRow:hover { - background-color: @f2grey; -} - -.List-tableRow--selected { - border-left: 5px solid @list-row-select-bord; -} - -.List-tableRow--disabled { - .List-tableCell, .List-tableCell * { - color: @b7grey; - cursor: not-allowed; - } -} - -.List-tableRow--disabled { - .List-actionButton:hover { - color: @list-action-icon; - background-color: @list-actn-bg !important; - } -} - -.List-tableRow--disabled { - .List-actionButtonCell * { - color: @default-err; - font-size: 11px; - text-transform: uppercase; - } -} - -.List-tableRow--invalid { - height: 40px; -} - -.List-tableRow--invalidBar { - align-items: center; - border-left: solid @at-space-2x @at-color-error; - color: @at-white; - display: flex; - height: 100%; - justify-content: center; - position: relative; - - i { - position: absolute; - left: -7px; - } -} - -.List-tableCell { - padding: 7px 15px; - border-top:0px!important; - word-wrap: break-word; -} - -.List-tableCell.description-column { - padding-top: 15px; - padding-bottom: 15px; -} - -.List-actionButtonCell { - padding-top:5px; - padding-right: 15px; - display:flex; - justify-content: flex-end; -} - -.List-actionButton { - font-size: 16px; - height: 30px; - min-width: 30px; - color: @list-action-icon; - background-color: @list-actn-bg; - border: none; - border-radius: 4px; - margin-left: 15px; -} - -.List-actionButton:hover { - background-color: @list-actn-bg-hov !important; - color: @list-actn-icn-hov; -} - -.List-actionButton--delete:hover { - background-color: @list-actn-del-bg-hov !important; -} - -.List-header { - display: flex; -} - -.List-title { - align-items: center; - flex: 1 0 auto; - display: flex; -} - -.List-titleBadge { - font-size: 11px; - font-weight: normal; - padding: 2px 10px; - height: 14px; - line-height: 10px; - margin: 0; - background-color: @list-title-badge; - border-radius: 5px; -} - -.List-titleBadge--selected { - background-color: @default-link; -} - -.List-titleText { - color: @list-title-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - line-height: 0.8; - text-transform: uppercase; -} - -.List-exitHolder { - justify-content: flex-end; - display:flex; -} - -.List-exit { - cursor:pointer; - padding:0px; - border: none; - height:20px; - font-size: 20px; - background-color:@default-bg; - color:@d7grey; - transition: color 0.2s; - line-height:1; -} - -.List-exit:hover{ - color:@default-icon; -} - -.List-actionHolder { - justify-content: flex-end; - display: flex; - // margin-bottom: 20px; - // float: right; -} - -.List-actionHolder--leftAlign { - width: 50%; - margin-left: 50%; - justify-content: flex-start; -} - -.List-actions { - align-items: center; - display: flex; - margin-bottom: -34px; -} - -.List-auxAction { - align-items: center; - display: flex; - order: 1; - margin-left: 20px; -} - -.List-auxActionStream { - width: 200px; -} - -.List-buttonSubmit { - background-color: @submit-button-bg; - color: @submit-button-text; -} - -.List-buttonSubmit:hover, -.List-buttonSubmit:focus { - color: @submit-button-text; - background-color: @submit-button-bg-hov; -} - -.List-buttonDefault { - background-color: @btn-bg; - color: @btn-txt; - border-color: @b7grey; - height: 30px; - line-height: 14px; -} - -.List-buttonDefault:hover, -.List-buttonDefault:focus { - background-color: @btn-bg-hov; - color: @btn-txt; -} - -.List-buttonDefault[disabled] { - opacity: 0.65; -} - -.List-searchDropdown { - border-top-left-radius: 5px!important; - border-bottom-left-radius: 5px!important; - height: 34px!important; - border-color: @d7grey; - color: @default-icon; - background-color: @default-bg; - border-right: none; -} - -.List-searchDropdown:focus, -.List-searchDropdown:active, -.List-searchDropdown.active -{ - color: @default-icon; - background-color: @default-tertiary-bg; -} - -.List-searchDropdown:hover { - background-color: @default-tertiary-bg; - color: @default-icon; -} - -.List-searchDropdownCarat { - border-top-color: @default-icon!important; -} - -.List-searchInput { - background-color: @list-srch-inpt-bg!important; - font-size: 14px!important; - color: @list-srch-inpt-txt!important; - border-color: @list-srch-inpt-bord!important; - border-radius: 0px 5px 5px 0px!important; - padding-left: 15px!important; - height: 34px!important; - padding-right: 45px!important; - font-family: 'Open Sans', sans-serif; -} - -.List-searchInput:placeholder-shown { - color: @list-srch-inpt-ph-txt!important; - text-transform: uppercase; -} - -.List-searchInput:focus { - border-color: @list-srch-inpt-focus!important; -} - -.List-searchInputIcon { - height: 32px; - width: 32px; - border-left: 1px solid @list-srch-inpt-bord; - color: @list-srch-btn-icon!important; - float: right; - position: relative; - top: -33px; - left: -2px; - z-index: 10; - font-size: 16px; - background-color: @list-srch-btn-bg; - display: flex; - align-items: center; - justify-content: center; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; -} - -.List-searchInputIcon:hover { - cursor: pointer; - background-color: @list-srch-btn-hov-bg; - color: @list-srch-btn-icon; -} - -.List-searchNoResults { - color: @default-interface-txt; - margin-top: 20px; -} - -.List-noItems { - margin-top: 52px; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 200px; - border-radius: 5px; - border: 1px solid @d7grey; - background-color: @default-no-items-bord; - color: @list-no-items-txt; - text-transform: uppercase; - text-align: center; - padding: 10px; -} - -.modal-body > .List-noItems { - margin-top: 0px; -} - -.List-actionButton--selected, -.List-editButton--selected { - background-color: @list-actn-bg-hov !important; - color: @list-actn-icn-hov; -} - -.List-searchWidget { - height: 34px; -} - -.List-searchWidget--compact { - max-width: ~"calc(100% - 91px)"; - margin-top: 10px; -} - -.List-searchRow { - margin-bottom: 20px; -} - -.List-staticColumn--smallStatus { - width: 25px; - padding-right: 0px!important; -} - -.List-staticColumn--mediumStatus { - width: 51px; - padding-right: 0px!important; -} - -.List-staticColumn--toggle { - width: 55px; - padding-right: 0px !important; -} - -.List-staticColumn--schedulerTime { - max-width: 164px; -} - -.List-staticColumn--invalidBar { - width: 10px; - padding-right: 0px!important; -} - -.List-staticColumnAdjacent { - padding-left: 10px!important; -} - -.List-staticColumnAdjacent--monospace { - font-family: monospace; -} - -.List-titleLockup { - margin-left: 4px; - margin-right: 6px; - display: inline-block; - margin-top: 0px; - padding-bottom: 2px; - vertical-align: bottom; -} - -.List-titleLockup:before { - content: "\007C"; - color: #d7d7d7; - display: block; - font-size: 13px; -} - -.List-action--showTooltipOnDisabled { - display: inline-block; - cursor: not-allowed; -} - -.List-action--showTooltipOnDisabled .btn[disabled] { - pointer-events: none; -} - -.List-action--showTooltipOnDisabled.disabled { - cursor: not-allowed; -} - -.List-action--notificationAdd { - text-align: right; - font-size: 11px; -} - -.List-dropdownButton { - border: none; -} - -.List-dropdownSuccess { - background-color: @submit-button-bg; - color: @submit-button-text; - border-color: @submit-button-bg-hov; -} - -.List-dropdownSuccess:hover, -.List-dropdownSuccess:focus { - color: @submit-button-text; - background-color: @submit-button-bg-hov; -} - -.List-infoCell { - display: flex; - justify-content: flex-end; - font-size: 0.8em; - cursor: pointer; - - .popover-content { - dl { - display: flex; - margin: 0; - } - dt, dd { - flex: 1 1 50%; - font-weight: inherit; - margin: 0; - } - } -} - -.List-infoCell--badge { - height: 15px; - color: @default-interface-txt; - background-color: @default-list-header-bg; - border-radius: 5px; - font-size: 10px; - padding-left: 10px; - padding-right: 10px; - margin-left: 10px; - text-transform: uppercase; - font-weight: 100; - margin-top: 2.25px; - outline: none; -} - -.List-actionsInner { - display: flex; -} - -@media (max-width: 991px) { - .List-searchWidget + .List-searchWidget { - margin-top: 20px; - } -} - -@media (max-width: 700px) { - .List-header { - flex-direction: column; - align-items: stretch; - } - .List-actionHolder { - justify-content: flex-start; - align-items: center; - flex: 1 0 auto; - margin-top: 12px; - } - .List-actions { - margin-bottom: 20px; - } - .List-well { - margin-top: 20px; - } - - .List-action { - margin-left: 20px; - } - - .List-actionsInner { - margin-left: -20px; - } -} - -.InventoryManage-container, .modal-body { - .List-header { - flex-direction: column; - align-items: stretch; - } - .List-actionHolder { - justify-content: flex-start; - align-items: center; - flex: 1 0 auto; - margin-top: 12px; - } - .List-actions { - margin-bottom: 20px; - } - .List-well { - margin-top: 20px; - } - .List-action:not(.ng-hide) ~ .List-action:not(.ng-hide) { - margin-left: 0; - } -} - -// Inventory Manage exceptions -.InventoryManage-container { - .List-actionHolder { - justify-content: flex-end; - } - .List-actions { - margin: 0 0 -34px 0; - } - .SmartSearch-searchTermContainer { - width: 100%; - } -} diff --git a/awx/ui/client/legacy/styles/log-viewer.less b/awx/ui/client/legacy/styles/log-viewer.less deleted file mode 100644 index 0690205d9a78..000000000000 --- a/awx/ui/client/legacy/styles/log-viewer.less +++ /dev/null @@ -1,29 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * log-viewer.css - * - * custom styles for LogViewer.js helper - * - */ - -#logviewer-modal-dialog { - - textarea { - overflow: scroll; - } - pre { - overflow: scroll; - word-wrap: normal; - word-break: normal; - white-space: pre-wrap; - } -} - -table.logviewer-status { - margin-top: 20px; - - .fld-label { - font-weight: bold; - } -} diff --git a/awx/ui/client/legacy/styles/stdout.less b/awx/ui/client/legacy/styles/stdout.less deleted file mode 100644 index 061e90383a3f..000000000000 --- a/awx/ui/client/legacy/styles/stdout.less +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2015 Ansible, Inc. - * - * Styles for job stdout - * - */ - - #jobs-stdout { - margin-bottom: 0px; - - #job-status { - label { - margin-right: 15px; - } - margin-bottom: 15px; - } - - .scroll-spinner { - display: none; - background-color: transparent; - color:#000; - } - #stdoutMoreRowsTop { - position: absolute; - top: 10px; - right: 20px; - } - #stdoutMoreRowsBottom { - float: right; - padding-right: 15px; - } - #pre-container { - overflow-x: scroll; - overflow-y: auto; - padding: 10px; - } - - } - -.ansi_fore { color: #AAAAAA; } -.ansi_back { background-color: @black; } -.ansi1 { font-weight: bold; } -.ansi3 { font-weight: italic; } -.ansi4 { text-decoration: underline; } -.ansi9 { text-decoration: line-through; } -.ansi30 { color: @default-data-txt; } -.ansi31 { color: @default-err; } -.ansi1.ansi31 { - color: @default-unreachable; -} -.ansi32 { color: @default-succ; } -.ansi33 { color: @default-warning; } -.ansi34 { color: @default-link; } -.ansi35 { color: @default-magenta; } -.ansi36 { color: @default-cyan; } -.ansi37 { color: @default-bg; } -.ansi40 { background-color: @default-stdout-txt; } -.ansi41 { background-color: @default-err; } -.ansi42 { background-color: @default-succ; } -.ansi43 { background-color: @default-warning; } -.ansi44 { background-color: @default-link; } -.ansi45 { background-color: @default-magenta; } -.ansi46 { background-color: @default-cyan; } -.ansi47 { background-color: @default-bg; } - -#pre-container-content > span { - display: inline-block; - white-space: pre-wrap; - word-wrap: normal; -} diff --git a/awx/ui/client/legacy/styles/survey-maker.less b/awx/ui/client/legacy/styles/survey-maker.less deleted file mode 100644 index 176ee7694f1e..000000000000 --- a/awx/ui/client/legacy/styles/survey-maker.less +++ /dev/null @@ -1,92 +0,0 @@ -/********************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * survey-maker.css - * - * custom styles for the survey maker - * - */ - - -/** -* #survey_maker_question_area{ -* border: 1px solid; -* border-color: rgb(204,204,204); -* border-radius: 4px; -* padding: 15px; -* } -*/ - -.question_form{ - border: 1px solid; - border-color: rgb(204,204,204); - border-radius: 4px; - padding: 5px; - margin-bottom: 15px; - height: 500px; -} - -.survey_maker_question{ - border: 1px solid; - border-color: rgb(204,204,204); - border-radius: 4px; - margin-bottom: 10px; -} - -.question_final{ - border-top: 1px dashed; - border-color: rgb(204,204,204); - border-radius: 4px; - padding: 5px; - position: relative; - - .survey-maker-password{ - margin-left: 30px; - } - - .final{ - margin-left: 15px; - margin-top: 5px; - } - .question_title{ - opacity: 0.7; - } - .description{ - opacity: 0.7; - margin-left: 15px; - } - .input_area{ - opacity: 0.7; - } - .mc{ - margin-left: 18px; - margin-right: 7px; - } - -} - -.question_actions{ - opacity: 1.0; -} - -#new_question{ - margin-top: 5px; -} - -#add_question_btn{ - margin-top: 15px; - margin-bottom: 15px; -} - - -.survey_taker_input{ - - .mc{ - margin-left: 18px; - margin-right: 7px; - } -} - -.survey_taker_description{ - margin-bottom:10px -} diff --git a/awx/ui/client/legacy/styles/text-label.less b/awx/ui/client/legacy/styles/text-label.less deleted file mode 100644 index eca6e83cf494..000000000000 --- a/awx/ui/client/legacy/styles/text-label.less +++ /dev/null @@ -1,15 +0,0 @@ -.host-disabled-label { - &:after { - display: inline-block; - content: "disabled"; - border-radius: 3px; - color: @default-icon; - text-transform: uppercase; - font-size: .7em; - font-style: normal; - margin-left: 0.5em; - padding: 0.35em; - padding-bottom: 0.2em; - line-height: 1.1; - } -} diff --git a/awx/ui/client/lib/components/_index.less b/awx/ui/client/lib/components/_index.less deleted file mode 100644 index 72c14fe4b5ea..000000000000 --- a/awx/ui/client/lib/components/_index.less +++ /dev/null @@ -1,13 +0,0 @@ -@import 'action/_index'; -@import 'input/_index'; -@import 'launchTemplateButton/_index'; -@import 'layout/_index'; -@import 'list/_index'; -@import 'modal/_index'; -@import 'panel/_index'; -@import 'popover/_index'; -@import 'relaunchButton/_index'; -@import 'tabs/_index'; -@import 'truncate/_index'; -@import 'utility/_index'; -@import 'code-mirror/_index'; diff --git a/awx/ui/client/lib/components/action/_index.less b/awx/ui/client/lib/components/action/_index.less deleted file mode 100644 index 6208e2a41dff..000000000000 --- a/awx/ui/client/lib/components/action/_index.less +++ /dev/null @@ -1,7 +0,0 @@ -.at-ActionGroup { - margin-top: @at-margin-panel; - - button:last-child { - margin-left: @at-margin-panel-inset; - } -} diff --git a/awx/ui/client/lib/components/action/action-group.directive.js b/awx/ui/client/lib/components/action/action-group.directive.js deleted file mode 100644 index 1974ab1d4331..000000000000 --- a/awx/ui/client/lib/components/action/action-group.directive.js +++ /dev/null @@ -1,16 +0,0 @@ -const templateUrl = require('~components/action/action-group.partial.html'); - -function atActionGroup () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - col: '@', - pos: '@' - } - }; -} - -export default atActionGroup; diff --git a/awx/ui/client/lib/components/action/action-group.partial.html b/awx/ui/client/lib/components/action/action-group.partial.html deleted file mode 100644 index e0df9581ac88..000000000000 --- a/awx/ui/client/lib/components/action/action-group.partial.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
- -
-
diff --git a/awx/ui/client/lib/components/code-mirror/_index.less b/awx/ui/client/lib/components/code-mirror/_index.less deleted file mode 100644 index 770546b1515f..000000000000 --- a/awx/ui/client/lib/components/code-mirror/_index.less +++ /dev/null @@ -1,76 +0,0 @@ -.noselect { - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Chrome/Safari/Opera */ - -khtml-user-select: none; /* Konqueror */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ - user-select: none; /* Non-prefixed version, currently - not supported by any browser */ -} - -.atCodeMirror-label{ - display: flex; - width: 100%; - margin-bottom: 5px; -} - -.atCodeMirror-labelLeftSide{ - flex: 1 0 auto; -} - -.atCodeMirror-labelText{ - text-transform: uppercase; - color: #707070; - font-weight: normal; - font-size: small; - padding-right: 5px; - width: 100%; -} - -.atCodeMirror-toggleContainer{ - margin: 0 0 0 10px; - display: initial; - padding-bottom: 5px; -} - -.atCodeMirror-expandTextContainer{ - flex: 1 0 auto; - text-align: right; - font-weight: normal; - color: @default-link; - cursor: pointer; - font-size: 12px; -} - -.CodeMirror-modal .modal-dialog{ - width: calc(~"100% - 200px"); - height: calc(~"100vh - 80px"); -} - - -@media screen and (min-width: 768px){ - .NetworkingExtraVars .modal-dialog{ - width: 700px; - } -} - -.CodeMirror-modal .modal-dialog{ - width: calc(~"100% - 200px"); - height: calc(~"100vh - 80px"); -} - -.CodeMirror-modal .modal-content{ - height: 100%; -} - -.NetworkingExtraVars .CodeMirror{ - overflow-x: hidden; -} - -.CodeMirror-modalControls{ - float: right; - margin-top: 15px; - button { - margin-left: 10px; - } -} diff --git a/awx/ui/client/lib/components/code-mirror/code-mirror.directive.js b/awx/ui/client/lib/components/code-mirror/code-mirror.directive.js deleted file mode 100644 index 6d74f2a6aa8a..000000000000 --- a/awx/ui/client/lib/components/code-mirror/code-mirror.directive.js +++ /dev/null @@ -1,78 +0,0 @@ -const templateUrl = require('~components/code-mirror/code-mirror.partial.html'); - -const CodeMirrorID = 'codemirror-extra-vars'; -const CodeMirrorModalID = '#CodeMirror-modal'; -const ParseVariable = 'parseType'; -const CodeMirrorVar = 'variables'; -const ParseType = 'yaml'; - -function atCodeMirrorController ( - $scope, - strings, - ParseTypeChange, - ParseVariableString -) { - const vm = this; - - function init (vars) { - $scope.variables = ParseVariableString(_.cloneDeep(vars)); - $scope.parseType = ParseType; - const options = { - scope: $scope, - variable: CodeMirrorVar, - parse_variable: ParseVariable, - field_id: CodeMirrorID, - readOnly: $scope.disabled - }; - ParseTypeChange(options); - } - - function expand () { - vm.expanded = true; - } - - function close () { - $(CodeMirrorModalID).off('hidden.bs.modal'); - $(CodeMirrorModalID).modal('hide'); - $('.popover').popover('hide'); - vm.expanded = false; - } - - vm.strings = strings; - vm.expanded = false; - vm.close = close; - vm.expand = expand; - if ($scope.init) { - $scope.init = init; - } - init($scope.variables); -} - -atCodeMirrorController.$inject = [ - '$scope', - 'CodeMirrorStrings', - 'ParseTypeChange', - 'ParseVariableString' -]; - -function atCodeMirrorTextarea () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - controller: atCodeMirrorController, - controllerAs: 'vm', - scope: { - disabled: '@', - label: '@', - labelClass: '@', - tooltip: '@', - tooltipPlacement: '@', - variables: '@', - init: '=' - } - }; -} - -export default atCodeMirrorTextarea; diff --git a/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html b/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html deleted file mode 100644 index 98349fd3a390..000000000000 --- a/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html +++ /dev/null @@ -1,60 +0,0 @@ -
-
-
- - {{ label || vm.strings.get('code_mirror.label.VARIABLES') }} - - - - -
-
- - -
-
-
-
{{ vm.strings.get('label.EXPAND') }}
-
- - - -
diff --git a/awx/ui/client/lib/components/code-mirror/code-mirror.strings.js b/awx/ui/client/lib/components/code-mirror/code-mirror.strings.js deleted file mode 100644 index 0dae4bc6a5fc..000000000000 --- a/awx/ui/client/lib/components/code-mirror/code-mirror.strings.js +++ /dev/null @@ -1,55 +0,0 @@ -function CodeMirrorStrings (BaseString) { - BaseString.call(this, 'code_mirror'); - - const { t } = this; - const ns = this.code_mirror; - - ns.label = { - EXTRA_VARIABLES: t.s('EXTRA VARIABLES'), - VARIABLES: t.s('VARIABLES'), - EXPAND: t.s('EXPAND'), - YAML: t.s('YAML'), - JSON: t.s('JSON') - - }; - - ns.tooltip = { - TOOLTIP: t.s(` -

- Enter inventory variables using either JSON or YAML - syntax. Use the radio button to toggle between the two. -

- JSON: -
-
- { -
"somevar": "somevalue", -
"password": "magic" -
- } -
- YAML: -
-
- --- -
somevar: somevalue -
password: magic -
-
-

- View JSON examples at - www.json.org -

-

- View YAML examples at - - docs.ansible.com -

`), - TOOLTIP_TITLE: t.s('EXTRA VARIABLES'), - JOB_RESULTS: t.s('Read-only view of extra variables added to the job template.') - }; -} - -CodeMirrorStrings.$inject = ['BaseStringService']; - -export default CodeMirrorStrings; diff --git a/awx/ui/client/lib/components/code-mirror/index.js b/awx/ui/client/lib/components/code-mirror/index.js deleted file mode 100644 index 21d4aedc098c..000000000000 --- a/awx/ui/client/lib/components/code-mirror/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import codemirror from './code-mirror.directive'; -import modal from './modal/code-mirror-modal.directive'; -import strings from './code-mirror.strings'; - -const MODULE_NAME = 'at.code.mirror'; - -angular.module(MODULE_NAME, []) - .directive('atCodeMirror', codemirror) - .directive('atCodeMirrorModal', modal) - .service('CodeMirrorStrings', strings); - -export default MODULE_NAME; diff --git a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js deleted file mode 100644 index 6a1837272c11..000000000000 --- a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js +++ /dev/null @@ -1,84 +0,0 @@ -const templateUrl = require('~components/code-mirror/modal/code-mirror-modal.partial.html'); - -const CodeMirrorModalID = '#CodeMirror-modal'; -const CodeMirrorID = 'codemirror-extra-vars-modal'; -const ParseVariable = 'parseType'; -const CodeMirrorVar = 'extra_variables'; -const ParseType = 'yaml'; -const ModalHeight = '#CodeMirror-modal .modal-dialog'; -const ModalHeader = '.atCodeMirror-label'; -const ModalFooter = '.CodeMirror-modalControls'; - -function atCodeMirrorModalController ( - $scope, - strings, - ParseTypeChange, - ParseVariableString -) { - const vm = this; - - function resize () { - const editor = $(`${CodeMirrorModalID} .CodeMirror`)[0].CodeMirror; - const height = $(ModalHeight).height() - $(ModalHeader).height() - - $(ModalFooter).height() - 100; - editor.setSize('100%', height); - } - - function toggle () { - $scope.parseTypeChange('parseType', 'extra_variables'); - setTimeout(resize, 0); - } - - function init () { - $(CodeMirrorModalID).modal('show'); - $scope.extra_variables = ParseVariableString(_.cloneDeep($scope.variables)); - $scope.parseType = ParseType; - const options = { - scope: $scope, - variable: CodeMirrorVar, - parse_variable: ParseVariable, - field_id: CodeMirrorID, - readOnly: $scope.disabled - }; - ParseTypeChange(options); - resize(); - $(CodeMirrorModalID).on('hidden.bs.modal', $scope.closeFn); - $(`${CodeMirrorModalID} .modal-dialog`).resizable({ - minHeight: 523, - minWidth: 600 - }); - $(`${CodeMirrorModalID} .modal-dialog`).on('resize', resize); - } - - vm.strings = strings; - vm.toggle = toggle; - init(); -} - -atCodeMirrorModalController.$inject = [ - '$scope', - 'CodeMirrorStrings', - 'ParseTypeChange', - 'ParseVariableString', -]; - -function atCodeMirrorModal () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - controller: atCodeMirrorModalController, - controllerAs: 'vm', - scope: { - disabled: '@', - label: '@', - labelClass: '@', - tooltip: '@', - variables: '@', - closeFn: '&' - } - }; -} - -export default atCodeMirrorModal; diff --git a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html deleted file mode 100644 index 056672a2b583..000000000000 --- a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html +++ /dev/null @@ -1,68 +0,0 @@ - diff --git a/awx/ui/client/lib/components/components.strings.js b/awx/ui/client/lib/components/components.strings.js deleted file mode 100644 index a53da0676f47..000000000000 --- a/awx/ui/client/lib/components/components.strings.js +++ /dev/null @@ -1,105 +0,0 @@ -function ComponentsStrings (BaseString) { - BaseString.call(this, 'components'); - - const { t } = this; - const ns = this.components; - - ns.REPLACE = t.s('REPLACE'); - ns.REVERT = t.s('REVERT'); - ns.ENCRYPTED = t.s('ENCRYPTED'); - ns.OPTIONS = t.s('OPTIONS'); - ns.SHOW = t.s('SHOW'); - ns.HIDE = t.s('HIDE'); - - ns.message = { - REQUIRED_INPUT_MISSING: t.s('Please enter a value.'), - INVALID_INPUT: t.s('Invalid input for this type.') - }; - - ns.file = { - PLACEHOLDER: t.s('CHOOSE A FILE') - }; - - ns.form = { - SUBMISSION_ERROR_TITLE: t.s('Unable to Submit'), - SUBMISSION_ERROR_MESSAGE: t.s('Unexpected server error. View the console for more information'), - SUBMISSION_ERROR_PREFACE: t.s('Unexpected Error') - }; - - ns.group = { - UNSUPPORTED_ERROR_PREFACE: t.s('Unsupported input type') - }; - - ns.label = { - PROMPT_ON_LAUNCH: t.s('Prompt on launch') - }; - - ns.select = { - UNSUPPORTED_TYPE_ERROR: t.s('Unsupported display model type'), - EMPTY_PLACEHOLDER: t.s('NO OPTIONS AVAILABLE') - }; - - ns.textarea = { - SSH_KEY_HINT: t.s('HINT: Drag and drop an SSH private key file on the field below.') - }; - - ns.lookup = { - NOT_FOUND: t.s('That value was not found. Please enter or select a valid value.') - }; - - ns.truncate = { - DEFAULT: t.s('Copy full revision to clipboard.'), - COPIED: t.s('Copied to clipboard.') - }; - - ns.layout = { - CURRENT_USER_LABEL: t.s('Logged in as'), - VIEW_DOCS: t.s('View Documentation'), - LOGOUT: t.s('Logout'), - DASHBOARD: t.s('Dashboard'), - JOBS: t.s('Jobs'), - SCHEDULES: t.s('Schedules'), - PORTAL_MODE: t.s('Portal Mode'), - PROJECTS: t.s('Projects'), - CREDENTIALS: t.s('Credentials'), - CREDENTIAL_TYPES: t.s('Credential Types'), - INVENTORIES: t.s('Inventories'), - TEMPLATES: t.s('Templates'), - ORGANIZATIONS: t.s('Organizations'), - USERS: t.s('Users'), - TEAMS: t.s('Teams'), - INVENTORY_SCRIPTS: t.s('Inventory Scripts'), - NOTIFICATIONS: t.s('Notifications'), - MANAGEMENT_JOBS: t.s('Management Jobs'), - INSTANCES: t.s('Instances'), - INSTANCE_GROUPS: t.s('Instance Groups'), - APPLICATIONS: t.s('Applications'), - SETTINGS: t.s('Settings'), - FOOTER_ABOUT: t.s('About'), - FOOTER_COPYRIGHT: t.s('Copyright © 2018 Red Hat, Inc.'), - VIEWS_HEADER: t.s('Views'), - RESOURCES_HEADER: t.s('Resources'), - ACCESS_HEADER: t.s('Access'), - ADMINISTRATION_HEADER: t.s('Administration') - }; - - ns.relaunch = { - DEFAULT: t.s('Relaunch using the same parameters'), - HOSTS: t.s('Relaunch using host parameters'), - DROPDOWN_TITLE: t.s('Relaunch On'), - ALL: t.s('All'), - FAILED: t.s('Failed') - }; - - ns.launchTemplate = { - DEFAULT: t.s('Start a job using this template') - }; - - ns.list = { - DEFAULT_EMPTY_LIST: t.s('Please add items to this list.') - }; -} - -ComponentsStrings.$inject = ['BaseStringService']; - -export default ComponentsStrings; diff --git a/awx/ui/client/lib/components/form/action.directive.js b/awx/ui/client/lib/components/form/action.directive.js deleted file mode 100644 index 4ba3c7d67a37..000000000000 --- a/awx/ui/client/lib/components/form/action.directive.js +++ /dev/null @@ -1,68 +0,0 @@ -const templateUrl = require('~components/form/action.partial.html'); - -function link (scope, element, attrs, controllers) { - const [formController, actionController] = controllers; - - actionController.init(formController, scope); -} - -function atFormActionController ($state, strings) { - const vm = this || {}; - - let form; - let scope; - - vm.init = (_form_, _scope_) => { - form = _form_; - scope = _scope_; - - switch (scope.type) { - case 'cancel': - vm.setCancelDefaults(); - break; - case 'save': - vm.setSaveDefaults(); - break; - default: - vm.setCustomDefaults(); - } - - form.register('action', scope); - }; - - vm.setCancelDefaults = () => { - scope.text = strings.get('CANCEL'); - scope.fill = 'Hollow'; - scope.color = 'default'; - scope.action = () => { $state.go(scope.to || '^'); }; - }; - - vm.setSaveDefaults = () => { - scope.text = strings.get('SAVE'); - scope.fill = ''; - scope.color = 'success'; - scope.action = () => { form.submit(); }; - }; -} - -atFormActionController.$inject = ['$state', 'ComponentsStrings']; - -function atFormAction () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atFormAction'], - templateUrl, - controller: atFormActionController, - controllerAs: 'vm', - link, - scope: { - state: '=', - type: '@', - to: '@' - } - }; -} - -export default atFormAction; diff --git a/awx/ui/client/lib/components/form/action.partial.html b/awx/ui/client/lib/components/form/action.partial.html deleted file mode 100644 index 245c649de17b..000000000000 --- a/awx/ui/client/lib/components/form/action.partial.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/awx/ui/client/lib/components/form/form.directive.js b/awx/ui/client/lib/components/form/form.directive.js deleted file mode 100644 index e0ac85c595f5..000000000000 --- a/awx/ui/client/lib/components/form/form.directive.js +++ /dev/null @@ -1,225 +0,0 @@ -const templateUrl = require('~components/form/form.partial.html'); - -function atFormLink (scope, el, attrs, controllers) { - const formController = controllers[0]; - const form = el[0]; - - scope.ns = 'form'; - scope[scope.ns] = { modal: {} }; - - formController.init(scope, form); -} - -function AtFormController (eventService, strings) { - const vm = this || {}; - - let scope; - let modal; - let form; - - vm.components = []; - vm.state = { - isValid: false, - disabled: false, - value: {}, - }; - - vm.init = (_scope_, _form_) => { - scope = _scope_; - form = _form_; - ({ modal } = scope[scope.ns]); - - vm.state.disabled = scope.state.disabled; - - vm.setListeners(); - }; - - vm.register = (category, component) => { - component.category = category; - component.form = vm.state; - - if (category === 'input') { - scope.state[component.state.id] = component.state; - } - - vm.components.push(component); - }; - - vm.setListeners = () => { - const listeners = eventService.addListeners([ - [form, 'keypress', vm.submitOnEnter] - ]); - - scope.$on('$destroy', () => eventService.remove(listeners)); - }; - - vm.submitOnEnter = event => { - if (event.key !== 'Enter' || event.srcElement.type === 'textarea') { - return; - } - - event.preventDefault(); - scope.$apply(vm.submit); - }; - - vm.submit = () => { - if (!vm.state.isValid) { - return; - } - - vm.state.disabled = true; - - const data = vm.components - .filter(component => component.category === 'input') - .reduce((values, component) => { - if (component.state._value === undefined) { - return values; - } - - if (component.state._format === 'selectFromOptions') { - values[component.state.id] = component.state._value[0]; - } else if (component.state._key && typeof component.state._value === 'object') { - values[component.state.id] = component.state._value[component.state._key]; - } else if (component.state._group) { - values[component.state._key] = values[component.state._key] || {}; - values[component.state._key][component.state.id] = component.state._value; - } else { - values[component.state.id] = component.state._value; - } - - return values; - }, {}); - - scope.state.save(data) - .then(scope.state.onSaveSuccess) - .catch(err => vm.onSaveError(err)) - .finally(() => { vm.state.disabled = false; }); - }; - - vm.onSaveError = err => { - let handled; - - if (err.status === 400) { - handled = vm.handleValidationError(err.data); - } - - if (err.status === 500) { - handled = vm.handleUnexpectedError(err); - } - - if (!handled) { - let message; - const title = strings.get('form.SUBMISSION_ERROR_TITLE'); - const preface = strings.get('form.SUBMISSION_ERROR_PREFACE'); - - if (typeof err.data === 'object') { - message = JSON.stringify(err.data); - } else { - message = err.data; - } - - modal.show(title, `${preface}: ${message}`); - } - }; - - vm.handleUnexpectedError = () => { - const title = strings.get('form.SUBMISSION_ERROR_TITLE'); - const message = strings.get('form.SUBMISSION_ERROR_MESSAGE'); - - modal.show(title, message); - - return true; - }; - - vm.handleValidationError = errors => { - const errorMessageSet = vm.setValidationMessages(errors); - - if (errorMessageSet) { - vm.check(); - } - - return errorMessageSet; - }; - - vm.setValidationMessages = (errors, errorSet) => { - let errorMessageSet = errorSet || false; - - Object.keys(errors).forEach(id => { - if (!Array.isArray(errors[id]) && typeof errors[id] === 'object') { - errorMessageSet = vm.setValidationMessages(errors[id], errorMessageSet); - - return; - } - - vm.components - .filter(component => component.category === 'input') - .filter(component => errors[component.state.id]) - .forEach(component => { - errorMessageSet = true; - - component.state._rejected = true; - component.state._message = errors[component.state.id].join(' '); - }); - }); - - return errorMessageSet; - }; - - vm.validate = () => { - let isValid = true; - - for (let i = 0; i < vm.components.length; i++) { - if (vm.components[i].category !== 'input') { - continue; - } - - if (!vm.components[i].state._isValid) { - isValid = false; - break; - } - } - - return isValid; - }; - - vm.check = () => { - const isValid = vm.validate(); - - if (isValid !== vm.state.isValid) { - vm.state.isValid = isValid; - } - }; - - vm.deregisterInputGroup = components => { - for (let i = 0; i < components.length; i++) { - for (let j = 0; j < vm.components.length; j++) { - if (components[i] === vm.components[j].state) { - vm.components.splice(j, 1); - delete scope.state[components[i].id]; - break; - } - } - } - }; -} - -AtFormController.$inject = ['EventService', 'ComponentsStrings']; - -function atForm () { - return { - restrict: 'E', - replace: true, - transclude: true, - require: ['atForm'], - templateUrl, - controller: AtFormController, - controllerAs: 'vm', - link: atFormLink, - scope: { - state: '=', - autocomplete: '@' - } - }; -} - -export default atForm; diff --git a/awx/ui/client/lib/components/form/form.partial.html b/awx/ui/client/lib/components/form/form.partial.html deleted file mode 100644 index dbfbd6cae54d..000000000000 --- a/awx/ui/client/lib/components/form/form.partial.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
-
- -
-
- - -
diff --git a/awx/ui/client/lib/components/index.js b/awx/ui/client/lib/components/index.js deleted file mode 100644 index 35b0e0193da6..000000000000 --- a/awx/ui/client/lib/components/index.js +++ /dev/null @@ -1,86 +0,0 @@ -import atLibServices from '~services'; - -import actionGroup from '~components/action/action-group.directive'; -import divider from '~components/utility/divider.directive'; -import form from '~components/form/form.directive'; -import formAction from '~components/form/action.directive'; -import inputCheckbox from '~components/input/checkbox.directive'; -import inputFile from '~components/input/file.directive'; -import inputGroup from '~components/input/group.directive'; -import inputLabel from '~components/input/label.directive'; -import inputLookup from '~components/input/lookup.directive'; -import inputMessage from '~components/input/message.directive'; -import inputSecret from '~components/input/secret.directive'; -import inputSelect from '~components/input/select.directive'; -import inputSlider from '~components/input/slider.directive'; -import inputText from '~components/input/text.directive'; -import inputTextarea from '~components/input/textarea.directive'; -import inputTextareaSecret from '~components/input/textarea-secret.directive'; -import launchTemplate from '~components/launchTemplateButton/launchTemplateButton.component'; -import layout from '~components/layout/layout.directive'; -import list from '~components/list/list.directive'; -import modal from '~components/modal/modal.directive'; -import panel from '~components/panel/panel.directive'; -import panelBody from '~components/panel/body.directive'; -import panelHeading from '~components/panel/heading.directive'; -import popover from '~components/popover/popover.directive'; -import relaunch from '~components/relaunchButton/relaunchButton.component'; -import row from '~components/list/row.directive'; -import rowItem from '~components/list/row-item.directive'; -import rowAction from '~components/list/row-action.directive'; -import sideNav from '~components/layout/side-nav.directive'; -import sideNavItem from '~components/layout/side-nav-item.directive'; -import tab from '~components/tabs/tab.directive'; -import tabGroup from '~components/tabs/group.directive'; -import topNavItem from '~components/layout/top-nav-item.directive'; -import truncate from '~components/truncate/truncate.directive'; -import atCodeMirror from '~components/code-mirror'; - -import BaseInputController from '~components/input/base.controller'; -import ComponentsStrings from '~components/components.strings'; - -const MODULE_NAME = 'at.lib.components'; - -angular - .module(MODULE_NAME, [ - atLibServices, - atCodeMirror - ]) - .directive('atActionGroup', actionGroup) - .directive('atDivider', divider) - .directive('atForm', form) - .directive('atFormAction', formAction) - .directive('atInputCheckbox', inputCheckbox) - .directive('atInputFile', inputFile) - .directive('atInputGroup', inputGroup) - .directive('atInputLabel', inputLabel) - .directive('atInputLookup', inputLookup) - .directive('atInputMessage', inputMessage) - .directive('atInputSecret', inputSecret) - .directive('atInputSelect', inputSelect) - .directive('atInputSlider', inputSlider) - .directive('atInputText', inputText) - .directive('atInputTextarea', inputTextarea) - .directive('atInputTextareaSecret', inputTextareaSecret) - .component('atLaunchTemplate', launchTemplate) - .directive('atLayout', layout) - .directive('atList', list) - .component('atRelaunch', relaunch) - .directive('atRow', row) - .directive('atRowItem', rowItem) - .directive('atRowAction', rowAction) - .directive('atModal', modal) - .directive('atPanel', panel) - .directive('atPanelBody', panelBody) - .directive('atPanelHeading', panelHeading) - .directive('atPopover', popover) - .directive('atSideNav', sideNav) - .directive('atSideNavItem', sideNavItem) - .directive('atTab', tab) - .directive('atTabGroup', tabGroup) - .directive('atTopNavItem', topNavItem) - .directive('atTruncate', truncate) - .service('BaseInputController', BaseInputController) - .service('ComponentsStrings', ComponentsStrings); - -export default MODULE_NAME; diff --git a/awx/ui/client/lib/components/input/_index.less b/awx/ui/client/lib/components/input/_index.less deleted file mode 100644 index 4867ea2242e6..000000000000 --- a/awx/ui/client/lib/components/input/_index.less +++ /dev/null @@ -1,274 +0,0 @@ -.at-Input { - .at-mixin-Placeholder(@at-color-input-placeholder); - - height: @at-height-input; - background: @at-color-input-background; - border-radius: @at-border-radius; - color: @at-color-input-text; - padding: 0 @at-padding-input; - - &, &:active { - border-color: @at-color-input-border; - } - - &:focus { - border-color: @at-color-input-focus; - } - - &[readonly] { - background: @at-color-input-readonly; - } - - &[disabled] { - background: @at-color-input-disabled; - } -} - -.at-InputCheckbox { - margin: 0; - padding: 0; - - & > label { - & > input[type=checkbox] { - height: @at-height-input; - margin: 0; - padding: 0; - } - - & > p { - margin: 0; - padding: 0 0 0 @at-padding-panel; - line-height: @at-line-height-tall; - } - } -} - -.at-InputContainer { - margin-top: @at-margin-panel; -} - -.at-Input-button { - .at-mixin-InputButton(); -} - -.at-Input-button--fixed-xs { - .at-mixin-InputButton(); - min-width: @at-width-input-button-sm; - height: @at-height-input; -} - -.at-Input-button--fixed-sm { - .at-mixin-InputButton(); - min-width: @at-width-input-button-md; - height: @at-height-input; -} - -.at-Input-button--fixed-md { - .at-mixin-InputButton(); - display: inherit; - min-width: @at-width-input-button-md; - height: @at-height-textarea; -} - -.at-Input-button--active { - .at-mixin-ButtonColor(at-color-info, at-color-default); -} - -.at-Input--focus { - border-color: @at-color-input-focus; -} - -.at-Input--rejected { - &, &:focus { - border-color: @at-color-input-error; - } -} - -.at-InputFile--hidden { - position: absolute; - height: 100%; - width: 100%; - left: 0; - z-index: -2; - opacity: 0; -} - -.at-InputFile--drag { - z-index: 3; -} - -.at-InputGroup { - padding: 0; - margin: @at-margin-panel 0 0 0; -} - -.at-InputGroup-border { - position: absolute; - width: 5px; - height: 100%; - background: @at-color-panel-border; - left: -5px; -} - -.at-InputGroup-title { - .at-mixin-Heading(@at-font-size-panel-inset-heading); - margin: 0 0 0 @at-margin-panel-inset; -} - -.at-InputGroup-divider { - clear: both; - margin: 0; - padding: 0; - height: @at-height-divider; -} - -.at-InputLabel { - display: inline-block; - width: 100%; -} - -.at-InputLabel-name { - color: @at-color-form-label; - font-size: @at-font-size-form-label; - font-weight: @at-font-weight-body; - text-transform: uppercase; -} - -.at-InputLabel-hint { - margin-left: @at-margin-form-label-hint; - color: @at-color-input-hint; - font-size: @at-font-size-help-text; - font-weight: @at-font-weight-body; - line-height: @at-line-height-short; -} - -.at-InputLabel-checkbox { - margin: 0; - padding: 0; -} - -.at-InputLabel-checkboxLabel { - margin-bottom: 0; - - & > input[type=checkbox] { - margin: 0 3px 0 0; - } - - & > p { - font-size: @at-font-size-help-text; - color: @at-color-form-label; - font-weight: @at-font-weight-body; - display: inline; - margin: 0; - padding: 0; - } -} - -.at-InputMessage--rejected { - font-size: @at-font-size-help-text; - color: @at-color-error; - margin: @at-margin-input-message 0 0 0; - padding: 0; -} - -.at-InputLabel-required { - color: @at-color-error; - font-weight: @at-font-weight-heading; - font-size: @at-font-size-form-label; - margin: 0; -} - -.at-InputSelect { - position: relative; - width: 100%; - - & > i { - font-size: @at-font-size-button; - position: absolute; - z-index: 3; - pointer-events: none; - top: @at-height-input / 3; - right: @at-height-input / 3; - color: @at-color-input-icon; - } -} - -.at-InputSelect-input { - position: relative; - z-index: 2; - pointer-events: none; -} - -.at-InputSelect-select { - height: @at-height-input; - cursor: pointer; - position: absolute; - z-index: 1; - top: 0; - - & > optgroup { - text-transform: uppercase; - - & > option { - text-transform: none; - } - } -} - -.at-InputTextarea { - .at-mixin-FontFixedWidth(); - min-height: @at-height-textarea; - padding: 6px @at-padding-input 0 @at-padding-input; -} - -.at-InputSlider { - display: flex; - padding: 5px 0; - - p { - color: @at-color-form-label; - font-size: @at-font-size-help-text; - font-weight: @at-font-weight-body; - margin: 0 0 0 10px; - padding: 0; - width: 50px; - } - - input[type=range] { - -webkit-appearance: none; - width: 100%; - background: transparent; - height: 20px; - border-right: 1px solid @at-color-input-slider-track; - border-left: 1px solid @at-color-input-slider-track; - - &:focus { - outline: none; - } - - &::-webkit-slider-runnable-track { - background: @at-color-input-slider-track; - cursor: pointer; - height: 1px; - width: 100%; - } - &::-webkit-slider-thumb { - -webkit-appearance: none; - background: @at-color-input-slider-thumb; - border-radius: 50%; - border: none; - cursor: pointer; - height: 16px; - margin-top: -7px; - width: 16px; - } - } - - input[type=range][disabled] { - &::-webkit-slider-thumb { - background: @at-color-disabled; - border: solid 1px @at-color-disabled; - cursor: not-allowed; - } - } -} diff --git a/awx/ui/client/lib/components/input/base.controller.js b/awx/ui/client/lib/components/input/base.controller.js deleted file mode 100644 index 32fa30b458d5..000000000000 --- a/awx/ui/client/lib/components/input/base.controller.js +++ /dev/null @@ -1,130 +0,0 @@ -function BaseInputController (strings) { - // Default values are universal. Don't translate. - const PROMPT_ON_LAUNCH_VALUE = 'ASK'; - const ENCRYPTED_VALUE = '$encrypted$'; - - return function extend (type, scope, element, form) { - const vm = this; - - vm.strings = strings; - - scope.state = scope.state || {}; - - scope.state._touched = false; - scope.state._required = scope.state.required || false; - scope.state._isValid = scope.state._isValid || false; - scope.state._disabled = scope.state._disabled || false; - scope.state._activeModel = scope.state._activeModel || '_value'; - - if (scope.state.ask_at_runtime) { - scope.state._displayPromptOnLaunch = true; - } - - if (scope.state._value) { - scope.state._edit = true; - scope.state._preEditValue = scope.state._value; - - if (scope.state._value === PROMPT_ON_LAUNCH_VALUE) { - scope.state._promptOnLaunch = true; - scope.state._disabled = true; - scope.state._activeModel = '_displayValue'; - } - - if (scope.state._value === ENCRYPTED_VALUE) { - scope.state._displayRevertReplace = true; - scope.state._enableToggle = true; - scope.state._disabled = true; - scope.state._isBeingReplaced = false; - scope.state._activeModel = '_displayValue'; - } - } - - form.register(type, scope); - - vm.validate = () => { - let isValid = true; - let message = ''; - - if (scope.state._value || scope.state._displayValue) { - scope.state._touched = true; - } - - if (scope.state._required && (!scope.state._value || !scope.state._value[0]) && - !scope.state._displayValue) { - isValid = false; - message = vm.strings.get('message.REQUIRED_INPUT_MISSING'); - } else if (scope.state._validate) { - const result = scope.state._validate(scope.state._value); - - if (!result.isValid) { - isValid = false; - message = result.message || vm.strings.get('message.INVALID_INPUT'); - } - } - - return { - isValid, - message - }; - }; - - vm.updateValidationState = result => { - if (!scope.state._touched && scope.state._required) { - return; - } - - scope.state._rejected = !result.isValid; - scope.state._isValid = result.isValid; - scope.state._message = result.message; - - form.check(); - }; - - vm.check = result => { - result = result || vm.validate(); - - vm.updateValidationState(result); - }; - - vm.onRevertReplaceToggle = () => { - if (!scope.state._isBeingReplaced) { - scope.state._buttonText = vm.strings.get('REPLACE'); - scope.state._disabled = true; - scope.state._enableToggle = true; - scope.state._value = scope.state._preEditValue; - scope.state._activeModel = '_displayValue'; - scope.state._placeholder = vm.strings.get('ENCRYPTED'); - } else { - scope.state._buttonText = vm.strings.get('REVERT'); - scope.state._disabled = false; - scope.state._enableToggle = false; - scope.state._activeModel = '_value'; - scope.state._value = ''; - scope.state._placeholder = ''; - } - }; - - vm.togglePromptOnLaunch = () => { - if (scope.state._promptOnLaunch) { - scope.state._value = PROMPT_ON_LAUNCH_VALUE; - scope.state._activeModel = '_displayValue'; - scope.state._disabled = true; - scope.state._enableToggle = false; - } else if (scope.state._isBeingReplaced === false) { - scope.state._disabled = true; - scope.state._enableToggle = true; - scope.state._value = scope.state._preEditValue; - } else { - scope.state._activeModel = '_value'; - scope.state._disabled = false; - scope.state._value = ''; - } - - vm.check(); - }; - }; -} - -BaseInputController.$inject = ['ComponentsStrings']; - -export default BaseInputController; diff --git a/awx/ui/client/lib/components/input/checkbox.directive.js b/awx/ui/client/lib/components/input/checkbox.directive.js deleted file mode 100644 index 00fcdcf05c71..000000000000 --- a/awx/ui/client/lib/components/input/checkbox.directive.js +++ /dev/null @@ -1,46 +0,0 @@ -const templateUrl = require('~components/input/checkbox.partial.html'); - -function atInputCheckboxLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputCheckboxController (baseInputController) { - const vm = this || {}; - - vm.init = (scope, element, form) => { - baseInputController.call(vm, 'input', scope, element, form); - scope.label = scope.state.label; - scope.state.label = vm.strings.get('OPTIONS'); - - vm.check(); - }; -} - -AtInputCheckboxController.$inject = ['BaseInputController']; - -function atInputCheckbox () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputCheckbox'], - templateUrl, - controller: AtInputCheckboxController, - controllerAs: 'vm', - link: atInputCheckboxLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputCheckbox; diff --git a/awx/ui/client/lib/components/input/checkbox.partial.html b/awx/ui/client/lib/components/input/checkbox.partial.html deleted file mode 100644 index df171e5cb593..000000000000 --- a/awx/ui/client/lib/components/input/checkbox.partial.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- -
- -
- -
-
diff --git a/awx/ui/client/lib/components/input/file.directive.js b/awx/ui/client/lib/components/input/file.directive.js deleted file mode 100644 index 42aa2c4fba1c..000000000000 --- a/awx/ui/client/lib/components/input/file.directive.js +++ /dev/null @@ -1,94 +0,0 @@ -const templateUrl = require('~components/input/file.partial.html'); - -function atInputFileLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputFileController (baseInputController, eventService) { - const vm = this || {}; - - let input; - let scope; - - vm.init = (_scope_, element, form) => { - baseInputController.call(vm, 'input', _scope_, element, form); - - scope = _scope_; - input = element.find('input')[0]; // eslint-disable-line prefer-destructuring - - vm.listeners = vm.setFileListeners(input); - - vm.check(); - }; - - vm.onButtonClick = () => { - if (scope.state._value) { - vm.removeFile(); - } else { - input.click(); - } - }; - - vm.setFileListeners = inputEl => eventService.addListeners([ - [inputEl, 'change', event => vm.handleFileChangeEvent(inputEl, event)] - ]); - - vm.handleFileChangeEvent = (element, event) => { - if (element.files.length > 0) { - const reader = new FileReader(); - - reader.onload = () => vm.readFile(reader, event); - reader.readAsText(element.files[0]); - } else { - scope.$apply(vm.removeFile); - } - }; - - vm.readFile = (reader, event) => { - scope.$apply(() => { - scope.state._value = reader.result; - scope.state._displayValue = event.target.files[0].name; - - vm.check(); - }); - }; - - vm.removeFile = () => { - delete scope.state._value; - delete scope.state._displayValue; - - input.value = ''; - }; -} - -AtInputFileController.$inject = [ - 'BaseInputController', - 'EventService' -]; - -function atInputFile () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputFile'], - templateUrl, - controller: AtInputFileController, - controllerAs: 'vm', - link: atInputFileLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputFile; diff --git a/awx/ui/client/lib/components/input/file.partial.html b/awx/ui/client/lib/components/input/file.partial.html deleted file mode 100644 index 7e13fcc47edb..000000000000 --- a/awx/ui/client/lib/components/input/file.partial.html +++ /dev/null @@ -1,25 +0,0 @@ -
-
- - -
- - - - -
- -
-
diff --git a/awx/ui/client/lib/components/input/group.directive.js b/awx/ui/client/lib/components/input/group.directive.js deleted file mode 100644 index 7e6f1f2426af..000000000000 --- a/awx/ui/client/lib/components/input/group.directive.js +++ /dev/null @@ -1,191 +0,0 @@ -const templateUrl = require('~components/input/group.partial.html'); - -function atInputGroupLink (scope, el, attrs, controllers) { - const groupController = controllers[0]; - const formController = controllers[1]; - const element = el[0].getElementsByClassName('at-InputGroup-container')[0]; - - groupController.init(scope, formController, element); -} - -function AtInputGroupController ($scope, $compile) { - const vm = this || {}; - - let form; - let scope; - let state; - let source; - let element; - - vm.init = (_scope_, _form_, _element_) => { - form = _form_; - scope = _scope_; - element = _element_; - state = scope.state || {}; - source = state._source; - - $scope.$watch('state._source._value', vm.update); - }; - - vm.isValidSource = () => { - if (!source._value || source._value === state._value) { - return false; - } - - return true; - }; - - vm.update = () => { - if (state._group) { - vm.clear(); - } - - if (!vm.isValidSource()) { - return; - } - - state._value = source._value; - - const inputs = state._get(source._value); - const group = vm.createComponentConfigs(inputs); - - vm.insert(group); - state._group = group; - }; - - vm.createComponentConfigs = inputs => { - const group = []; - - if (inputs) { - inputs.forEach((input, i) => { - input = Object.assign(input, vm.getComponentType(input)); - - group.push(Object.assign({ - _element: vm.createComponent(input, i), - _key: 'inputs', - _group: true, - _groupIndex: i - }, input)); - }); - } - - return group; - }; - - vm.getComponentType = input => { - const config = {}; - - if (input.type === 'string') { - if (!input.multiline) { - if (input.secret) { - config._component = 'at-input-secret'; - } else { - config._component = 'at-input-text'; - } - } else { - config._expand = true; - - if (input.secret) { - config._component = 'at-input-textarea-secret'; - } else { - config._component = 'at-input-textarea'; - } - } - - if (input.format === 'ssh_private_key') { - config._format = 'ssh-key'; - } - } else if (input.type === 'number') { - config._component = 'at-input-number'; - } else if (input.type === 'boolean') { - config._component = 'at-input-checkbox'; - } else if (input.type === 'file') { - config._component = 'at-input-file'; - } else if (input.choices) { - config._component = 'at-input-select'; - config._format = 'array'; - config._data = input.choices; - config._exp = 'choice for (index, choice) in state._data'; - } else { - const preface = vm.strings.get('group.UNSUPPORTED_ERROR_PREFACE'); - throw new Error(`${preface}: ${input.type}`); - } - - return config; - }; - - vm.insert = group => { - const container = document.createElement('div'); - let col = 1; - const colPerRow = 12 / scope.col; - let isDivided = true; - - group.forEach((input, i) => { - if (input._expand && !isDivided) { - container.appendChild(vm.createDivider()[0]); - } - - container.appendChild(input._element[0]); - - if ((input._expand || col % colPerRow === 0) && i !== group.length - 1) { - container.appendChild(vm.createDivider()[0]); - isDivided = true; - col = 0; - } else { - isDivided = false; - } - - col++; - }); - - element.appendChild(container); - }; - - vm.createComponent = (input, index) => { - const tabindex = Number(scope.tab) + index; - const col = input._expand ? 12 : scope.col; - const component = angular.element(`<${input._component} col="${col}" tab="${tabindex}" - state="${state._reference}._group[${index}]"> - `); - - $compile(component)(scope.$parent); - - return component; - }; - - vm.createDivider = () => { - const divider = angular.element(''); - $compile(divider[0])(scope.$parent); - - return divider; - }; - - vm.clear = () => { - form.deregisterInputGroup(state._group); - element.innerHTML = ''; - state._group = undefined; - state._value = undefined; - }; -} - -AtInputGroupController.$inject = ['$scope', '$compile']; - -function atInputGroup () { - return { - restrict: 'E', - replace: true, - transclude: true, - require: ['atInputGroup', '^^atForm'], - templateUrl, - controller: AtInputGroupController, - controllerAs: 'vm', - link: atInputGroupLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputGroup; diff --git a/awx/ui/client/lib/components/input/group.partial.html b/awx/ui/client/lib/components/input/group.partial.html deleted file mode 100644 index 45d4a845e0d6..000000000000 --- a/awx/ui/client/lib/components/input/group.partial.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
-
-
-
-

- -

-
-
-
-
-
diff --git a/awx/ui/client/lib/components/input/label.directive.js b/awx/ui/client/lib/components/input/label.directive.js deleted file mode 100644 index ea1fafd23a57..000000000000 --- a/awx/ui/client/lib/components/input/label.directive.js +++ /dev/null @@ -1,11 +0,0 @@ -const templateUrl = require('~components/input/label.partial.html'); - -function atInputLabel () { - return { - restrict: 'E', - replace: true, - templateUrl - }; -} - -export default atInputLabel; diff --git a/awx/ui/client/lib/components/input/label.partial.html b/awx/ui/client/lib/components/input/label.partial.html deleted file mode 100644 index c8d4802ffd04..000000000000 --- a/awx/ui/client/lib/components/input/label.partial.html +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/awx/ui/client/lib/components/input/lookup.directive.js b/awx/ui/client/lib/components/input/lookup.directive.js deleted file mode 100644 index 0447d6b44881..000000000000 --- a/awx/ui/client/lib/components/input/lookup.directive.js +++ /dev/null @@ -1,151 +0,0 @@ -const templateUrl = require('~components/input/lookup.partial.html'); - -const DEFAULT_DEBOUNCE = 250; -const DEFAULT_KEY = 'name'; - -function atInputLookupLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputLookupController (baseInputController, $q, $state) { - const vm = this || {}; - - let scope; - let model; - let search; - - vm.init = (_scope_, element, form) => { - baseInputController.call(vm, 'input', _scope_, element, form); - - scope = _scope_; - model = scope.state._model; - scope.state._debounce = scope.state._debounce || DEFAULT_DEBOUNCE; - search = scope.state._search || { - key: DEFAULT_KEY, - config: { - unique: true - } - }; - - scope.$watch(scope.state._resource, vm.watchResource); - - vm.check(); - }; - - vm.watchResource = () => { - if (!scope[scope.state._resource]) { - return; - } - - if (scope[scope.state._resource] !== scope.state._value) { - scope.state._displayValue = scope[`${scope.state._resource}_name`]; - - vm.search(); - } - }; - - vm.lookup = () => { - const params = {}; - - if (scope.state._value && scope.state._isValid) { - params.selected = scope.state._value; - } - - $state.go(scope.state._route, params); - }; - - vm.reset = () => { - scope.state._value = undefined; - scope[scope.state._resource] = undefined; - }; - - vm.searchAfterDebounce = () => { - vm.isDebouncing = true; - - vm.debounce = window.setTimeout(() => { - vm.isDebouncing = false; - vm.search(); - }, scope.state._debounce); - }; - - vm.resetDebounce = () => { - clearTimeout(vm.debounce); - vm.searchAfterDebounce(); - }; - - vm.search = () => { - scope.state._touched = true; - - if (scope.state._displayValue === '' && !scope.state._required) { - scope.state._value = null; - return vm.check({ isValid: true }); - } - - return model.search({ [search.key]: scope.state._displayValue }, search.config) - .then(found => { - if (!found) { - vm.reset(); - - return; - } - - scope[scope.state._resource] = model.get('id'); - scope.state._value = model.get('id'); - scope.state._displayValue = model.get('name'); - }) - .catch(() => vm.reset()) - .finally(() => { - const isValid = scope.state._value !== undefined; - const message = isValid ? '' : vm.strings.get('lookup.NOT_FOUND'); - - vm.check({ isValid, message }); - }); - }; - - vm.searchOnInput = () => { - if (vm.isDebouncing) { - vm.resetDebounce(); - - return; - } - - vm.searchAfterDebounce(); - }; - - vm.removeTag = (tagToRemove) => { - _.remove(scope.state._value, (tag) => tag === tagToRemove); - }; -} - -AtInputLookupController.$inject = [ - 'BaseInputController', - '$q', - '$state' -]; - -function atInputLookup () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputLookup'], - templateUrl, - controller: AtInputLookupController, - controllerAs: 'vm', - link: atInputLookupLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputLookup; diff --git a/awx/ui/client/lib/components/input/lookup.partial.html b/awx/ui/client/lib/components/input/lookup.partial.html deleted file mode 100644 index 88cd218e9c40..000000000000 --- a/awx/ui/client/lib/components/input/lookup.partial.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
- - -
- - - - - - -
-
- {{ tag.hostname }} - {{ tag }} -
-
- -
-
-
-
- - -
- -
-
\ No newline at end of file diff --git a/awx/ui/client/lib/components/input/message.directive.js b/awx/ui/client/lib/components/input/message.directive.js deleted file mode 100644 index 6e4dba6da344..000000000000 --- a/awx/ui/client/lib/components/input/message.directive.js +++ /dev/null @@ -1,11 +0,0 @@ -const templateUrl = require('~components/input/message.partial.html'); - -function atInputMessage () { - return { - restrict: 'E', - replace: true, - templateUrl - }; -} - -export default atInputMessage; diff --git a/awx/ui/client/lib/components/input/message.partial.html b/awx/ui/client/lib/components/input/message.partial.html deleted file mode 100644 index cb73ab962022..000000000000 --- a/awx/ui/client/lib/components/input/message.partial.html +++ /dev/null @@ -1,4 +0,0 @@ -

- {{ state._message }} -

- diff --git a/awx/ui/client/lib/components/input/secret.directive.js b/awx/ui/client/lib/components/input/secret.directive.js deleted file mode 100644 index 01b16d412b99..000000000000 --- a/awx/ui/client/lib/components/input/secret.directive.js +++ /dev/null @@ -1,77 +0,0 @@ -const templateUrl = require('~components/input/secret.partial.html'); - -function atInputSecretLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputSecretController (baseInputController) { - const vm = this || {}; - - let scope; - - vm.init = (_scope_, element, form) => { - baseInputController.call(vm, 'input', _scope_, element, form); - - scope = _scope_; - scope.type = 'password'; - - if (!scope.state._value || scope.state._promptOnLaunch) { - scope.mode = 'input'; - scope.state._buttonText = vm.strings.get('SHOW'); - - vm.toggle = vm.toggleShowHide; - } else { - scope.mode = 'encrypted'; - scope.state._buttonText = vm.strings.get('REPLACE'); - scope.state._placeholder = vm.strings.get('ENCRYPTED'); - vm.toggle = vm.toggleRevertReplace; - } - - vm.check(); - }; - - vm.toggleRevertReplace = () => { - scope.state._isBeingReplaced = !scope.state._isBeingReplaced; - - vm.onRevertReplaceToggle(); - }; - - vm.toggleShowHide = () => { - if (scope.type === 'password') { - scope.type = 'text'; - scope.state._buttonText = vm.strings.get('HIDE'); - } else { - scope.type = 'password'; - scope.state._buttonText = vm.strings.get('SHOW'); - } - }; -} - -AtInputSecretController.$inject = ['BaseInputController']; - -function atInputSecret () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputSecret'], - templateUrl, - controller: AtInputSecretController, - controllerAs: 'vm', - link: atInputSecretLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputSecret; diff --git a/awx/ui/client/lib/components/input/secret.partial.html b/awx/ui/client/lib/components/input/secret.partial.html deleted file mode 100644 index 2c1523e7e613..000000000000 --- a/awx/ui/client/lib/components/input/secret.partial.html +++ /dev/null @@ -1,30 +0,0 @@ -
-
- - -
- - - - -
- - -
-
diff --git a/awx/ui/client/lib/components/input/select.directive.js b/awx/ui/client/lib/components/input/select.directive.js deleted file mode 100644 index ddc0e23766e7..000000000000 --- a/awx/ui/client/lib/components/input/select.directive.js +++ /dev/null @@ -1,96 +0,0 @@ -const templateUrl = require('~components/input/select.partial.html'); - -function atInputSelectLink (scope, element, attrs, controllers) { - const [formController, inputController] = controllers; - - inputController.init(scope, element, formController); -} - -function AtInputSelectController (baseInputController, eventService) { - const vm = this || {}; - - let scope; - let element; - let input; - let select; - - vm.init = (_scope_, _element_, form) => { - baseInputController.call(vm, 'input', _scope_, _element_, form); - - scope = _scope_; - element = _element_; - [input] = element.find('input'); - [select] = element.find('select'); - - if (scope.tab === '1') { - select.focus(); - } - - if (!scope.state._data || scope.state._data.length === 0) { - scope.state._disabled = true; - scope.state._placeholder = vm.strings.get('select.EMPTY_PLACEHOLDER'); - } - - vm.setListeners(); - vm.check(); - - if (scope.state._value) { - vm.updateDisplayModel(); - } - }; - - vm.setListeners = () => { - const listeners = eventService.addListeners([ - [input, 'focus', () => select.focus], - [select, 'mousedown', () => scope.$apply(() => { scope.open = !scope.open; })], - [select, 'focus', () => input.classList.add('at-Input--focus')], - [select, 'change', () => scope.$apply(() => { - scope.open = false; - vm.updateDisplayModel(); - vm.check(); - })], - [select, 'blur', () => { - input.classList.remove('at-Input--focus'); - scope.open = scope.open && false; - }] - ]); - - scope.$on('$destroy', () => eventService.remove(listeners)); - }; - - vm.updateDisplayModel = () => { - if (scope.state._format === 'selectFromOptions') { - scope.displayModel = scope.state._value[1]; - } else if (scope.state._format === 'array') { - scope.displayModel = scope.state._value; - } else if (scope.state._format === 'objects') { - scope.displayModel = scope.state._value[scope.state._display]; - } else if (scope.state._format === 'grouped-object') { - scope.displayModel = scope.state._value[scope.state._display]; - } else { - throw new Error(vm.strings.get('select.UNSUPPORTED_TYPE_ERROR')); - } - }; -} - -AtInputSelectController.$inject = ['BaseInputController', 'EventService']; - -function atInputSelect () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^at-form', 'atInputSelect'], - templateUrl, - controller: AtInputSelectController, - controllerAs: 'vm', - link: atInputSelectLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputSelect; diff --git a/awx/ui/client/lib/components/input/select.partial.html b/awx/ui/client/lib/components/input/select.partial.html deleted file mode 100644 index f3ba5e845a48..000000000000 --- a/awx/ui/client/lib/components/input/select.partial.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- - -
- - - - - -
- - -
-
diff --git a/awx/ui/client/lib/components/input/slider.directive.js b/awx/ui/client/lib/components/input/slider.directive.js deleted file mode 100644 index a2e1b8c28e47..000000000000 --- a/awx/ui/client/lib/components/input/slider.directive.js +++ /dev/null @@ -1,38 +0,0 @@ -const templateUrl = require('~components/input/slider.partial.html'); - -function atInputSliderLink (scope, element, attrs, controllers) { - const [formController, inputController] = controllers; - - inputController.init(scope, element, formController); -} - -function atInputSliderController (baseInputController) { - const vm = this || {}; - - vm.init = (_scope_, _element_, form) => { - baseInputController.call(vm, 'input', _scope_, _element_, form); - - vm.check(); - }; -} - -atInputSliderController.$inject = ['BaseInputController']; - -function atInputSlider () { - return { - restrict: 'E', - require: ['^^atForm', 'atInputSlider'], - replace: true, - templateUrl, - controller: atInputSliderController, - controllerAs: 'vm', - link: atInputSliderLink, - scope: { - state: '=?', - col: '@', - tab: '@' - } - }; -} - -export default atInputSlider; diff --git a/awx/ui/client/lib/components/input/slider.partial.html b/awx/ui/client/lib/components/input/slider.partial.html deleted file mode 100644 index e07abdadfacd..000000000000 --- a/awx/ui/client/lib/components/input/slider.partial.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
- -
- -

{{ state._value }}%

-
-
-
diff --git a/awx/ui/client/lib/components/input/text.directive.js b/awx/ui/client/lib/components/input/text.directive.js deleted file mode 100644 index d28f4c2640e2..000000000000 --- a/awx/ui/client/lib/components/input/text.directive.js +++ /dev/null @@ -1,48 +0,0 @@ -const templateUrl = require('~components/input/text.partial.html'); - -function atInputTextLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputTextController (baseInputController) { - const vm = this || {}; - - let scope; - - vm.init = (_scope_, element, form) => { - baseInputController.call(vm, 'input', _scope_, element, form); - scope = _scope_; - - vm.check(); - scope.$watch('state._value', () => vm.check()); - }; -} - -AtInputTextController.$inject = ['BaseInputController']; - -function atInputText () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputText'], - templateUrl, - controller: AtInputTextController, - controllerAs: 'vm', - link: atInputTextLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputText; diff --git a/awx/ui/client/lib/components/input/text.partial.html b/awx/ui/client/lib/components/input/text.partial.html deleted file mode 100644 index 8a1a22137e76..000000000000 --- a/awx/ui/client/lib/components/input/text.partial.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
- - - - - -
-
diff --git a/awx/ui/client/lib/components/input/textarea-secret.directive.js b/awx/ui/client/lib/components/input/textarea-secret.directive.js deleted file mode 100644 index 2bcbe027d5f7..000000000000 --- a/awx/ui/client/lib/components/input/textarea-secret.directive.js +++ /dev/null @@ -1,121 +0,0 @@ -const templateUrl = require('~components/input/textarea-secret.partial.html'); - -function atInputTextareaSecretLink (scope, element, attrs, controllers) { - const [formController, inputController] = controllers; - - if (scope.tab === '1') { - element.find('textarea')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputTextareaSecretController (baseInputController, eventService) { - const vm = this || {}; - - let scope; - let textarea; - let input; - - vm.init = (_scope_, element, form) => { - baseInputController.call(vm, 'input', _scope_, element, form); - - scope = _scope_; - - [textarea] = element.find('textarea'); - - if (scope.state.format === 'ssh_private_key') { - scope.ssh = true; - scope.state._hint = scope.state._hint || vm.strings.get('textarea.SSH_KEY_HINT'); - [input] = element.find('input'); - } - - if (scope.state._value) { - scope.state._buttonText = vm.strings.get('REPLACE'); - scope.state._placeholder = vm.strings.get('ENCRYPTED'); - } else if (scope.state.format === 'ssh_private_key') { - vm.listeners = vm.setFileListeners(textarea, input); - scope.state._displayHint = true; - } - - vm.check(); - - scope.$watch('state[state._activeModel]', () => vm.check()); - scope.$watch('state._isBeingReplaced', () => vm.onIsBeingReplacedChanged()); - }; - - vm.onIsBeingReplacedChanged = () => { - if (!scope.state._touched) return; - - vm.onRevertReplaceToggle(); - - if (scope.state._isBeingReplaced) { - scope.state._placeholder = ''; - scope.state._displayHint = true; - vm.listeners = vm.setFileListeners(textarea, input); - } else { - scope.state._displayHint = false; - scope.state._placeholder = vm.strings.get('ENCRYPTED'); - - if (vm.listeners) { - eventService.remove(vm.listeners); - } - } - }; - - vm.setFileListeners = (textareaEl, inputEl) => eventService.addListeners([ - [textareaEl, 'dragenter', event => { - event.stopPropagation(); - event.preventDefault(); - scope.$apply(() => { scope.drag = true; }); - }], - - [inputEl, 'dragleave', event => { - event.stopPropagation(); - event.preventDefault(); - scope.$apply(() => { scope.drag = false; }); - }], - - [inputEl, 'change', event => { - const reader = new FileReader(); - - reader.onload = () => vm.readFile(reader, event); - reader.readAsText(inputEl.files[0]); - }] - ]); - - vm.readFile = (reader) => { - scope.$apply(() => { - scope.state._value = reader.result; - vm.check(); - scope.drag = false; - input.value = ''; - }); - }; -} - -AtInputTextareaSecretController.$inject = [ - 'BaseInputController', - 'EventService', - 'ComponentsStrings' -]; - -function atInputTextareaSecret () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputTextareaSecret'], - templateUrl, - controller: AtInputTextareaSecretController, - controllerAs: 'vm', - link: atInputTextareaSecretLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputTextareaSecret; diff --git a/awx/ui/client/lib/components/input/textarea-secret.partial.html b/awx/ui/client/lib/components/input/textarea-secret.partial.html deleted file mode 100644 index e716cbf48d4c..000000000000 --- a/awx/ui/client/lib/components/input/textarea-secret.partial.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
- - -
-
- -
- - -
- - -
-
diff --git a/awx/ui/client/lib/components/input/textarea.directive.js b/awx/ui/client/lib/components/input/textarea.directive.js deleted file mode 100644 index d5ac607c5158..000000000000 --- a/awx/ui/client/lib/components/input/textarea.directive.js +++ /dev/null @@ -1,44 +0,0 @@ -const templateUrl = require('~components/input/textarea.partial.html'); - -function atInputTextareaLink (scope, element, attrs, controllers) { - const formController = controllers[0]; - const inputController = controllers[1]; - - if (scope.tab === '1') { - element.find('input')[0].focus(); - } - - inputController.init(scope, element, formController); -} - -function AtInputTextareaController (baseInputController) { - const vm = this || {}; - - vm.init = (scope, element, form) => { - baseInputController.call(vm, 'input', scope, element, form); - - vm.check(); - }; -} - -AtInputTextareaController.$inject = ['BaseInputController']; - -function atInputTextarea () { - return { - restrict: 'E', - transclude: true, - replace: true, - require: ['^^atForm', 'atInputTextarea'], - templateUrl, - controller: AtInputTextareaController, - controllerAs: 'vm', - link: atInputTextareaLink, - scope: { - state: '=', - col: '@', - tab: '@' - } - }; -} - -export default atInputTextarea; diff --git a/awx/ui/client/lib/components/input/textarea.partial.html b/awx/ui/client/lib/components/input/textarea.partial.html deleted file mode 100644 index bc0738dc9f22..000000000000 --- a/awx/ui/client/lib/components/input/textarea.partial.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- - - - - -
-
diff --git a/awx/ui/client/lib/components/launchTemplateButton/_index.less b/awx/ui/client/lib/components/launchTemplateButton/_index.less deleted file mode 100644 index f0d68bd3d8a7..000000000000 --- a/awx/ui/client/lib/components/launchTemplateButton/_index.less +++ /dev/null @@ -1,23 +0,0 @@ -.at-LaunchTemplate { - &--button { - font-size: 16px; - height: 30px; - min-width: 30px; - color: #848992; - background-color: inherit; - border: none; - border-radius: 5px; - } - - &--button:hover { - background-color: @at-blue; - color: white; - } -} - -.open { - .at-LaunchTemplate--button { - background-color: @at-blue; - color: white; - } -} diff --git a/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.component.js b/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.component.js deleted file mode 100644 index f8f6734c0e7b..000000000000 --- a/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.component.js +++ /dev/null @@ -1,154 +0,0 @@ -import templateUrl from './launchTemplateButton.partial.html'; - -const atLaunchTemplate = { - templateUrl, - bindings: { - template: '<' - }, - controller: ['JobTemplateModel', 'WorkflowJobTemplateModel', 'PromptService', '$state', - 'ComponentsStrings', 'ProcessErrors', '$scope', 'TemplatesStrings', 'Alert', - atLaunchTemplateCtrl], - controllerAs: 'vm' -}; - -function atLaunchTemplateCtrl ( - JobTemplate, WorkflowTemplate, PromptService, $state, - componentsStrings, ProcessErrors, $scope, templatesStrings, Alert -) { - const vm = this; - const jobTemplate = new JobTemplate(); - const workflowTemplate = new WorkflowTemplate(); - vm.strings = componentsStrings; - - const createErrorHandler = (path, action) => - ({ data, status }) => { - const hdr = templatesStrings.get('error.HEADER'); - const msg = templatesStrings.get('error.CALL', { path, action, status }); - ProcessErrors($scope, data, status, null, { hdr, msg }); - }; - - vm.startLaunchTemplate = () => { - if (vm.template.type === 'job_template') { - const selectedJobTemplate = jobTemplate.create(); - const preLaunchPromises = [ - selectedJobTemplate.getLaunch(vm.template.id), - selectedJobTemplate.optionsLaunch(vm.template.id), - ]; - - Promise.all(preLaunchPromises) - .then(([launchData, launchOptions]) => { - if (selectedJobTemplate.canLaunchWithoutPrompt()) { - selectedJobTemplate - .postLaunch({ id: vm.template.id }) - .then(({ data }) => { - $state.go('output', { id: data.job, type: 'playbook' }, { reload: true }); - }); - } else { - const promptData = { - launchConf: launchData.data, - launchOptions: launchOptions.data, - template: vm.template.id, - templateType: vm.template.type, - prompts: PromptService.processPromptValues({ - launchConf: launchData.data, - launchOptions: launchOptions.data - }), - triggerModalOpen: true - }; - - if (launchData.data.survey_enabled) { - selectedJobTemplate.getSurveyQuestions(vm.template.id) - .then(({ data }) => { - const processed = PromptService.processSurveyQuestions({ - surveyQuestions: data.spec - }); - promptData.surveyQuestions = processed.surveyQuestions; - vm.promptData = promptData; - }); - } else { - vm.promptData = promptData; - } - } - }); - } else if (vm.template.type === 'workflow_job_template') { - const selectedWorkflowJobTemplate = workflowTemplate.create(); - const preLaunchPromises = [ - selectedWorkflowJobTemplate.getLaunch(vm.template.id), - selectedWorkflowJobTemplate.optionsLaunch(vm.template.id), - ]; - - Promise.all(preLaunchPromises) - .then(([launchData, launchOptions]) => { - if (selectedWorkflowJobTemplate.canLaunchWithoutPrompt()) { - selectedWorkflowJobTemplate - .postLaunch({ id: vm.template.id }) - .then(({ data }) => { - $state.go('workflowResults', { id: data.workflow_job }, { reload: true }); - }); - } else { - const promptData = { - launchConf: launchData.data, - launchOptions: launchOptions.data, - template: vm.template.id, - templateType: vm.template.type, - prompts: PromptService.processPromptValues({ - launchConf: launchData.data, - launchOptions: launchOptions.data - }), - triggerModalOpen: true, - }; - - if (launchData.data.survey_enabled) { - selectedWorkflowJobTemplate.getSurveyQuestions(vm.template.id) - .then(({ data }) => { - const processed = PromptService.processSurveyQuestions({ - surveyQuestions: data.spec - }); - promptData.surveyQuestions = processed.surveyQuestions; - vm.promptData = promptData; - }); - } else { - vm.promptData = promptData; - } - } - }); - } else { - Alert(templatesStrings.get('error.UNKNOWN'), templatesStrings.get('alert.UNKNOWN_LAUNCH')); - } - }; - - vm.launchTemplateWithPrompts = () => { - const jobLaunchData = PromptService.bundlePromptDataForLaunch(vm.promptData); - - // If the extra_vars dict is empty, we don't want to include it - // if we didn't prompt for anything. - if ( - _.isEmpty(jobLaunchData.extra_vars) && - !( - vm.promptData.launchConf.ask_variables_on_launch && - vm.promptData.launchConf.survey_enabled && - vm.promptData.surveyQuestions.length > 0 - ) - ) { - delete jobLaunchData.extra_vars; - } - - if (vm.promptData.templateType === 'job_template') { - jobTemplate.create().postLaunch({ - id: vm.promptData.template, - launchData: jobLaunchData - }).then((launchRes) => { - $state.go('output', { id: launchRes.data.job, type: 'playbook' }, { reload: true }); - }).catch(createErrorHandler('launch job template', 'POST')); - } else if (vm.promptData.templateType === 'workflow_job_template') { - workflowTemplate.create().postLaunch({ - id: vm.promptData.template, - launchData: jobLaunchData - }).then((launchRes) => { - $state.go('workflowResults', { id: launchRes.data.workflow_job }, { reload: true }); - }).catch(createErrorHandler('launch workflow job template', 'POST')); - } - }; -} - -export default atLaunchTemplate; diff --git a/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.partial.html b/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.partial.html deleted file mode 100644 index fc5c90de57ae..000000000000 --- a/awx/ui/client/lib/components/launchTemplateButton/launchTemplateButton.partial.html +++ /dev/null @@ -1,9 +0,0 @@ -
- - -
diff --git a/awx/ui/client/lib/components/layout/_index.less b/awx/ui/client/lib/components/layout/_index.less deleted file mode 100644 index b3a673bc999f..000000000000 --- a/awx/ui/client/lib/components/layout/_index.less +++ /dev/null @@ -1,224 +0,0 @@ -.at-Layout { - height: 100vh; - width: 100vw; - display: flex; - - &-topNav { - display: flex; - background-color: @at-color-top-nav-background; - z-index: @at-z-index-nav; - position: fixed; - right: 0; - left: 0; - top: 0; - height: @at-height-top-nav; - - .at-Layout-topNavRightAligner { - margin-left: auto; - } - - .at-Layout-topNavItem { - color: @at-color-top-nav-item-text; - padding: 0 @at-padding-top-nav-item-sides; - - a { - cursor: pointer; - } - - a, div { - color: @at-color-top-nav-item-text; - display: flex; - align-items: center; - justify-content: center; - height: 100%; - } - - i { - color: @at-color-top-nav-item-icon; - font-size: @at-height-top-nav-item-icon; - } - - &--logo { - padding-left: 0px; - - img { - max-width: @main-menu-max-width; - max-height: @main-menu-max-height; - height: @main-menu-height; - width: @main-menu-width; - margin: @main-menu-margin; - flex: initial; - } - } - - &--user { - i { - margin-right: @at-margin-top-nav-item-between-icon-and-name; - } - } - - &--socket { - i { - margin-top: @at-margin-top-nav-item-icon-socket-top-makeup; - font-size: @at-height-top-nav-item-icon-socket; - text-shadow: - -@at-border-default-width -@at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline, - @at-border-default-width -@at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline, - -@at-border-default-width @at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline, - @at-border-default-width @at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline - } - } - - &:focus, - &:hover, - &.is-currentRoute { - background-color: @at-color-top-nav-item-background-hover; - } - - &.is-loggedOut { - opacity: 0; - } - } - } - - &-side { - background: @at-color-side-nav-background; - position: fixed; - bottom: 0; - top: @at-height-top-side-nav-makeup; - overflow-y: auto; - max-height: 100vh; - min-width: @at-width-collapsed-side-nav; - z-index: @at-z-index-side-nav; - display: none; - - .at-Layout-sideNavItem { - background: inherit; - color: @at-color-side-nav-content; - display: flex; - cursor: pointer; - text-transform: uppercase; - - > i.fa { - padding-left: 20px; - } - - i { - cursor: pointer; - color: @at-color-side-nav-content; - font-size: @at-height-side-nav-item-icon; - padding: @at-padding-side-nav-item-icon; - } - - i.fa-cubes { - margin-left: -4px; - } - - &:hover, - &.is-active { - background: @at-color-side-nav-item-background-hover; - border-left: @at-highlight-left-border-size solid @at-color-side-nav-item-border-hover; - - i { - color: @at-color-side-nav-content; - margin-left: @at-highlight-left-border-margin-makeup; - } - - i.fa-cubes { - margin-left: -9px; - } - } - } - - .at-Layout-sideNavSpacer { - background: inherit; - height: 5px; - } - - &--expanded { - width: @at-width-expanded-side-nav; - display: block; - - .at-Layout-sideNavItem { - display: flex; - justify-content: flex-start; - align-items: center; - padding-right: @at-padding-between-side-nav-icon-text; - } - - + .at-Layout-main { - padding-left: @at-width-expanded-side-nav; - } - } - } - - &-main { - display: flex; - height: 100%; - width: 100%; - flex-direction: column; - overflow-x: hidden; - } - - &-content { - flex: 1px; - } - - &-footer { - background-color: @at-color-footer-background; - color: @at-color-footer; - position: relative; - padding-right: @at-padding-footer-right; - padding-bottom: @at-padding-footer-bottom; - margin-top: @at-margin-footer-top; - flex: 0; - display: flex; - align-items: center; - justify-content: flex-end; - - a { - cursor: pointer; - margin-right: @at-margin-after-footer-link; - } - } -} - -@media screen and (max-width: @at-breakpoint-mobile-layout) { - .at-Layout { - &-side { - top: 60px; - background-color: transparent; - - .at-Layout-sideNavItem.at-Layout-sideNavToggle { - display: flex; - height: 40px; - align-items: center; - width: 55px; - } - - .at-Layout-sideNavItem, - .at-Layout-sideNavSpacer { - display: none; - background-color: @at-color-side-nav-background; - } - - &--expanded { - width: 100vw; - z-index: @at-z-index-side-nav; - - .at-Layout-sideNavItem, - .at-Layout-sideNavSpacer { - display: flex; - } - } - } - - .at-Layout-main { - padding-left: 0; - - #content-container { - padding-top: 100px; - } - } - } -} diff --git a/awx/ui/client/lib/components/layout/layout.directive.js b/awx/ui/client/lib/components/layout/layout.directive.js deleted file mode 100644 index 0efd3ea0dfc9..000000000000 --- a/awx/ui/client/lib/components/layout/layout.directive.js +++ /dev/null @@ -1,57 +0,0 @@ -const templateUrl = require('~components/layout/layout.partial.html'); - -function AtLayoutController ($scope, strings, $transitions) { - const vm = this || {}; - - $transitions.onSuccess({}, (transition) => { - vm.currentState = transition.to().name; - }); - - $scope.$watch('$root.current_user', (val) => { - vm.isLoggedIn = val && val.username; - if (val) { - vm.isSuperUser = $scope.$root.user_is_superuser || $scope.$root.user_is_system_auditor; - vm.currentUsername = val.username; - vm.currentUserId = val.id; - } - }); - - $scope.$watch('$root.socketStatus', (newStatus) => { - vm.socketState = newStatus; - vm.socketIconClass = `icon-socket-${vm.socketState}`; - }); - - $scope.$watch('$root.licenseMissing', (licenseMissing) => { - vm.licenseIsMissing = licenseMissing; - }); - - vm.getString = string => { - try { - return strings.get(`layout.${string}`); - } catch (err) { - return strings.get(string); - } - }; - - vm.isExpanded = false; - - vm.toggleExpansion = () => { - vm.isExpanded = !vm.isExpanded; - }; -} - -AtLayoutController.$inject = ['$scope', 'ComponentsStrings', '$transitions']; - -function atLayout () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - controller: AtLayoutController, - controllerAs: 'vm', - scope: {} - }; -} - -export default atLayout; diff --git a/awx/ui/client/lib/components/layout/layout.partial.html b/awx/ui/client/lib/components/layout/layout.partial.html deleted file mode 100644 index 05f0c24bff92..000000000000 --- a/awx/ui/client/lib/components/layout/layout.partial.html +++ /dev/null @@ -1,113 +0,0 @@ -
- - - - - - -
- - - - - - - - -
- - - - - - -
- - - - - - - - -
- - - - -
-
-
- -
- -
-
diff --git a/awx/ui/client/lib/components/layout/side-nav-item.directive.js b/awx/ui/client/lib/components/layout/side-nav-item.directive.js deleted file mode 100644 index d4b11bf71600..000000000000 --- a/awx/ui/client/lib/components/layout/side-nav-item.directive.js +++ /dev/null @@ -1,54 +0,0 @@ -const templateUrl = require('~components/layout/side-nav-item.partial.html'); - -function atSideNavItemLink (scope, element, attrs, ctrl) { - [scope.navVm, scope.layoutVm] = ctrl; -} - -function AtSideNavItemController ($scope, strings) { - const vm = this || {}; - - $scope.$watch('layoutVm.currentState', current => { - if ($scope.name === 'portal mode') { - vm.isRoute = (current && current.indexOf('portalMode') === 0); - } else if (current && current.indexOf($scope.route) === 0) { - if (current.indexOf('jobs.schedules') === 0 && $scope.route === 'jobs') { - vm.isRoute = false; - } else { - vm.isRoute = true; - } - } else { - vm.isRoute = false; - } - }); - - vm.tooltip = { - popover: { - text: strings.get(`layout.${$scope.name}`), - on: 'mouseenter', - icon: $scope.iconClass, - position: 'right', - arrowHeight: 18 - } - }; -} - -AtSideNavItemController.$inject = ['$scope', 'ComponentsStrings']; - -function atSideNavItem () { - return { - restrict: 'E', - templateUrl, - require: ['^^atSideNav', '^^atLayout'], - controller: AtSideNavItemController, - controllerAs: 'vm', - link: atSideNavItemLink, - scope: { - iconClass: '@', - name: '@', - route: '@', - systemAdminOnly: '@' - } - }; -} - -export default atSideNavItem; diff --git a/awx/ui/client/lib/components/layout/side-nav-item.partial.html b/awx/ui/client/lib/components/layout/side-nav-item.partial.html deleted file mode 100644 index 3b1be8cc80b5..000000000000 --- a/awx/ui/client/lib/components/layout/side-nav-item.partial.html +++ /dev/null @@ -1,9 +0,0 @@ -
- - - - {{ layoutVm.getString(name) }} - -
diff --git a/awx/ui/client/lib/components/layout/side-nav.directive.js b/awx/ui/client/lib/components/layout/side-nav.directive.js deleted file mode 100644 index 4b963b279621..000000000000 --- a/awx/ui/client/lib/components/layout/side-nav.directive.js +++ /dev/null @@ -1,55 +0,0 @@ -const templateUrl = require('~components/layout/side-nav.partial.html'); - -let $document; - -function atSideNavLink (scope, element, attrs, ctrl) { - scope.layoutVm = ctrl; - - $document.on('click', (e) => { - if ($(e.target).parents('.at-Layout-side').length === 0) { - scope.$emit('clickOutsideSideNav'); - } - }); -} - -function AtSideNavController ($scope, $window) { - const vm = this || {}; - const breakpoint = 700; - - - - $scope.$watch('layoutVm.currentState', () => { - if ($window.innerWidth <= breakpoint) { - vm.isExpanded = false; - } - }); - - $scope.$on('clickOutsideSideNav', () => { - if ($window.innerWidth <= breakpoint) { - vm.isExpanded = false; - } - }); -} - -AtSideNavController.$inject = ['$scope', '$window']; - -function atSideNav (_$document_) { - $document = _$document_; - - return { - restrict: 'E', - replace: true, - require: '^^atLayout', - controller: AtSideNavController, - controllerAs: 'vm', - link: atSideNavLink, - transclude: true, - templateUrl, - scope: { - } - }; -} - -atSideNav.$inject = ['$document']; - -export default atSideNav; diff --git a/awx/ui/client/lib/components/layout/side-nav.partial.html b/awx/ui/client/lib/components/layout/side-nav.partial.html deleted file mode 100644 index 4696266dccb5..000000000000 --- a/awx/ui/client/lib/components/layout/side-nav.partial.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/awx/ui/client/lib/components/layout/top-nav-item.directive.js b/awx/ui/client/lib/components/layout/top-nav-item.directive.js deleted file mode 100644 index 8851565a3ff2..000000000000 --- a/awx/ui/client/lib/components/layout/top-nav-item.directive.js +++ /dev/null @@ -1,30 +0,0 @@ -const templateUrl = require('~components/layout/top-nav-item.partial.html'); - -function atTopNavItemLink (scope, element, attrs, ctrl) { - scope.layoutVm = ctrl; - - scope.isHidden = false; - - const shownWhen = attrs.isShown; - - if (shownWhen !== 'missingLicense') { - scope.$watch('layoutVm.licenseIsMissing', (val) => { - scope.isHidden = val; - }); - } -} - -function atTopNavItem () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - require: '^^atLayout', - link: atTopNavItemLink, - scope: { - } - }; -} - -export default atTopNavItem; diff --git a/awx/ui/client/lib/components/layout/top-nav-item.partial.html b/awx/ui/client/lib/components/layout/top-nav-item.partial.html deleted file mode 100644 index 2071888e0fc7..000000000000 --- a/awx/ui/client/lib/components/layout/top-nav-item.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
-
diff --git a/awx/ui/client/lib/components/list/_index.less b/awx/ui/client/lib/components/list/_index.less deleted file mode 100644 index 08b39d8f05e0..000000000000 --- a/awx/ui/client/lib/components/list/_index.less +++ /dev/null @@ -1,285 +0,0 @@ -.at-List { - margin-top: @at-margin-top-list; -} - -.at-List--empty { - margin-top: @at-margin-top-list; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: @at-height-list-empty; - border-radius: @at-border-radius; - border: @at-border-default-width solid @at-color-list-empty-border; - background-color: @at-color-list-empty-background; - color: @at-color-list-empty; - text-transform: uppercase; - text-align: center; - padding: @at-padding-list-empty; -} - -.at-List-toolbar { - width: 100%; - display: flex; - align-items: center; - margin-bottom: @at-margin-bottom-list-toolbar; -} - -.at-List-search { - flex: auto; -} - -.at-List-toolbarAction { - margin-left: @at-margin-left-toolbar-action; - display: flex; - align-items: center; - justify-content: center; - height: @at-height-toolbar-action; - border-radius: @at-border-radius; - position: relative; -} - -.at-List-toolbarActionButton { - border: none; - border-radius: @at-border-radius; - min-width: 80px; -} - -.at-List-toolbarActionDropdownMenu { - border-top-right-radius: 0; - border: 1px solid @at-gray-d7; - float: right; - left: auto; - margin: 0; - right: 0; -} - -.at-List-container { - border: @at-border-default-width solid @at-color-list-border; - border-radius: @at-border-radius; -} - -.at-Row { - display: grid; - grid-template-columns: 10px 1fr; -} - -.at-Row--active { - border-left: @at-border-style-list-active-indicator; - border-top-left-radius: @at-border-radius; - border-top-right-radius: @at-border-radius; -} - -.at-Row--active .at-Row--invalid { - border-left: @at-white solid 1px; -} - -.at-Row--active .at-Row-content { - margin-left: -5px; -} - -.at-Row ~ .at-Row { - border-top-left-radius: 0px; - border-top-right-radius: 0px; - border-top: @at-border-default-width solid @at-color-list-border; -} - -.at-Row--invalid { - align-items: center; - background: @at-color-error; - display: flex; - justify-content: center; - - .at-Popover { - padding: 0; - - &-icon i { - color: @at-white; - } - - &-icon i:hover { - color: @at-white; - } - } -} - -.at-Row-content { - align-items: center; - display: flex; - flex-wrap: wrap; - grid-column-start: 2; - padding: @at-padding-list-row; -} - -.at-Row-toggle { - align-self: flex-start; - margin-right: @at-space-4x; -} - -.at-Row-actions { - display: flex; -} - -.at-Row-items { - flex: 1; -} - -.at-RowItem { - display: grid; - grid-template-columns: 120px 1fr; - align-items: center; - line-height: @at-height-list-row-item; -} - -.at-RowItem-status { - margin-right: @at-margin-right-list-row-item-status; -} - -.at-RowItem--isHeader { - display: flex; - color: @at-color-body-text; - margin-bottom: @at-margin-bottom-list-header; - line-height: @at-line-height-list-row-item-header; -} - -.at-RowItem--isHeaderLink { - color: @at-blue; - cursor: pointer; -} -.at-RowItem--isHeaderLink:hover { - color: @at-blue-hover; -} - -.at-RowItem--labels { - line-height: @at-line-height-list-row-item-labels; - display: flex; - flex-wrap: wrap; - - * { - font-size: 10px; - } -} - -.at-RowItem-header { - font-weight: bold; -} - -.at-RowItem-tagContainer { - display: flex; - margin-left: @at-margin-left-list-row-item-tag-container; -} - -.at-RowItem-tag { - text-transform: uppercase; - font-weight: 100; - background-color: @at-color-list-row-item-tag-background; - border-radius: @at-border-radius; - color: @at-color-list-row-item-tag; - font-size: @at-font-size-list-row-item-tag; - margin-left: @at-margin-left-list-row-item-tag; - margin-top: @at-margin-top-list-row-item-tag; - padding: @at-padding-list-row-item-tag; - line-height: @at-line-height-list-row-item-tag; -} - -.at-RowItem-tag--primary { - background: @at-color-list-row-item-tag-primary-background; - color: @at-color-list-row-item-tag-primary; -} - -.at-RowItem-tag--header { - height: @at-height-list-row-item-tag; - line-height: inherit; -} - -.at-RowItem-tagIcon { - margin-right: @at-margin-right-list-row-item-tag-icon; -} - -.at-RowItem-label { - text-transform: uppercase; - color: @at-color-list-row-item-label; - font-size: @at-font-size; -} - -.at-RowItem-value { - font-size: @at-font-size-3x; -} - -.at-RowItem-badge { - background-color: @at-gray-848992; - border-radius: @at-border-radius; - color: @at-white; - font-size: 11px; - font-weight: normal; - height: 14px; - line-height: 10px; - margin: 0 10px; - padding: 2px 10px; -} - -.at-RowAction { - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - margin-left: @at-margin-left-list-row-action; - padding: @at-padding-list-row-action; - background: @at-color-list-row-action-background; - border-radius: @at-border-radius; - height: @at-height-list-row-action; - width: @at-width-list-row-action; - - i { - font-size: @at-font-size-list-row-action-icon; - color: @at-color-list-row-action-icon; - } -} - -.at-RowAction:hover { - background-color: @at-color-list-row-action-hover; - - i { - color: @at-color-list-row-action-icon-hover; - } -} - -.at-RowAction--danger:hover { - background-color: @at-color-list-row-action-hover-danger; -} - -.at-Row .at-Row-checkbox { - align-self: start; - margin: 2px 20px 0 0; -} - -.at-RowItem--inline { - display: inline-flex; - margin-right: @at-margin-right-list-row-item-inline; - - .at-RowItem-label { - width: auto; - margin-right: @at-margin-right-list-row-item-inline-label; - } -} - -@media screen and (max-width: @at-breakpoint-compact-list) { - .at-Row-actions { - flex-direction: column; - align-items: center; - } - - .at-RowAction { - margin: @at-margin-list-row-action-mobile; - } - - .at-RowItem--inline { - display: flex; - margin-right: inherit; - - .at-RowItem-label { - width: @at-width-list-row-item-label; - margin-right: inherit; - } - } -} diff --git a/awx/ui/client/lib/components/list/list.directive.js b/awx/ui/client/lib/components/list/list.directive.js deleted file mode 100644 index 7c6a1c1adcc0..000000000000 --- a/awx/ui/client/lib/components/list/list.directive.js +++ /dev/null @@ -1,31 +0,0 @@ -const templateUrl = require('~components/list/list.partial.html'); - -function atListLink (scope, element, attrs) { - if (!attrs.results) { - throw new Error('at-list directive requires results attr to set up the empty list properly'); - } -} - -function AtListController (strings) { - this.strings = strings; -} - -AtListController.$inject = ['ComponentsStrings']; - -function atList () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - results: '=', - emptyListReason: '@' - }, - link: atListLink, - controller: AtListController, - controllerAs: 'vm', - }; -} - -export default atList; diff --git a/awx/ui/client/lib/components/list/list.partial.html b/awx/ui/client/lib/components/list/list.partial.html deleted file mode 100644 index 3bd90e666333..000000000000 --- a/awx/ui/client/lib/components/list/list.partial.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
-
-
- {{ emptyListReason || vm.strings.get("list.DEFAULT_EMPTY_LIST") }} -
-
diff --git a/awx/ui/client/lib/components/list/row-action.directive.js b/awx/ui/client/lib/components/list/row-action.directive.js deleted file mode 100644 index 18b183549923..000000000000 --- a/awx/ui/client/lib/components/list/row-action.directive.js +++ /dev/null @@ -1,15 +0,0 @@ -const templateUrl = require('~components/list/row-action.partial.html'); - -function atRowAction () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - icon: '@' - } - }; -} - -export default atRowAction; diff --git a/awx/ui/client/lib/components/list/row-action.partial.html b/awx/ui/client/lib/components/list/row-action.partial.html deleted file mode 100644 index 58a747976910..000000000000 --- a/awx/ui/client/lib/components/list/row-action.partial.html +++ /dev/null @@ -1,4 +0,0 @@ -
- -
diff --git a/awx/ui/client/lib/components/list/row-item.directive.js b/awx/ui/client/lib/components/list/row-item.directive.js deleted file mode 100644 index 67e169835aed..000000000000 --- a/awx/ui/client/lib/components/list/row-item.directive.js +++ /dev/null @@ -1,32 +0,0 @@ -const templateUrl = require('~components/list/row-item.partial.html'); - -function atRowItem () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - inline: '@', - badge: '@', - headerValue: '@', - headerLink: '@', - headerState: '@', - headerTag: '@', - status: '@', - statusTip: '@', - labelValue: '@', - labelLink: '@', - labelState: '@', - value: '@', - valueLink: '@', - valueBindHtml: '@', - smartStatus: '=?', - tagValues: '=?', - // TODO: add see more for tags if applicable - tagsAreCreds: '@' - } - }; -} - -export default atRowItem; diff --git a/awx/ui/client/lib/components/list/row-item.partial.html b/awx/ui/client/lib/components/list/row-item.partial.html deleted file mode 100644 index 7698ba85a9e2..000000000000 --- a/awx/ui/client/lib/components/list/row-item.partial.html +++ /dev/null @@ -1,58 +0,0 @@ -
-
- - - - -
- - -
- {{ headerValue }} -
-
- {{ headerTag }} -
- -
- {{ labelValue }} -
- - -
-
-
-
- - -
-
- - - - - - - - - {{ tag.name }} -
-
-
diff --git a/awx/ui/client/lib/components/list/row.directive.js b/awx/ui/client/lib/components/list/row.directive.js deleted file mode 100644 index 98805a1cf71a..000000000000 --- a/awx/ui/client/lib/components/list/row.directive.js +++ /dev/null @@ -1,17 +0,0 @@ -const templateUrl = require('~components/list/row.partial.html'); - -function atRow () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - templateId: '@', - invalid: '=', - invalidTooltip: '=' - } - }; -} - -export default atRow; diff --git a/awx/ui/client/lib/components/list/row.partial.html b/awx/ui/client/lib/components/list/row.partial.html deleted file mode 100644 index dc6dfbd9f011..000000000000 --- a/awx/ui/client/lib/components/list/row.partial.html +++ /dev/null @@ -1,6 +0,0 @@ -
-
- -
-
-
diff --git a/awx/ui/client/lib/components/modal/_index.less b/awx/ui/client/lib/components/modal/_index.less deleted file mode 100644 index 1d3b2be342a2..000000000000 --- a/awx/ui/client/lib/components/modal/_index.less +++ /dev/null @@ -1,28 +0,0 @@ -.at-Modal-body { - font-size: @at-font-size; - padding: @at-padding-panel 0; -} - -.at-Modal-dismiss { - .at-mixin-ButtonIcon(); - font-size: @at-font-size-modal-dismiss; - color: @at-color-icon-dismiss; - text-align: right; -} - -.at-Modal-heading { - margin: 0; - overflow: visible; - - & > .at-Modal-dismiss { - margin: 0; - } -} - -.at-Modal-title { - margin: 0; - padding: 0; - - .at-mixin-Heading(@at-font-size-modal-heading); -} - diff --git a/awx/ui/client/lib/components/modal/modal.directive.js b/awx/ui/client/lib/components/modal/modal.directive.js deleted file mode 100644 index 3f77d374e763..000000000000 --- a/awx/ui/client/lib/components/modal/modal.directive.js +++ /dev/null @@ -1,85 +0,0 @@ -const templateUrl = require('~components/modal/modal.partial.html'); - -const DEFAULT_ANIMATION_DURATION = 150; - -function atModalLink (scope, el, attrs, controllers) { - const modalController = controllers[0]; - const property = `scope.${scope.ns}.modal`; - - const done = scope.$watch(property, () => { - modalController.init(scope, el); - done(); - }); -} - -function AtModalController ($timeout, eventService, strings) { - const vm = this; - - let overlay; - let listeners; - - vm.strings = strings; - - vm.init = (scope, el) => { - overlay = el[0]; // eslint-disable-line prefer-destructuring - - vm.modal = scope[scope.ns].modal; - vm.modal.show = vm.show; - vm.modal.hide = vm.hide; - vm.modal.onClose = scope.onClose; - }; - - vm.show = (title, message) => { - vm.modal.title = title; - vm.modal.message = message; - - listeners = eventService.addListeners([ - [overlay, 'click', vm.clickToHide] - ]); - - overlay.style.display = 'block'; - overlay.style.opacity = 1; - }; - - vm.hide = () => { - overlay.style.opacity = 0; - - eventService.remove(listeners); - - setTimeout(() => { - overlay.style.display = 'none'; - }, DEFAULT_ANIMATION_DURATION); - - if (vm.modal.onClose) { - vm.modal.onClose(); - } - }; - - vm.clickToHide = event => { - if ($(event.target).hasClass('at-Modal')) { - vm.hide(); - } - }; -} - -AtModalController.$inject = [ - '$timeout', - 'EventService', - 'ComponentsStrings' -]; - -function atModal () { - return { - restrict: 'E', - replace: true, - transclude: true, - require: ['atModal'], - templateUrl, - controller: AtModalController, - controllerAs: 'vm', - link: atModalLink, - scope: true - }; -} - -export default atModal; diff --git a/awx/ui/client/lib/components/modal/modal.partial.html b/awx/ui/client/lib/components/modal/modal.partial.html deleted file mode 100644 index 1eca295b2b38..000000000000 --- a/awx/ui/client/lib/components/modal/modal.partial.html +++ /dev/null @@ -1,32 +0,0 @@ - diff --git a/awx/ui/client/lib/components/panel/_index.less b/awx/ui/client/lib/components/panel/_index.less deleted file mode 100644 index b89faeb405a7..000000000000 --- a/awx/ui/client/lib/components/panel/_index.less +++ /dev/null @@ -1,58 +0,0 @@ -.at-Panel { - margin: @at-margin-panel 0 0 0; - padding: @at-padding-panel; - border-color: @at-color-panel-border; -} - -.at-Panel-heading { - margin: 0; - padding: 0; -} - -.at-Panel-headingRow { - margin-bottom: 20px; -} - -.at-Panel-dismiss { - .at-mixin-ButtonIcon(); - color: @at-color-icon-dismiss; - text-align: right; -} - -.at-Panel-body { - margin: 0; - padding: 0; -} - -.at-Panel-headingTitle { - .at-mixin-Heading(@at-font-size-panel-heading); - text-transform: none; -} - -.at-Panel-headingTitleBadge { - font-size: 11px; - font-weight: normal; - padding: 2px 10px; - line-height: 10px; - background-color: #848992; - border-radius: 5px; - display: inline-block; - min-width: 10px; - color: #fff; - vertical-align: middle; - white-space: nowrap; - text-align: center; - margin-left: 5px; -} - -.at-Panel-label { - text-transform: uppercase; - color: @default-interface-txt; - font-size: 12px; - font-weight: normal!important; - width: 30%; - - @media screen and (max-width: @breakpoint-md) { - flex: 2.5 0 auto; - } -} diff --git a/awx/ui/client/lib/components/panel/body.directive.js b/awx/ui/client/lib/components/panel/body.directive.js deleted file mode 100644 index 1cf795596a44..000000000000 --- a/awx/ui/client/lib/components/panel/body.directive.js +++ /dev/null @@ -1,15 +0,0 @@ -const templateUrl = require('~components/panel/body.partial.html'); - -function atPanelBody () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - scope: { - state: '=' - } - }; -} - -export default atPanelBody; diff --git a/awx/ui/client/lib/components/panel/body.partial.html b/awx/ui/client/lib/components/panel/body.partial.html deleted file mode 100644 index fa6c56e458f4..000000000000 --- a/awx/ui/client/lib/components/panel/body.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
diff --git a/awx/ui/client/lib/components/panel/heading.directive.js b/awx/ui/client/lib/components/panel/heading.directive.js deleted file mode 100644 index 8850c10c2fea..000000000000 --- a/awx/ui/client/lib/components/panel/heading.directive.js +++ /dev/null @@ -1,19 +0,0 @@ -const templateUrl = require('~components/panel/heading.partial.html'); - -function link (scope, el, attrs, panel) { - scope.hideDismiss = Boolean(attrs.hideDismiss); - panel.use(scope); -} - -function atPanelHeading () { - return { - restrict: 'E', - require: '^^atPanel', - replace: true, - transclude: true, - templateUrl, - link - }; -} - -export default atPanelHeading; diff --git a/awx/ui/client/lib/components/panel/heading.partial.html b/awx/ui/client/lib/components/panel/heading.partial.html deleted file mode 100644 index e57e6a880dbd..000000000000 --- a/awx/ui/client/lib/components/panel/heading.partial.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
-

- -

-
-
-
- -
-
-
-

- -

-
-
diff --git a/awx/ui/client/lib/components/panel/panel.directive.js b/awx/ui/client/lib/components/panel/panel.directive.js deleted file mode 100644 index a58b386acf2d..000000000000 --- a/awx/ui/client/lib/components/panel/panel.directive.js +++ /dev/null @@ -1,46 +0,0 @@ -const templateUrl = require('~components/panel/panel.partial.html'); - -function atPanelLink (scope, el, attrs, controller) { - const panelController = controller; - - panelController.init(scope); -} - -function AtPanelController ($state) { - const vm = this; - - let scope; - - vm.init = (_scope_) => { - scope = _scope_; - }; - - vm.dismiss = () => { - $state.go(scope.onDismiss || '^'); - }; - - vm.use = child => { - child.dismiss = vm.dismiss; - }; -} - -AtPanelController.$inject = ['$state']; - -function atPanel () { - return { - restrict: 'E', - replace: true, - require: 'atPanel', - transclude: true, - templateUrl, - controller: AtPanelController, - controllerAs: 'vm', - link: atPanelLink, - scope: { - state: '=', - onDismiss: '@' - } - }; -} - -export default atPanel; diff --git a/awx/ui/client/lib/components/panel/panel.partial.html b/awx/ui/client/lib/components/panel/panel.partial.html deleted file mode 100644 index 476653e39006..000000000000 --- a/awx/ui/client/lib/components/panel/panel.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
diff --git a/awx/ui/client/lib/components/popover/_index.less b/awx/ui/client/lib/components/popover/_index.less deleted file mode 100644 index e6356217cad5..000000000000 --- a/awx/ui/client/lib/components/popover/_index.less +++ /dev/null @@ -1,57 +0,0 @@ -.at-Popover { - padding: 0 0 0 5px; -} - -.at-Popover--inline { - display: inline-block; -} - -.at-Popover-icon { - .at-mixin-ButtonIcon(); - color: @at-color-icon-popover; - font-size: @at-font-size-icon; - margin: 0; -} - -.at-Popover-icon--defaultCursor { - i > { - cursor: default; - } -} - -.at-Popover-container { - visibility: hidden; - opacity: 0; - color: @at-white; - background-color: @at-color-body-background-dark; - max-width: @at-popover-maxwidth; - padding: @at-padding-popover; - height: auto; - position: fixed; - z-index: 2000; - margin: 0; - border-radius: @at-border-radius; - box-shadow: 0 5px 10px rgba(0,0,0, 0.2); - transition: opacity .15s linear; - font-weight: @at-font-weight-body; -} - -.at-Popover-arrow { - color: @at-color-body-background-dark; - position: fixed; - z-index: 1999; - padding: 0; - margin: 0; -} - -.at-Popover-title { - .at-mixin-Heading(@at-font-size-body); - color: @at-color-body-text-dark; - margin-bottom: @at-margin-popover; -} - -.at-Popover-text { - margin: 0; - padding: 0; - font-size: @at-font-size; -} diff --git a/awx/ui/client/lib/components/popover/popover.directive.js b/awx/ui/client/lib/components/popover/popover.directive.js deleted file mode 100644 index ae23f0620957..000000000000 --- a/awx/ui/client/lib/components/popover/popover.directive.js +++ /dev/null @@ -1,220 +0,0 @@ -const templateUrl = require('~components/popover/popover.partial.html'); - -const DEFAULT_POSITION = 'right'; -const DEFAULT_ACTION = 'click'; -const DEFAULT_ICON = 'fa fa-question-circle'; -const DEFAULT_ALIGNMENT = 'inline'; -const DEFAULT_ARROW_HEIGHT = 14; -const DEFAULT_PADDING = 10; -const DEFAULT_REFRESH_DELAY = 50; -const DEFAULT_RESET_ON_EXIT = false; - -function atPopoverLink (scope, el, attr, controllers) { - const popoverController = controllers[0]; - const container = el[0]; - const popover = container.getElementsByClassName('at-Popover-container')[0]; - const icon = container.getElementsByTagName('i')[0]; - - const done = scope.$watch('state', () => { - popoverController.init(scope, container, icon, popover); - done(); - }); -} - -function AtPopoverController () { - const vm = this; - - let icon; - let popover; - let scope; - - vm.init = (_scope_, _container_, _icon_, _popover_) => { - scope = _scope_; - icon = _icon_; - popover = _popover_; - - scope.popover = scope.state.popover || {}; - - scope.popover.text = scope.state.help_text || scope.popover.text; - scope.popover.title = scope.state.label || scope.popover.title; - scope.popover.inline = scope.popover.inline || DEFAULT_ALIGNMENT; - scope.popover.position = scope.popover.position || DEFAULT_POSITION; - scope.popover.icon = scope.popover.icon || DEFAULT_ICON; - scope.popover.on = scope.popover.on || DEFAULT_ACTION; - scope.popover.resetOnExit = scope.popover.resetOnExit || DEFAULT_RESET_ON_EXIT; - scope.popover.arrowHeight = scope.popover.arrowHeight || DEFAULT_ARROW_HEIGHT; - - if (scope.popover.resetOnExit) { - scope.originalText = scope.popover.text; - scope.originalTitle = scope.popover.title; - } - - icon.addEventListener(scope.popover.on, vm.createDisplayListener()); - - scope.$watch('popover.text', vm.refresh); - - if (scope.popover.click) { - icon.addEventListener('click', scope.popover.click); - } - }; - - vm.createDismissListener = () => event => { - event.stopPropagation(); - - if (vm.isClickWithinPopover(event, popover)) { - return; - } - - vm.dismiss(); - - if (scope.popover.on === 'mouseenter') { - icon.removeEventListener('mouseleave', vm.dismissListener); - } else { - window.addEventListener(scope.popover.on, vm.dismissListener); - } - - window.removeEventListener('resize', vm.dismissListener); - }; - - vm.dismiss = (refresh) => { - if (!refresh && scope.popover.resetOnExit) { - scope.popover.text = scope.originalText; - scope.popover.title = scope.originalTitle; - } - - vm.open = false; - - popover.style.visibility = 'hidden'; - popover.style.opacity = 0; - }; - - vm.isClickWithinPopover = (event, popoverEl) => { - const box = popoverEl.getBoundingClientRect(); - - const x = event.clientX; - const y = event.clientY; - - if ((x <= box.right && x >= box.left) && (y >= box.top && y <= box.bottom)) { - return true; - } - - return false; - }; - - vm.createDisplayListener = () => event => { - if (vm.open) { - return; - } - - event.stopPropagation(); - - vm.display(); - - vm.dismissListener = vm.createDismissListener(event); - - if (scope.popover.on === 'mouseenter') { - icon.addEventListener('mouseleave', vm.dismissListener); - } else { - window.addEventListener(scope.popover.on, vm.dismissListener); - } - - window.addEventListener('resize', vm.dismissListener); - }; - - vm.refresh = () => { - if (!vm.open) { - return; - } - - vm.dismiss(true); - window.setTimeout(vm.display, DEFAULT_REFRESH_DELAY); - }; - - vm.getPositions = () => { - const arrow = popover.getElementsByClassName('at-Popover-arrow')[0]; - - arrow.style.lineHeight = `${DEFAULT_ARROW_HEIGHT}px`; - arrow.children[0].style.lineHeight = `${scope.popover.arrowHeight}px`; - - const data = { - arrow, - icon: icon.getBoundingClientRect(), - popover: popover.getBoundingClientRect(), - windowHeight: window.innerHeight - }; - - data.cx = Math.floor(data.icon.left + (data.icon.width / 2)); - data.cy = Math.floor(data.icon.top + (data.icon.height / 2)); - data.rightBoundary = Math.floor(data.icon.right); - - return data; - }; - - vm.display = () => { - vm.open = true; - - const positions = vm.getPositions(); - - popover.style.visibility = 'visible'; - popover.style.opacity = 1; - - if (scope.popover.position === 'right') { - vm.displayRight(positions); - } else if (scope.popover.position === 'top') { - vm.displayTop(positions); - } - }; - - vm.displayRight = (pos) => { - const arrowHeight = pos.arrow.offsetHeight; - const arrowLeft = pos.rightBoundary + DEFAULT_PADDING; - const popoverLeft = arrowLeft + DEFAULT_PADDING - 1; - - let popoverTop; - if (pos.cy < (pos.popover.height / 2)) { - popoverTop = DEFAULT_PADDING; - } else { - popoverTop = Math.floor((pos.cy - pos.popover.height / 2)); - } - - const arrowTop = Math.floor(popoverTop + (pos.popover.height / 2) - (arrowHeight / 2)); - - pos.arrow.style.top = `${arrowTop}px`; - pos.arrow.style.left = `${arrowLeft}px`; - - popover.style.top = `${popoverTop}px`; - popover.style.left = `${popoverLeft}px`; - }; - - vm.displayTop = (pos) => { - const arrowTop = pos.icon.top - pos.icon.height - DEFAULT_PADDING; - const arrowLeft = Math.floor(pos.icon.right - pos.icon.width - (pos.arrow.style.width / 2)); - - const popoverTop = pos.icon.top - pos.popover.height - pos.icon.height - 5; - const popoverLeft = Math.floor(pos.cx - (pos.popover.width / 2)); - - pos.arrow.style.top = `${arrowTop}px`; - pos.arrow.style.left = `${arrowLeft}px`; - - popover.style.top = `${popoverTop}px`; - popover.style.left = `${popoverLeft}px`; - }; -} - -function atPopover () { - return { - restrict: 'E', - replace: true, - transclude: true, - require: ['atPopover'], - templateUrl, - controller: AtPopoverController, - controllerAs: 'vm', - link: atPopoverLink, - scope: { - state: '=' - } - }; -} - -export default atPopover; diff --git a/awx/ui/client/lib/components/popover/popover.partial.html b/awx/ui/client/lib/components/popover/popover.partial.html deleted file mode 100644 index 974575f68f32..000000000000 --- a/awx/ui/client/lib/components/popover/popover.partial.html +++ /dev/null @@ -1,16 +0,0 @@ -
-
- -
-
-
-
-
-
-
-

{{ popover.title | translate }}

-

{{ popover.text | translate }}

-
-
-
diff --git a/awx/ui/client/lib/components/relaunchButton/_index.less b/awx/ui/client/lib/components/relaunchButton/_index.less deleted file mode 100644 index 7bc6e55e13e1..000000000000 --- a/awx/ui/client/lib/components/relaunchButton/_index.less +++ /dev/null @@ -1,39 +0,0 @@ -.at-Relaunch { - margin-left: 15px; - - &--button { - font-size: 16px; - height: 30px; - min-width: 30px; - color: #848992; - background-color: inherit; - border: none; - border-radius: 4px; - } - &--button:hover { - background-color: @at-blue; - color: white; - } - &--dropdownTitle { - color: #707070; - font-size: 12px; - font-weight: bold; - text-transform: uppercase; - padding: 3px 10px; - } - &--dropdownOptions { - i { - padding-right: 5px; - } - a:hover { - cursor: pointer; - } - } -} - -.open { - .at-Relaunch--button { - background-color: @at-blue; - color: white; - } -} diff --git a/awx/ui/client/lib/components/relaunchButton/relaunchButton.component.js b/awx/ui/client/lib/components/relaunchButton/relaunchButton.component.js deleted file mode 100644 index 561664185bb8..000000000000 --- a/awx/ui/client/lib/components/relaunchButton/relaunchButton.component.js +++ /dev/null @@ -1,282 +0,0 @@ -import templateUrl from './relaunchButton.partial.html'; - -const atRelaunch = { - templateUrl, - bindings: { - job: '<' - }, - controller: ['ProcessErrors', 'AdhocRun', 'ComponentsStrings', - 'ProjectModel', 'InventorySourceModel', 'WorkflowJobModel', 'Alert', - 'AdHocCommandModel', 'JobModel', 'JobTemplateModel', 'PromptService', - '$state', '$q', '$scope', atRelaunchCtrl - ], - controllerAs: 'vm' -}; - -function atRelaunchCtrl ( - ProcessErrors, AdhocRun, strings, - Project, InventorySource, WorkflowJob, Alert, - AdHocCommand, Job, JobTemplate, PromptService, - $state, $q, $scope -) { - const vm = this; - const jobObj = new Job(); - const jobTemplate = new JobTemplate(); - - const updateTooltip = () => { - if (vm.job.type === 'job' && vm.job.status === 'failed') { - vm.tooltip = strings.get('relaunch.HOSTS'); - } else { - vm.tooltip = strings.get('relaunch.DEFAULT'); - } - }; - - const checkRelaunchPlaybook = (option) => { - jobObj.getRelaunch({ - id: vm.job.id - }).then((getRelaunchRes) => { - if ( - getRelaunchRes.data.passwords_needed_to_start && - getRelaunchRes.data.passwords_needed_to_start.length > 0 - ) { - const jobPromises = [ - jobObj.request('get', vm.job.id), - jobTemplate.optionsLaunch(vm.job.unified_job_template), - jobObj.getCredentials(vm.job.id) - ]; - - $q.all(jobPromises) - .then(([jobRes, launchOptions, jobCreds]) => { - const populatedJob = jobRes.data; - const jobTypeChoices = _.get( - launchOptions, - 'data.actions.POST.job_type.choices', - [] - ).map(c => ({ label: c[1], value: c[0] })); - const verbosityChoices = _.get( - launchOptions, - 'data.actions.POST.verbosity.choices', - [] - ).map(c => ({ label: c[1], value: c[0] })); - const verbosity = _.find( - verbosityChoices, - item => item.value === populatedJob.verbosity - ); - const jobType = _.find( - jobTypeChoices, - item => item.value === populatedJob.job_type - ); - - vm.promptData = { - launchConf: { - passwords_needed_to_start: - getRelaunchRes.data.passwords_needed_to_start - }, - launchOptions: launchOptions.data, - job: vm.job.id, - relaunchHostType: option ? (option.name).toLowerCase() : null, - prompts: { - credentials: { - value: populatedJob.summary_fields.credentials ? - _.merge( - jobCreds.data.results, - populatedJob.summary_fields.credentials - ) : [] - }, - variables: { - value: populatedJob.extra_vars - }, - inventory: { - value: populatedJob.summary_fields.inventory || null - }, - verbosity: { - value: verbosity, - choices: verbosityChoices - }, - jobType: { - value: jobType, - choices: jobTypeChoices - }, - limit: { - value: populatedJob.limit - }, - tags: { - value: populatedJob.job_tags - }, - skipTags: { - value: populatedJob.skip_tags - }, - diffMode: { - value: populatedJob.diff_mode - } - }, - triggerModalOpen: true - }; - }); - } else { - const launchParams = { - id: vm.job.id, - }; - - if (_.has(option, 'name')) { - launchParams.relaunchData = { - hosts: (option.name).toLowerCase() - }; - } - - jobObj.postRelaunch(launchParams) - .then((launchRes) => { - if (!$state.is('jobs')) { - const relaunchType = launchRes.data.type === 'job' ? 'playbook' : launchRes.data.type; - $state.go('output', { id: launchRes.data.id, type: relaunchType }, { reload: true }); - } - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - } - }); - }; - - vm.$onInit = () => { - vm.showRelaunch = vm.job.type !== 'system_job' && vm.job.summary_fields.user_capabilities.start; - - vm.icon = 'icon-launch'; - vm.dropdownTitle = strings.get('relaunch.DROPDOWN_TITLE'); - vm.dropdownOptions = [ - { - name: strings.get('relaunch.ALL'), - icon: 'icon-host-all' - }, - { - name: strings.get('relaunch.FAILED'), - icon: 'icon-host-failed' - } - ]; - - updateTooltip(); - - $scope.$watch('vm.job.status', () => { - updateTooltip(); - }); - }; - - vm.relaunchJob = () => { - if (vm.job.type === 'inventory_update') { - const inventorySource = new InventorySource(); - - inventorySource.getUpdate(vm.job.inventory_source) - .then((getUpdateRes) => { - if (getUpdateRes.data.can_update) { - inventorySource.postUpdate(vm.job.inventory_source) - .then((postUpdateRes) => { - if (!$state.is('jobs')) { - $state.go('output', { id: postUpdateRes.data.id, type: 'inventory' }, { reload: true }); - } - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - } else { - Alert( - 'Permission Denied', 'You do not have permission to sync this inventory source. Please contact your system administrator.', - 'alert-danger' - ); - } - }); - } else if (vm.job.type === 'project_update') { - const project = new Project(); - - project.getUpdate(vm.job.project) - .then((getUpdateRes) => { - if (getUpdateRes.data.can_update) { - project.postUpdate(vm.job.project) - .then((postUpdateRes) => { - if (!$state.is('jobs')) { - $state.go('output', { id: postUpdateRes.data.id, type: 'project' }, { reload: true }); - } - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - } else { - Alert( - 'Permission Denied', 'You do not have access to update this project. Please contact your system administrator.', - 'alert-danger' - ); - } - }); - } else if (vm.job.type === 'workflow_job') { - const workflowJob = new WorkflowJob(); - - workflowJob.postRelaunch({ - id: vm.job.id - }).then((launchRes) => { - if (!$state.is('jobs')) { - $state.go('workflowResults', { id: launchRes.data.id }, { reload: true }); - } - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - } else if (vm.job.type === 'ad_hoc_command') { - const adHocCommand = new AdHocCommand(); - - adHocCommand.getRelaunch({ - id: vm.job.id - }).then((getRelaunchRes) => { - if ( - getRelaunchRes.data.passwords_needed_to_start && - getRelaunchRes.data.passwords_needed_to_start.length > 0 - ) { - AdhocRun({ scope: $scope, project_id: vm.job.id, relaunch: true }); - } else { - adHocCommand.postRelaunch({ - id: vm.job.id - }).then((launchRes) => { - if (!$state.is('jobs')) { - $state.go('output', { id: launchRes.data.id, type: 'command' }, { reload: true }); - } - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - } - }); - } else if (vm.job.type === 'job') { - checkRelaunchPlaybook(); - } - }; - - vm.relaunchOn = (option) => { - checkRelaunchPlaybook(option); - }; - - vm.relaunchJobWithPassword = () => { - jobObj.postRelaunch({ - id: vm.promptData.job, - relaunchData: PromptService.bundlePromptDataForRelaunch(vm.promptData) - }).then((launchRes) => { - if (!$state.is('jobs')) { - $state.go('output', { id: launchRes.data.job, type: 'playbook' }, { reload: true }); - } - }).catch(({ data, status }) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: `Error relaunching job. POST returned status: ${status}` - }); - }); - }; -} - -export default atRelaunch; diff --git a/awx/ui/client/lib/components/relaunchButton/relaunchButton.partial.html b/awx/ui/client/lib/components/relaunchButton/relaunchButton.partial.html deleted file mode 100644 index 22f71201526b..000000000000 --- a/awx/ui/client/lib/components/relaunchButton/relaunchButton.partial.html +++ /dev/null @@ -1,35 +0,0 @@ -
- -
- - - -
- - - -
diff --git a/awx/ui/client/lib/components/tabs/_index.less b/awx/ui/client/lib/components/tabs/_index.less deleted file mode 100644 index e999a7561394..000000000000 --- a/awx/ui/client/lib/components/tabs/_index.less +++ /dev/null @@ -1,36 +0,0 @@ -.at-TabGroup { - margin-top: @at-margin-panel; -} - -.at-Tab { - margin: 0 @at-margin-item-column 0 0; - font-size: @at-font-size-body; - line-height: 1; -} - -.at-Tab--active { - &, &:hover, &:active, &:focus { - color: @at-color-tab-text-default-active; - background-color: @at-color-tab-default-active; - border-color: @at-color-tab-border-default-active; - cursor: default; - } -} - -.at-Tab--disabled { - &, &:hover, &:active, &:focus { - background-color: @at-color-tab-default-disabled; - color: @at-color-tab-text-default-disabled; - border-color: @at-color-tab-border-default-disabled; - opacity: 0.65; - cursor: not-allowed; - } -} - -.at-TabGroup + .at-Panel-body { - margin-top: 20px; -} - -.at-TabGroup--padBelow { - margin-bottom: 20px; -} diff --git a/awx/ui/client/lib/components/tabs/group.directive.js b/awx/ui/client/lib/components/tabs/group.directive.js deleted file mode 100644 index d3c55a295fb4..000000000000 --- a/awx/ui/client/lib/components/tabs/group.directive.js +++ /dev/null @@ -1,36 +0,0 @@ -const templateUrl = require('~components/tabs/group.partial.html'); - -function AtTabGroupController () { - const vm = this; - - vm.tabs = []; - - vm.register = tab => { - tab.active = true; - - vm.tabs.push(tab); - }; - - vm.clearActive = () => { - vm.tabs.forEach((tab) => { - tab.state._active = false; - }); - }; -} - -function atTabGroup () { - return { - restrict: 'E', - replace: true, - require: 'atTabGroup', - transclude: true, - templateUrl, - controller: AtTabGroupController, - controllerAs: 'vm', - scope: { - state: '=' - } - }; -} - -export default atTabGroup; diff --git a/awx/ui/client/lib/components/tabs/group.partial.html b/awx/ui/client/lib/components/tabs/group.partial.html deleted file mode 100644 index 8f4e538da4c4..000000000000 --- a/awx/ui/client/lib/components/tabs/group.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
diff --git a/awx/ui/client/lib/components/tabs/tab.directive.js b/awx/ui/client/lib/components/tabs/tab.directive.js deleted file mode 100644 index 4c7eea37858e..000000000000 --- a/awx/ui/client/lib/components/tabs/tab.directive.js +++ /dev/null @@ -1,55 +0,0 @@ -const templateUrl = require('~components/tabs/tab.partial.html'); - -function atTabLink (scope, el, attrs, controllers) { - const groupController = controllers[0]; - const tabController = controllers[1]; - - tabController.init(scope, groupController); -} - -function AtTabController ($state) { - const vm = this; - - let scope; - let group; - - vm.init = (_scope_, _group_) => { - scope = _scope_; - group = _group_; - - group.register(scope); - }; - - vm.go = () => { - if (scope.state._disabled || scope.state._active) { - return; - } - - if (scope.state._go) { - $state.go(scope.state._go, scope.state._params, { reload: true }); - } else { - group.clearActive(); - scope.state._active = true; - } - }; -} - -AtTabController.$inject = ['$state']; - -function atTab () { - return { - restrict: 'E', - replace: true, - transclude: true, - require: ['^^atTabGroup', 'atTab'], - templateUrl, - controller: AtTabController, - controllerAs: 'vm', - link: atTabLink, - scope: { - state: '=' - } - }; -} - -export default atTab; diff --git a/awx/ui/client/lib/components/tabs/tab.partial.html b/awx/ui/client/lib/components/tabs/tab.partial.html deleted file mode 100644 index 747e47057143..000000000000 --- a/awx/ui/client/lib/components/tabs/tab.partial.html +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/awx/ui/client/lib/components/truncate/_index.less b/awx/ui/client/lib/components/truncate/_index.less deleted file mode 100644 index bc26f1c820bf..000000000000 --- a/awx/ui/client/lib/components/truncate/_index.less +++ /dev/null @@ -1,31 +0,0 @@ -.at-Truncate { - display: flex; - align-items: center; - - .at-Truncate-text { - font-family: monospace, Courier, "Courier New", "Open Sans", sans-serif; - } - - .at-Truncate-copy { - color: @at-gray-b7; - cursor: pointer; - margin-left: 10px; - - i:hover { - color: @at-blue; - } - } - - .at-Truncate-textarea { - background: transparent; - border: none; - box-shadow: none; - height: 2em; - left: 0px; - outline: none; - padding: 0px; - position: fixed; - top: 0px; - width: 2em; - } -} \ No newline at end of file diff --git a/awx/ui/client/lib/components/truncate/truncate.directive.js b/awx/ui/client/lib/components/truncate/truncate.directive.js deleted file mode 100644 index 8cc3df8bef28..000000000000 --- a/awx/ui/client/lib/components/truncate/truncate.directive.js +++ /dev/null @@ -1,66 +0,0 @@ -const templateUrl = require('~components/truncate/truncate.partial.html'); - -function atTruncateLink (scope, el, attr, ctrl) { - const truncateController = ctrl; - const { string } = attr; - const { maxlength } = attr; - - truncateController.init(el, string, maxlength); -} - -function AtTruncateController (strings) { - const vm = this; - let el; - let string; - let maxlength; - vm.strings = strings; - - vm.init = (_el_, _string_, _maxlength_) => { - el = _el_; - string = _string_; - maxlength = _maxlength_; - vm.truncatedString = string.substring(0, maxlength); - }; - - vm.copyToClipboard = () => { - vm.tooltip.popover.text = vm.strings.get('truncate.COPIED'); - - const textarea = el[0].getElementsByClassName('at-Truncate-textarea')[0]; - textarea.value = string; - textarea.select(); - - document.execCommand('copy'); - }; - - vm.tooltip = { - popover: { - text: vm.strings.get('truncate.DEFAULT'), - on: 'mouseover', - position: 'top', - icon: 'fa fa-clone', - resetOnExit: true, - click: vm.copyToClipboard - } - }; -} - -AtTruncateController.$inject = ['ComponentsStrings']; - -function atTruncate () { - return { - restrict: 'E', - replace: true, - transclude: true, - templateUrl, - controller: AtTruncateController, - controllerAs: 'vm', - link: atTruncateLink, - scope: { - state: '=', - maxLength: '@', - string: '@' - } - }; -} - -export default atTruncate; diff --git a/awx/ui/client/lib/components/truncate/truncate.partial.html b/awx/ui/client/lib/components/truncate/truncate.partial.html deleted file mode 100644 index aa329908eb4d..000000000000 --- a/awx/ui/client/lib/components/truncate/truncate.partial.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
- {{vm.truncatedString}} -
-
- -
- -
diff --git a/awx/ui/client/lib/components/utility/_index.less b/awx/ui/client/lib/components/utility/_index.less deleted file mode 100644 index f9851bef2be7..000000000000 --- a/awx/ui/client/lib/components/utility/_index.less +++ /dev/null @@ -1,5 +0,0 @@ -.at-Divider { - clear: both; - margin: 0; - padding: 0; -} diff --git a/awx/ui/client/lib/components/utility/divider.directive.js b/awx/ui/client/lib/components/utility/divider.directive.js deleted file mode 100644 index 8aa71fad5014..000000000000 --- a/awx/ui/client/lib/components/utility/divider.directive.js +++ /dev/null @@ -1,12 +0,0 @@ -const templateUrl = require('~components/utility/divider.partial.html'); - -function atPanelBody () { - return { - restrict: 'E', - replace: true, - templateUrl, - scope: false - }; -} - -export default atPanelBody; diff --git a/awx/ui/client/lib/components/utility/divider.partial.html b/awx/ui/client/lib/components/utility/divider.partial.html deleted file mode 100644 index 514695d55ca1..000000000000 --- a/awx/ui/client/lib/components/utility/divider.partial.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/awx/ui/client/lib/models/AdHocCommand.js b/awx/ui/client/lib/models/AdHocCommand.js deleted file mode 100644 index 7bea2677ac33..000000000000 --- a/awx/ui/client/lib/models/AdHocCommand.js +++ /dev/null @@ -1,49 +0,0 @@ -let $http; -let BaseModel; - -function getRelaunch (params) { - const req = { - method: 'GET', - url: `${this.path}${params.id}/relaunch/` - }; - - return $http(req); -} - -function postRelaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/relaunch/` - }; - - return $http(req); -} - -function getStats () { - return Promise.resolve(null); -} - -function AdHocCommandModel (method, resource, config) { - BaseModel.call(this, 'ad_hoc_commands'); - - this.Constructor = AdHocCommandModel; - this.postRelaunch = postRelaunch.bind(this); - this.getRelaunch = getRelaunch.bind(this); - this.getStats = getStats.bind(this); - - return this.create(method, resource, config); -} - -function AdHocCommandModelLoader (_$http_, _BaseModel_) { - $http = _$http_; - BaseModel = _BaseModel_; - - return AdHocCommandModel; -} - -AdHocCommandModelLoader.$inject = [ - '$http', - 'BaseModel', -]; - -export default AdHocCommandModelLoader; diff --git a/awx/ui/client/lib/models/Application.js b/awx/ui/client/lib/models/Application.js deleted file mode 100644 index 2a364eb9e739..000000000000 --- a/awx/ui/client/lib/models/Application.js +++ /dev/null @@ -1,80 +0,0 @@ -let Base; - -function createFormSchema (method, config) { - function mungeSelectFromOptions (configObj, value) { - configObj.choices = [[null, '']].concat(configObj.choices); - configObj._data = configObj.choices; - configObj._exp = 'choice[1] for choice in state._data'; - configObj._format = 'selectFromOptions'; - - configObj._data.forEach((val, i) => { - if (val[0] === value) { - configObj._value = configObj._data[i]; - } - }); - - return configObj; - } - - if (!config) { - config = method; - method = 'GET'; - } - - const schema = Object.assign({}, this.options(`actions.${method.toUpperCase()}`)); - - if (config && config.omit) { - config.omit.forEach(key => delete schema[key]); - } - - Object.keys(schema).forEach(key => { - schema[key].id = key; - - if (this.has(key) && schema[key].type !== 'choice') { - schema[key]._value = this.get(key); - } - - if (schema[key].type === 'choice') { - schema[key] = mungeSelectFromOptions(schema[key], this.get(key)); - } - }); - - // necessary because authorization_grant_type is not changeable on update - if (method === 'put') { - schema.authorization_grant_type = mungeSelectFromOptions(Object.assign({}, this - .options('actions.GET.authorization_grant_type')), this - .get('authorization_grant_type')); - - schema.authorization_grant_type._required = false; - schema.authorization_grant_type._disabled = true; - } - - return schema; -} - -function setDependentResources () { - this.dependentResources = []; -} - -function ApplicationModel (method, resource, config) { - // TODO: change to applications - Base.call(this, 'applications'); - - this.Constructor = ApplicationModel; - this.createFormSchema = createFormSchema.bind(this); - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function ApplicationModelLoader (BaseModel) { - Base = BaseModel; - - return ApplicationModel; -} - -ApplicationModelLoader.$inject = [ - 'BaseModel', -]; - -export default ApplicationModelLoader; diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js deleted file mode 100644 index a7cc321806fc..000000000000 --- a/awx/ui/client/lib/models/Base.js +++ /dev/null @@ -1,732 +0,0 @@ -let $http; -let $q; -let cache; -let strings; - -function request (method, resource, config) { - let req = this.parseRequestConfig(method, resource, config); - - if (Array.isArray(req.method)) { - const promises = req.method.map((_method, i) => { - const _resource = Array.isArray(req.resource) ? req.resource[i] : req.resource; - - req = this.parseRequestConfig(_method, _resource, config); - - if (this.isCacheable(req)) { - return this.requestWithCache(req); - } - - return this.request(req); - }); - - return $q.all(promises); - } - - if (this.isCacheable(req)) { - return this.requestWithCache(req); - } - - return this.http[req.method](req); -} - -function requestWithCache (config) { - const key = cache.createKey(config.method, this.path, config.resource); - - return cache.get(key) - .then(data => { - if (data) { - this.model[config.method.toUpperCase()] = data; - - return data; - } - - return this.http[config.method](config) - .then(res => { - cache.put(key, res.data); - - return res; - }); - }); -} - -/** - * Intended to be useful in searching and filtering results using params - * supported by the API. - * - * @arg {Object} params - An object of keys and values to to format and - * to the URL as a query string. Refer to the API documentation for the - * resource in use for specifics. - * @arg {Object} config - Configuration specific to the UI to accommodate - * common use cases. - * - * @yields {boolean} - Indicating a match has been found. If so, the results - * are set on the model. - */ -function search (params = {}, config = {}) { - const req = { - method: 'GET', - url: this.path - }; - - if (typeof params === 'string') { - req.url = '?params'; - } else if (Array.isArray(params)) { - req.url += `?${params.join('&')}`; - } else { - req.params = params; - } - - return $http(req) - .then(({ data }) => { - if (!data.count) { - return false; - } - - if (config.unique) { - if (data.count !== 1) { - return false; - } - - [this.model.GET] = data.results; - } else { - this.model.GET = data; - } - - return true; - }); -} - -function httpGet (config = {}) { - const req = { - method: 'GET', - url: this.path - }; - - if (config.params) { - req.params = config.params; - - if (config.params.page_size) { - this.page.size = config.params.page_size; - this.page.current = 1; - - if (config.pageCache) { - this.page.cachedPages = this.page.cachedPages || {}; - this.page.cache = this.page.cache || {}; - this.page.limit = config.pageLimit || false; - - if (!_.has(this.page.cachedPages, 'root')) { - this.page.cachedPages.root = []; - } - - if (!_.has(this.page.cache, 'root')) { - this.page.cache.root = {}; - } - } - } - } - - if (typeof config.resource === 'object') { - this.model.GET = config.resource; - - return $q.resolve(); - } else if (config.resource) { - req.url = `${this.path}${config.resource}/`; - } - - return $http(req) - .then(res => { - this.model.GET = res.data; - - if (config.pageCache) { - this.page.cache.root[this.page.current] = res.data.results; - this.page.cachedPages.root.push(this.page.current); - this.page.count = res.data.count; - this.page.last = Math.ceil(res.data.count / this.page.size); - } - - return res; - }); -} - -function httpPost (config = {}) { - const req = { - method: 'POST', - url: this.path, - data: config.data - }; - - if (config.url) { - req.url = `${this.path}${config.url}`; - } - - return $http(req) - .then(res => { - this.model.GET = res.data; - - return res; - }); -} - -function httpPatch (config = {}) { - const req = { - method: 'PUT', - url: `${this.path}${this.get('id')}/`, - data: config.changes - }; - - return $http(req); -} - -function httpPut (config = {}) { - const model = _.merge(this.get(), config.data); - - const req = { - method: 'PUT', - url: `${this.path}${this.get('id')}/`, - data: model - }; - - return $http(req); -} - -function httpOptions (config = {}) { - const req = { - method: 'OPTIONS', - url: this.path - }; - - if (config.resource) { - req.url = `${this.path}${config.resource}/`; - } - - return $http(req) - .then(res => { - this.model.OPTIONS = res.data; - - return res; - }); -} - -function httpDelete (config = {}) { - const req = { - method: 'DELETE', - url: this.path - }; - - if (config.resource) { - req.url = `${this.path}${config.resource}/`; - } - - return $http(req); -} - -function options (keys) { - return this.find('options', keys); -} - -function get (keys) { - return this.find('get', keys); -} - -function unset (method, keys) { - if (!keys) { - keys = method; - method = 'GET'; - } - - method = method.toUpperCase(); - keys = keys.split('.'); - - if (!keys.length) { - delete this.model[method]; - } else if (keys.length === 1) { - delete this.model[method][keys[0]]; - } else { - const property = keys.splice(-1); - keys = keys.join('.'); - - const model = this.find(method, keys); - delete model[property]; - } -} - -function set (method, keys, value) { - if (!value) { - value = keys; - keys = method; - method = 'GET'; - } - - keys = keys.split('.'); - - if (keys.length === 1) { - this.model[keys[0]] = value; - } else { - const property = keys.splice(-1); - keys = keys.join('.'); - - const model = this.find(method, keys); - - model[property] = value; - } -} - -function match (method, key, value) { - if (!value) { - value = key; - key = method; - method = 'GET'; - } - - const model = this.model[method.toUpperCase()]; - - if (!model) { - return null; - } - - if (!model.results) { - if (model[key] === value) { - return model; - } - - return null; - } - - const result = model.results.filter(object => object[key] === value); - - return result.length === 0 ? null : result[0]; -} - -function find (method, keys) { - let value = this.model[method.toUpperCase()]; - - if (!keys) { - return value; - } - - try { - keys = keys.split('.'); - - keys.forEach(key => { - const bracketIndex = key.indexOf('['); - const hasArray = bracketIndex !== -1; - - if (!hasArray) { - value = value[key]; - return; - } - - if (bracketIndex === 0) { - value = value[Number(key.substring(1, key.length - 1))]; - return; - } - - const prop = key.substring(0, bracketIndex); - const index = Number(key.substring(bracketIndex + 1, key.length - 1)); - - value = value[prop][index]; - }); - } catch (err) { - return undefined; - } - - return value; -} - -function has (method, keys) { - if (!keys) { - keys = method; - method = 'GET'; - } - - method = method.toUpperCase(); - - let value; - switch (method) { - case 'OPTIONS': - value = this.options(keys); - break; - default: - value = this.get(keys); - } - - return value !== undefined && value !== null; -} - -function extend (method, related, config = {}) { - const req = this.parseRequestConfig(method.toUpperCase(), config); - - if (_.get(config, 'params.page_size')) { - this.page.size = config.params.page_size; - this.page.current = 1; - - if (config.pageCache) { - this.page.cachedPages = this.page.cachedPages || {}; - this.page.cache = this.page.cache || {}; - this.page.limit = config.pageLimit || false; - - if (!_.has(this.page.cachedPages, `related.${related}`)) { - _.set(this.page.cachedPages, `related.${related}`, []); - } - - if (!_.has(this.page.cache, `related.${related}`)) { - _.set(this.page.cache, `related.${related}`, []); - } - } - } - - if (this.has(req.method, `related.${related}`)) { - req.url = this.get(`related.${related}`); - - Object.assign(req, config); - - return $http(req) - .then(({ data }) => { - this.set(req.method, `related.${related}`, data); - - if (config.pageCache) { - this.page.cache.related[related][this.page.current] = data.results; - this.page.cachedPages.related[related].push(this.page.current); - this.page.count = data.count; - this.page.last = Math.ceil(data.count / this.page.size); - } - - return this; - }); - } - - return Promise.reject(new Error(`No related property, ${related}, exists`)); -} - -function updateCount (count) { - this.page.count = count; - this.page.last = Math.ceil(count / this.page.size); - - return this.page.last; -} - -function goToPage (config) { - const params = config.params || {}; - const { page } = config; - - let url; - let key; - let pageNumber; - let pageCache; - let pagesInCache; - - if (config.related) { - url = `${this.endpoint}${config.related}/`; - key = `related.${config.related}`; - } else { - url = this.endpoint; - key = 'root'; - } - - params.page_size = this.page.size; - - if (page === 'next') { - pageNumber = this.page.current + 1; - } else if (page === 'previous') { - pageNumber = this.page.current - 1; - } else if (page === 'first') { - pageNumber = 1; - } else if (page === 'last') { - pageNumber = this.page.last; - } else { - pageNumber = page; - } - - if (pageNumber < 1 || pageNumber > this.page.last) { - return Promise.resolve(null); - } - - this.page.current = pageNumber; - - if (this.page.cache) { - pageCache = _.get(this.page.cache, key); - pagesInCache = _.get(this.page.cachedPages, key); - - if (_.has(pageCache, pageNumber)) { - return Promise.resolve({ - results: pageCache[pageNumber], - page: pageNumber - }); - } - } - - params.page_size = this.page.size; - params.page = pageNumber; - - const req = { - method: 'GET', - url, - params - }; - - return $http(req) - .then(({ data }) => { - if (pageCache) { - pageCache[pageNumber] = data.results; - pagesInCache.push(pageNumber); - - if (pagesInCache.length > this.page.limit) { - const pageToDelete = pagesInCache.shift(); - - delete pageCache[pageToDelete]; - } - } - - return { - results: data.results, - page: pageNumber - }; - }); -} - -function next (config = {}) { - config.page = 'next'; - - return this.goToPage(config); -} - -function prev (config = {}) { - config.page = 'previous'; - - return this.goToPage(config); -} - -function normalizePath (resource) { - const version = '/api/v2/'; - - return `${version}${resource}/`; -} - -function isEditable () { - let canEdit = this.get('summary_fields.user_capabilities.edit'); - - if (canEdit === undefined) { - canEdit = true; - } - - if (canEdit) { - return true; - } - - if (this.has('options', 'actions.PUT')) { - return true; - } - - return false; -} - -function isCreatable () { - if (this.has('options', 'actions.POST')) { - return true; - } - - return false; -} - -function isCacheable () { - if (this.settings.cache === true) { - return true; - } - - return false; -} - -function graft (id) { - let item = this.get('results').filter(result => result.id === id); - - item = item ? item[0] : undefined; - - if (!item) { - return undefined; - } - - return new this.Constructor('get', item, true); -} - -function getDependentResourceCounts (id) { - this.setDependentResources(id); - - const promises = []; - - this.dependentResources.forEach(resource => { - promises.push(resource.model.request('get', { params: resource.params }) - .then(res => ({ - label: resource.model.label, - count: res.data.count - }))); - }); - - return Promise.all(promises); -} - -function copy () { - if (!this.has('POST', 'related.copy')) { - return Promise.reject(new Error('No related property, copy, exists')); - } - - const date = new Date(); - const name = `${this.get('name')}@${date.toLocaleTimeString()}`; - - const url = `${this.path}${this.get('id')}/copy/`; - - const req = { - url, - method: 'POST', - data: { name } - }; - - return $http(req).then(res => res.data); -} - -/** - * `create` is called on instantiation of every model. Models can be - * instantiated empty or with `GET` and/or `OPTIONS` requests that yield data. - * If model data already exists a new instance can be created (see: `graft`) - * with existing data. - * - * @arg {string=} method - Populate the model with `GET` or `OPTIONS` data. - * @arg {(string|Object)=} resource - An `id` reference to a particular - * resource or an existing model's data. - * @arg {config=} config - Create a new instance from existing model data. - * - * @returns {(Object|Promise)} - Returns a reference to the model instance - * if an empty instance or graft is created. Otherwise, a promise yielding - * a model instance is returned. - */ -function create (method, resource, config) { - const req = this.parseRequestConfig(method, resource, config); - - if (!req || !req.method) { - return this; - } - - if (req.resource) { - this.setEndpoint(req.resource); - } - - this.promise = this.request(req); - - if (req.graft) { - return this; - } - - return this.promise - .then(() => this); -} - -function setEndpoint (resource) { - if (Array.isArray(resource)) { - this.endpoint = `${this.path}${resource[0]}/`; - } else { - this.endpoint = `${this.path}${resource}/`; - } -} - -function parseRequestConfig (method, resource, config) { - if (!method) { - return null; - } - - let req = {}; - - if (Array.isArray(method)) { - if (Array.isArray(resource)) { - req.resource = resource; - } else if (resource === null) { - req.resource = undefined; - } else if (typeof resource === 'object') { - req = resource; - } - - req.method = method; - } else if (typeof method === 'string') { - if (resource === null) { - req.resource = undefined; - } else if (typeof resource === 'object') { - req = resource; - } else { - req.resource = resource; - } - - req.method = method; - } else if (typeof method === 'object') { - req = method; - } else { - req = config; - req.method = method; - req.resource = resource === null ? undefined : resource; - } - - return req; -} - -/** - * Base functionality for API interaction. - * - * @arg {string} resource - The API resource for the model extending BaseModel to - * use. - * @arg {Object=} settings - Configuration applied to all instances of the - * extending model. - * @arg {boolean=} settings.cache - Cache the model data. - * - */ -function BaseModel (resource, settings) { - this.create = create; - this.find = find; - this.get = get; - this.goToPage = goToPage; - this.graft = graft; - this.has = has; - this.isEditable = isEditable; - this.isCacheable = isCacheable; - this.isCreatable = isCreatable; - this.match = match; - this.next = next; - this.normalizePath = normalizePath; - this.options = options; - this.parseRequestConfig = parseRequestConfig; - this.prev = prev; - this.request = request; - this.requestWithCache = requestWithCache; - this.search = search; - this.set = set; - this.setEndpoint = setEndpoint; - this.unset = unset; - this.extend = extend; - this.copy = copy; - this.getDependentResourceCounts = getDependentResourceCounts; - this.updateCount = updateCount; - - this.http = { - get: httpGet.bind(this), - options: httpOptions.bind(this), - patch: httpPatch.bind(this), - post: httpPost.bind(this), - put: httpPut.bind(this), - delete: httpDelete.bind(this) - }; - - this.page = {}; - this.model = {}; - this.path = this.normalizePath(resource); - this.label = strings.get(`${resource}.LABEL`); - this.settings = settings || {}; -} - -function BaseModelLoader (_$http_, _$q_, _cache_, ModelsStrings) { - $http = _$http_; - $q = _$q_; - cache = _cache_; - strings = ModelsStrings; - - return BaseModel; -} - -BaseModelLoader.$inject = ['$http', '$q', 'CacheService', 'ModelsStrings']; - -export default BaseModelLoader; diff --git a/awx/ui/client/lib/models/Config.js b/awx/ui/client/lib/models/Config.js deleted file mode 100644 index 9f2e3ab87a35..000000000000 --- a/awx/ui/client/lib/models/Config.js +++ /dev/null @@ -1,39 +0,0 @@ -let $log; -let Base; - -function getTruncatedVersion () { - let version; - - try { - [version] = this.get('version').split('-'); - } catch (err) { - $log.error(err); - } - - return version; -} - -function isOpen () { - return this.get('license_info.license_type') === 'open'; -} - -function ConfigModel (method, resource, config) { - Base.call(this, 'config', { cache: true }); - - this.Constructor = ConfigModel; - this.getTruncatedVersion = getTruncatedVersion; - this.isOpen = isOpen; - - return this.create(method, resource, config); -} - -function ConfigModelLoader (BaseModel, _$log_) { - Base = BaseModel; - $log = _$log_; - - return ConfigModel; -} - -ConfigModelLoader.$inject = ['BaseModel', '$log']; - -export default ConfigModelLoader; diff --git a/awx/ui/client/lib/models/Credential.js b/awx/ui/client/lib/models/Credential.js deleted file mode 100644 index 93d29bb0024a..000000000000 --- a/awx/ui/client/lib/models/Credential.js +++ /dev/null @@ -1,112 +0,0 @@ -const ENCRYPTED_VALUE = '$encrypted$'; - -let Base; -let Project; -let JobTemplate; -let Inventory; -let InventorySource; - -function createFormSchema (method, config) { - if (!config) { - config = method; - method = 'GET'; - } - - const schema = Object.assign({}, this.options(`actions.${method.toUpperCase()}`)); - - if (config && config.omit) { - config.omit.forEach(key => delete schema[key]); - } - - Object.keys(schema).forEach(key => { - schema[key].id = key; - - if (this.has(key)) { - schema[key]._value = this.get(key); - } - }); - - return schema; -} - -function assignInputGroupValues (inputs) { - if (!inputs) { - return []; - } - - return inputs.map(input => { - const value = this.get(`inputs.${input.id}`); - - input._value = value; - input._encrypted = value === ENCRYPTED_VALUE; - - return input; - }); -} - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new Project(), - params: { - credential: id - } - }, - { - model: new JobTemplate(), - params: { - credential: id, - ask_credential_on_launch: false - } - }, - { - model: new Inventory(), - params: { - insights_credential: id - } - }, - { - model: new InventorySource(), - params: { - credential: id - } - } - ]; -} - -function CredentialModel (method, resource, config) { - Base.call(this, 'credentials'); - - this.Constructor = CredentialModel; - this.createFormSchema = createFormSchema.bind(this); - this.assignInputGroupValues = assignInputGroupValues.bind(this); - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function CredentialModelLoader ( - BaseModel, - ProjectModel, - JobTemplateModel, - InventoryModel, - InventorySourceModel -) { - Base = BaseModel; - Project = ProjectModel; - JobTemplate = JobTemplateModel; - Inventory = InventoryModel; - InventorySource = InventorySourceModel; - - return CredentialModel; -} - -CredentialModelLoader.$inject = [ - 'BaseModel', - 'ProjectModel', - 'JobTemplateModel', - 'InventoryModel', - 'InventorySourceModel' -]; - -export default CredentialModelLoader; diff --git a/awx/ui/client/lib/models/CredentialType.js b/awx/ui/client/lib/models/CredentialType.js deleted file mode 100644 index 0607350ad81e..000000000000 --- a/awx/ui/client/lib/models/CredentialType.js +++ /dev/null @@ -1,68 +0,0 @@ -let Base; -let Credential; - -function categorizeByKind () { - const group = {}; - - this.get('results').forEach(result => { - group[result.kind] = group[result.kind] || []; - group[result.kind].push(result); - }); - - return Object.keys(group).map(category => ({ - data: group[category], - category - })); -} - -function mergeInputProperties () { - if (!this.has('inputs.fields')) { - return undefined; - } - - const required = this.get('inputs.required'); - - return this.get('inputs.fields').forEach((field, i) => { - if (!required || required.indexOf(field.id) === -1) { - this.set(`inputs.fields[${i}].required`, false); - } else { - this.set(`inputs.fields[${i}].required`, true); - } - }); -} - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new Credential(), - params: { - credential_type: id - } - } - ]; -} - -function CredentialTypeModel (method, resource, config) { - Base.call(this, 'credential_types'); - - this.Constructor = CredentialTypeModel; - this.categorizeByKind = categorizeByKind.bind(this); - this.mergeInputProperties = mergeInputProperties.bind(this); - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function CredentialTypeModelLoader (BaseModel, CredentialModel) { - Base = BaseModel; - Credential = CredentialModel; - - return CredentialTypeModel; -} - -CredentialTypeModelLoader.$inject = [ - 'BaseModel', - 'CredentialModel' -]; - -export default CredentialTypeModelLoader; diff --git a/awx/ui/client/lib/models/Instance.js b/awx/ui/client/lib/models/Instance.js deleted file mode 100644 index 09b7df0547e7..000000000000 --- a/awx/ui/client/lib/models/Instance.js +++ /dev/null @@ -1,47 +0,0 @@ -let Base; - -function createFormSchema (method, config) { - if (!config) { - config = method; - method = 'GET'; - } - - const schema = Object.assign({}, this.options(`actions.${method.toUpperCase()}`)); - - if (config && config.omit) { - config.omit.forEach(key => delete schema[key]); - } - - Object.keys(schema).forEach(key => { - schema[key].id = key; - - if (this.has(key)) { - schema[key]._value = this.get(key); - } - }); - - return schema; -} - -function InstanceModel (method, resource, config) { - // Base takes two args: resource and settings - // resource is the string endpoint - Base.call(this, 'instances'); - - this.Constructor = InstanceModel; - this.createFormSchema = createFormSchema.bind(this); - - return this.create(method, resource, config); -} - -function InstanceModelLoader (BaseModel) { - Base = BaseModel; - - return InstanceModel; -} - -InstanceModelLoader.$inject = [ - 'BaseModel' -]; - -export default InstanceModelLoader; diff --git a/awx/ui/client/lib/models/InstanceGroup.js b/awx/ui/client/lib/models/InstanceGroup.js deleted file mode 100644 index cc82432c422d..000000000000 --- a/awx/ui/client/lib/models/InstanceGroup.js +++ /dev/null @@ -1,47 +0,0 @@ -let Base; - -function createFormSchema (method, config) { - if (!config) { - config = method; - method = 'GET'; - } - - const schema = Object.assign({}, this.options(`actions.${method.toUpperCase()}`)); - - if (config && config.omit) { - config.omit.forEach(key => delete schema[key]); - } - - Object.keys(schema).forEach(key => { - schema[key].id = key; - - if (this.has(key)) { - schema[key]._value = this.get(key); - } - }); - - return schema; -} - -function InstanceGroupModel (method, resource, config) { - // Base takes two args: resource and settings - // resource is the string endpoint - Base.call(this, 'instance_groups'); - - this.Constructor = InstanceGroupModel; - this.createFormSchema = createFormSchema.bind(this); - - return this.create(method, resource, config); -} - -function InstanceGroupModelLoader (BaseModel) { - Base = BaseModel; - - return InstanceGroupModel; -} - -InstanceGroupModelLoader.$inject = [ - 'BaseModel' -]; - -export default InstanceGroupModelLoader; diff --git a/awx/ui/client/lib/models/Inventory.js b/awx/ui/client/lib/models/Inventory.js deleted file mode 100644 index 3d270dfc79de..000000000000 --- a/awx/ui/client/lib/models/Inventory.js +++ /dev/null @@ -1,36 +0,0 @@ -let Base; -let JobTemplate; - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new JobTemplate(), - params: { - inventory: id - } - } - ]; -} - -function InventoryModel (method, resource, config) { - Base.call(this, 'inventories'); - - this.Constructor = InventoryModel; - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function InventoryModelLoader (BaseModel, JobTemplateModel) { - Base = BaseModel; - JobTemplate = JobTemplateModel; - - return InventoryModel; -} - -InventoryModelLoader.$inject = [ - 'BaseModel', - 'JobTemplateModel' -]; - -export default InventoryModelLoader; diff --git a/awx/ui/client/lib/models/InventoryScript.js b/awx/ui/client/lib/models/InventoryScript.js deleted file mode 100644 index 1b759410abd3..000000000000 --- a/awx/ui/client/lib/models/InventoryScript.js +++ /dev/null @@ -1,36 +0,0 @@ -let Base; -let InventorySource; - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new InventorySource(), - params: { - source_script: id - } - } - ]; -} - -function InventoryScriptModel (method, resource, config) { - Base.call(this, 'inventory_scripts'); - - this.Constructor = InventoryScriptModel; - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function InventoryScriptModelLoader (BaseModel, InventorySourceModel) { - Base = BaseModel; - InventorySource = InventorySourceModel; - - return InventoryScriptModel; -} - -InventoryScriptModelLoader.$inject = [ - 'BaseModel', - 'InventorySourceModel' -]; - -export default InventoryScriptModelLoader; diff --git a/awx/ui/client/lib/models/InventorySource.js b/awx/ui/client/lib/models/InventorySource.js deleted file mode 100644 index 0d68a1178007..000000000000 --- a/awx/ui/client/lib/models/InventorySource.js +++ /dev/null @@ -1,63 +0,0 @@ -let Base; -let WorkflowJobTemplateNode; -let $http; - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new WorkflowJobTemplateNode(), - params: { - unified_job_template: id - } - } - ]; -} - -function getUpdate (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/update/` - }; - - return $http(req); -} - -function postUpdate (id) { - const req = { - method: 'POST', - url: `${this.path}${id}/update/` - }; - - return $http(req); -} - -function InventorySourceModel (method, resource, config) { - Base.call(this, 'inventory_sources'); - - this.Constructor = InventorySourceModel; - this.setDependentResources = setDependentResources.bind(this); - this.getUpdate = getUpdate.bind(this); - this.postUpdate = postUpdate.bind(this); - - return this.create(method, resource, config); -} - -function InventorySourceModelLoader ( - BaseModel, - WorkflowJobTemplateNodeModel, - _$http_ -) { - Base = BaseModel; - WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - $http = _$http_; - - return InventorySourceModel; -} - -InventorySourceModelLoader.$inject = [ - 'BaseModel', - 'WorkflowJobTemplateNodeModel', - '$http' -]; - -export default InventorySourceModelLoader; diff --git a/awx/ui/client/lib/models/InventoryUpdate.js b/awx/ui/client/lib/models/InventoryUpdate.js deleted file mode 100644 index 668a05459d62..000000000000 --- a/awx/ui/client/lib/models/InventoryUpdate.js +++ /dev/null @@ -1,27 +0,0 @@ -let BaseModel; - -function getStats () { - return Promise.resolve(null); -} - -function InventoryUpdateModel (method, resource, config) { - BaseModel.call(this, 'inventory_updates'); - - this.getStats = getStats.bind(this); - - this.Constructor = InventoryUpdateModel; - - return this.create(method, resource, config); -} - -function InventoryUpdateModelLoader (_BaseModel_) { - BaseModel = _BaseModel_; - - return InventoryUpdateModel; -} - -InventoryUpdateModelLoader.$inject = [ - 'BaseModel' -]; - -export default InventoryUpdateModelLoader; diff --git a/awx/ui/client/lib/models/Job.js b/awx/ui/client/lib/models/Job.js deleted file mode 100644 index 1e466b0e6d34..000000000000 --- a/awx/ui/client/lib/models/Job.js +++ /dev/null @@ -1,85 +0,0 @@ -let $http; -let BaseModel; - -function getRelaunch (params) { - const req = { - method: 'GET', - url: `${this.path}${params.id}/relaunch/` - }; - - return $http(req); -} - -function postRelaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/relaunch/` - }; - - if (params.relaunchData) { - req.data = params.relaunchData; - } - - return $http(req); -} - -function getStats () { - if (!this.has('GET', 'id')) { - return Promise.reject(new Error('No property, id, exists')); - } - - if (!this.has('GET', 'related.job_events')) { - return Promise.reject(new Error('No related property, job_events, exists')); - } - - const req = { - method: 'GET', - url: `${this.path}${this.get('id')}/job_events/`, - params: { event: 'playbook_on_stats' }, - }; - - return $http(req) - .then(({ data }) => { - if (data.results.length > 0) { - return data.results[0]; - } - - return null; - }); -} - -function getCredentials (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/credentials/` - }; - - return $http(req); -} - -function JobModel (method, resource, config) { - BaseModel.call(this, 'jobs'); - - this.Constructor = JobModel; - - this.postRelaunch = postRelaunch.bind(this); - this.getRelaunch = getRelaunch.bind(this); - this.getStats = getStats.bind(this); - this.getCredentials = getCredentials.bind(this); - - return this.create(method, resource, config); -} - -function JobModelLoader (_$http_, _BaseModel_) { - $http = _$http_; - BaseModel = _BaseModel_; - - return JobModel; -} - -JobModelLoader.$inject = [ - '$http', - 'BaseModel', -]; - -export default JobModelLoader; diff --git a/awx/ui/client/lib/models/JobEvent.js b/awx/ui/client/lib/models/JobEvent.js deleted file mode 100644 index 1c71ba9c546f..000000000000 --- a/awx/ui/client/lib/models/JobEvent.js +++ /dev/null @@ -1,19 +0,0 @@ -let BaseModel; - -function JobEventModel (method, resource, config) { - BaseModel.call(this, 'job_events'); - - this.Constructor = JobEventModel; - - return this.create(method, resource, config); -} - -function JobEventModelLoader (_BaseModel_) { - BaseModel = _BaseModel_; - - return JobEventModel; -} - -JobEventModel.$inject = ['BaseModel']; - -export default JobEventModelLoader; diff --git a/awx/ui/client/lib/models/JobTemplate.js b/awx/ui/client/lib/models/JobTemplate.js deleted file mode 100644 index b1b3599f4b72..000000000000 --- a/awx/ui/client/lib/models/JobTemplate.js +++ /dev/null @@ -1,110 +0,0 @@ -let Base; -let WorkflowJobTemplateNode; -let $http; - -function optionsLaunch (id) { - const req = { - method: 'OPTIONS', - url: `${this.path}${id}/launch/` - }; - - return $http(req); -} - -function getLaunch (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/launch/` - }; - - return $http(req) - .then(res => { - this.model.launch.GET = res.data; - - return res; - }); -} - -function postLaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/launch/` - }; - - if (params.launchData) { - req.data = params.launchData; - } - - return $http(req); -} - -function getSurveyQuestions (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/survey_spec/` - }; - - return $http(req); -} - -function canLaunchWithoutPrompt () { - const launchData = this.model.launch.GET; - - return ( - launchData.can_start_without_user_input && - !launchData.ask_inventory_on_launch && - !launchData.ask_credential_on_launch && - !launchData.ask_verbosity_on_launch && - !launchData.ask_job_type_on_launch && - !launchData.ask_limit_on_launch && - !launchData.ask_tags_on_launch && - !launchData.ask_skip_tags_on_launch && - !launchData.ask_variables_on_launch && - !launchData.ask_diff_mode_on_launch && - !launchData.survey_enabled - ); -} - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new WorkflowJobTemplateNode(), - params: { - unified_job_template: id - } - } - ]; -} - -function JobTemplateModel (method, resource, config) { - Base.call(this, 'job_templates'); - - this.Constructor = JobTemplateModel; - this.setDependentResources = setDependentResources.bind(this); - this.optionsLaunch = optionsLaunch.bind(this); - this.getLaunch = getLaunch.bind(this); - this.postLaunch = postLaunch.bind(this); - this.getSurveyQuestions = getSurveyQuestions.bind(this); - this.canLaunchWithoutPrompt = canLaunchWithoutPrompt.bind(this); - - this.model.launch = {}; - - return this.create(method, resource, config); -} - -function JobTemplateModelLoader (BaseModel, WorkflowJobTemplateNodeModel, _$http_) { - Base = BaseModel; - WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - $http = _$http_; - - return JobTemplateModel; -} - -JobTemplateModelLoader.$inject = [ - 'BaseModel', - 'WorkflowJobTemplateNodeModel', - '$http', - '$state' -]; - -export default JobTemplateModelLoader; diff --git a/awx/ui/client/lib/models/Me.js b/awx/ui/client/lib/models/Me.js deleted file mode 100644 index 221a29da3410..000000000000 --- a/awx/ui/client/lib/models/Me.js +++ /dev/null @@ -1,27 +0,0 @@ -let Base; - -function MeModel (method, resource, config) { - Base.call(this, 'me'); - - this.Constructor = MeModel; - - return this.create(method, resource, config) - .then(() => { - if (this.has('results')) { - _.merge(this.model.GET, this.get('results[0]')); - this.unset('results'); - } - - return this; - }); -} - -function MeModelLoader (BaseModel) { - Base = BaseModel; - - return MeModel; -} - -MeModelLoader.$inject = ['BaseModel']; - -export default MeModelLoader; diff --git a/awx/ui/client/lib/models/NotificationTemplate.js b/awx/ui/client/lib/models/NotificationTemplate.js deleted file mode 100644 index 6418a7184d5d..000000000000 --- a/awx/ui/client/lib/models/NotificationTemplate.js +++ /dev/null @@ -1,21 +0,0 @@ -let Base; - -function NotificationTemplateModel (method, resource, config) { - Base.call(this, 'notification_templates'); - - this.Constructor = NotificationTemplateModel; - - return this.create(method, resource, config); -} - -function NotificationTemplateModelLoader (BaseModel) { - Base = BaseModel; - - return NotificationTemplateModel; -} - -NotificationTemplateModelLoader.$inject = [ - 'BaseModel' -]; - -export default NotificationTemplateModelLoader; diff --git a/awx/ui/client/lib/models/Organization.js b/awx/ui/client/lib/models/Organization.js deleted file mode 100644 index 6209889fba33..000000000000 --- a/awx/ui/client/lib/models/Organization.js +++ /dev/null @@ -1,36 +0,0 @@ -let Base; -let Credential; - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new Credential(), - params: { - organization: id - } - } - ]; -} - -function OrganizationModel (method, resource, config) { - Base.call(this, 'organizations'); - - this.Constructor = OrganizationModel; - this.setDependentResources = setDependentResources.bind(this); - - return this.create(method, resource, config); -} - -function OrganizationModelLoader (BaseModel, CredentialModel) { - Base = BaseModel; - Credential = CredentialModel; - - return OrganizationModel; -} - -OrganizationModelLoader.$inject = [ - 'BaseModel', - 'CredentialModel' -]; - -export default OrganizationModelLoader; diff --git a/awx/ui/client/lib/models/Project.js b/awx/ui/client/lib/models/Project.js deleted file mode 100644 index 02606c3dcd7c..000000000000 --- a/awx/ui/client/lib/models/Project.js +++ /dev/null @@ -1,83 +0,0 @@ -let Base; -let JobTemplate; -let WorkflowJobTemplateNode; -let InventorySource; -let $http; - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new JobTemplate(), - params: { - project: id - } - }, - { - model: new WorkflowJobTemplateNode(), - params: { - unified_job_template: id - } - }, - { - model: new InventorySource(), - params: { - source_project: id - } - } - ]; -} - -function getUpdate (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/update/` - }; - - return $http(req); -} - -function postUpdate (id) { - const req = { - method: 'POST', - url: `${this.path}${id}/update/` - }; - - return $http(req); -} - -function ProjectModel (method, resource, config) { - Base.call(this, 'projects'); - - this.Constructor = ProjectModel; - this.setDependentResources = setDependentResources.bind(this); - this.getUpdate = getUpdate.bind(this); - this.postUpdate = postUpdate.bind(this); - - return this.create(method, resource, config); -} - -function ProjectModelLoader ( - BaseModel, - JobTemplateModel, - WorkflowJobTemplateNodeModel, - InventorySourceModel, - _$http_ -) { - Base = BaseModel; - JobTemplate = JobTemplateModel; - WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - InventorySource = InventorySourceModel; - $http = _$http_; - - return ProjectModel; -} - -ProjectModelLoader.$inject = [ - 'BaseModel', - 'JobTemplateModel', - 'WorkflowJobTemplateNodeModel', - 'InventorySourceModel', - '$http' -]; - -export default ProjectModelLoader; diff --git a/awx/ui/client/lib/models/ProjectUpdate.js b/awx/ui/client/lib/models/ProjectUpdate.js deleted file mode 100644 index df038283cf95..000000000000 --- a/awx/ui/client/lib/models/ProjectUpdate.js +++ /dev/null @@ -1,51 +0,0 @@ -let $http; -let BaseModel; - -function getStats () { - if (!this.has('GET', 'id')) { - return Promise.reject(new Error('No property, id, exists')); - } - - if (!this.has('GET', 'related.events')) { - return Promise.reject(new Error('No related property, events, exists')); - } - - const req = { - method: 'GET', - url: `${this.path}${this.get('id')}/events/`, - params: { event: 'playbook_on_stats' }, - }; - - return $http(req) - .then(({ data }) => { - if (data.results.length > 0) { - return data.results[0]; - } - - return null; - }); -} - -function ProjectUpdateModel (method, resource, config) { - BaseModel.call(this, 'project_updates'); - - this.getStats = getStats.bind(this); - - this.Constructor = ProjectUpdateModel; - - return this.create(method, resource, config); -} - -function ProjectUpdateModelLoader (_$http_, _BaseModel_) { - $http = _$http_; - BaseModel = _BaseModel_; - - return ProjectUpdateModel; -} - -ProjectUpdateModelLoader.$inject = [ - '$http', - 'BaseModel' -]; - -export default ProjectUpdateModelLoader; diff --git a/awx/ui/client/lib/models/Schedule.js b/awx/ui/client/lib/models/Schedule.js deleted file mode 100644 index b6bd3cf60f3c..000000000000 --- a/awx/ui/client/lib/models/Schedule.js +++ /dev/null @@ -1,38 +0,0 @@ -let Base; -let $http; - -function postCredential (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/credentials/` - }; - - if (params.data) { - req.data = params.data; - } - - return $http(req); -} - -function ScheduleModel (method, resource, config) { - Base.call(this, 'schedules'); - - this.Constructor = ScheduleModel; - this.postCredential = postCredential.bind(this); - - return this.create(method, resource, config); -} - -function ScheduleModelLoader (BaseModel, _$http_) { - Base = BaseModel; - $http = _$http_; - - return ScheduleModel; -} - -ScheduleModelLoader.$inject = [ - 'BaseModel', - '$http' -]; - -export default ScheduleModelLoader; diff --git a/awx/ui/client/lib/models/SystemJob.js b/awx/ui/client/lib/models/SystemJob.js deleted file mode 100644 index 1f1f1c5ee3af..000000000000 --- a/awx/ui/client/lib/models/SystemJob.js +++ /dev/null @@ -1,25 +0,0 @@ -let BaseModel; - -function getStats () { - return Promise.resolve(null); -} - -function SystemJobModel (method, resource, config) { - BaseModel.call(this, 'system_jobs'); - - this.getStats = getStats.bind(this); - - this.Constructor = SystemJobModel; - - return this.create(method, resource, config); -} - -function SystemJobModelLoader (_BaseModel_) { - BaseModel = _BaseModel_; - - return SystemJobModel; -} - -SystemJobModelLoader.$inject = ['BaseModel']; - -export default SystemJobModelLoader; diff --git a/awx/ui/client/lib/models/UnifiedJob.js b/awx/ui/client/lib/models/UnifiedJob.js deleted file mode 100644 index 13078f8fa2fc..000000000000 --- a/awx/ui/client/lib/models/UnifiedJob.js +++ /dev/null @@ -1,21 +0,0 @@ -let Base; - -function UnifiedJobModel (method, resource, config) { - Base.call(this, 'unified_jobs'); - - this.Constructor = UnifiedJobModel; - - return this.create(method, resource, config); -} - -function UnifiedJobModelLoader (BaseModel) { - Base = BaseModel; - - return UnifiedJobModel; -} - -UnifiedJobModelLoader.$inject = [ - 'BaseModel' -]; - -export default UnifiedJobModelLoader; diff --git a/awx/ui/client/lib/models/UnifiedJobTemplate.js b/awx/ui/client/lib/models/UnifiedJobTemplate.js deleted file mode 100644 index 94c066af6a65..000000000000 --- a/awx/ui/client/lib/models/UnifiedJobTemplate.js +++ /dev/null @@ -1,110 +0,0 @@ -let BaseModel; -let WorkflowJobTemplateNode; -let $http; - -function optionsLaunch (id) { - const req = { - method: 'OPTIONS', - url: `${this.path}${id}/launch/` - }; - - return $http(req); -} - -function getLaunch (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/launch/` - }; - - return $http(req) - .then(res => { - this.model.launch.GET = res.data; - - return res; - }); -} - -function postLaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/launch/` - }; - - if (params.launchData) { - req.data = params.launchData; - } - - return $http(req); -} - -function getSurveyQuestions (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/survey_spec/` - }; - - return $http(req); -} - -function canLaunchWithoutPrompt () { - const launchData = this.model.launch.GET; - - return ( - launchData.can_start_without_user_input && - !launchData.ask_inventory_on_launch && - !launchData.ask_credential_on_launch && - !launchData.ask_verbosity_on_launch && - !launchData.ask_job_type_on_launch && - !launchData.ask_limit_on_launch && - !launchData.ask_tags_on_launch && - !launchData.ask_skip_tags_on_launch && - !launchData.ask_variables_on_launch && - !launchData.ask_diff_mode_on_launch && - !launchData.survey_enabled - ); -} - -function setDependentResources (id) { - this.dependentResources = [ - { - model: new WorkflowJobTemplateNode(), - params: { - unified_job_template: id - } - } - ]; -} - -function UnifiedJobTemplateModel (method, resource, graft) { - BaseModel.call(this, 'unified_job_templates'); - - this.Constructor = UnifiedJobTemplateModel; - this.setDependentResources = setDependentResources.bind(this); - this.optionsLaunch = optionsLaunch.bind(this); - this.getLaunch = getLaunch.bind(this); - this.postLaunch = postLaunch.bind(this); - this.getSurveyQuestions = getSurveyQuestions.bind(this); - this.canLaunchWithoutPrompt = canLaunchWithoutPrompt.bind(this); - - this.model.launch = {}; - - return this.create(method, resource, graft); -} - -function UnifiedJobTemplateModelLoader (_BaseModel_, WorkflowJobTemplateNodeModel, _$http_) { - BaseModel = _BaseModel_; - WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - $http = _$http_; - - return UnifiedJobTemplateModel; -} - -UnifiedJobTemplateModelLoader.$inject = [ - 'BaseModel', - 'WorkflowJobTemplateNodeModel', - '$http', - '$state' -]; - -export default UnifiedJobTemplateModelLoader; diff --git a/awx/ui/client/lib/models/WorkflowJob.js b/awx/ui/client/lib/models/WorkflowJob.js deleted file mode 100644 index 02ea3582cc16..000000000000 --- a/awx/ui/client/lib/models/WorkflowJob.js +++ /dev/null @@ -1,34 +0,0 @@ -let Base; -let $http; - -function postRelaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/relaunch/` - }; - - return $http(req); -} - -function WorkflowJobModel (method, resource, config) { - Base.call(this, 'workflow_jobs'); - - this.Constructor = WorkflowJobModel; - this.postRelaunch = postRelaunch.bind(this); - - return this.create(method, resource, config); -} - -function WorkflowJobModelLoader (BaseModel, _$http_) { - Base = BaseModel; - $http = _$http_; - - return WorkflowJobModel; -} - -WorkflowJobModelLoader.$inject = [ - 'BaseModel', - '$http' -]; - -export default WorkflowJobModelLoader; diff --git a/awx/ui/client/lib/models/WorkflowJobTemplate.js b/awx/ui/client/lib/models/WorkflowJobTemplate.js deleted file mode 100644 index 79198bbe8210..000000000000 --- a/awx/ui/client/lib/models/WorkflowJobTemplate.js +++ /dev/null @@ -1,85 +0,0 @@ -let Base; -let $http; - -function optionsLaunch (id) { - const req = { - method: 'OPTIONS', - url: `${this.path}${id}/launch/` - }; - - return $http(req); -} - -function getLaunch (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/launch/` - }; - - return $http(req) - .then(res => { - this.model.launch.GET = res.data; - - return res; - }); -} - -function postLaunch (params) { - const req = { - method: 'POST', - url: `${this.path}${params.id}/launch/` - }; - - if (params.launchData) { - req.data = params.launchData; - } - - return $http(req); -} - -function getSurveyQuestions (id) { - const req = { - method: 'GET', - url: `${this.path}${id}/survey_spec/` - }; - - return $http(req); -} - -function canLaunchWithoutPrompt () { - const launchData = this.model.launch.GET; - - return ( - launchData.can_start_without_user_input && - !launchData.survey_enabled - ); -} - -function WorkflowJobTemplateModel (method, resource, config) { - Base.call(this, 'workflow_job_templates'); - - this.Constructor = WorkflowJobTemplateModel; - this.optionsLaunch = optionsLaunch.bind(this); - this.getLaunch = getLaunch.bind(this); - this.postLaunch = postLaunch.bind(this); - this.getSurveyQuestions = getSurveyQuestions.bind(this); - this.canLaunchWithoutPrompt = canLaunchWithoutPrompt.bind(this); - - this.model.launch = {}; - - return this.create(method, resource, config); -} - -function WorkflowJobTemplateModelLoader (BaseModel, _$http_) { - Base = BaseModel; - $http = _$http_; - - return WorkflowJobTemplateModel; -} - -WorkflowJobTemplateModelLoader.$inject = [ - 'BaseModel', - '$http' -]; - -export default WorkflowJobTemplateModelLoader; diff --git a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js deleted file mode 100644 index c08cbd2e8cc8..000000000000 --- a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js +++ /dev/null @@ -1,21 +0,0 @@ -let Base; - -function WorkflowJobTemplateNodeModel (method, resource, config) { - Base.call(this, 'workflow_job_template_nodes'); - - this.Constructor = WorkflowJobTemplateNodeModel; - - return this.create(method, resource, config); -} - -function WorkflowJobTemplateNodeModelLoader (BaseModel) { - Base = BaseModel; - - return WorkflowJobTemplateNodeModel; -} - -WorkflowJobTemplateNodeModelLoader.$inject = [ - 'BaseModel' -]; - -export default WorkflowJobTemplateNodeModelLoader; diff --git a/awx/ui/client/lib/models/index.js b/awx/ui/client/lib/models/index.js deleted file mode 100644 index d50c825e2298..000000000000 --- a/awx/ui/client/lib/models/index.js +++ /dev/null @@ -1,68 +0,0 @@ -import atLibServices from '~services'; - -import Application from '~models/Application'; -import AdHocCommand from '~models/AdHocCommand'; -import Base from '~models/Base'; -import Config from '~models/Config'; -import Credential from '~models/Credential'; -import CredentialType from '~models/CredentialType'; -import Instance from '~models/Instance'; -import InstanceGroup from '~models/InstanceGroup'; -import Inventory from '~models/Inventory'; -import InventoryScript from '~models/InventoryScript'; -import InventorySource from '~models/InventorySource'; -import InventoryUpdate from '~models/InventoryUpdate'; -import Job from '~models/Job'; -import JobEvent from '~models/JobEvent'; -import JobTemplate from '~models/JobTemplate'; -import Me from '~models/Me'; -import NotificationTemplate from '~models/NotificationTemplate'; -import Organization from '~models/Organization'; -import Project from '~models/Project'; -import Schedule from '~models/Schedule'; -import ProjectUpdate from '~models/ProjectUpdate'; -import SystemJob from '~models/SystemJob'; -import UnifiedJobTemplate from '~models/UnifiedJobTemplate'; -import WorkflowJob from '~models/WorkflowJob'; -import WorkflowJobTemplate from '~models/WorkflowJobTemplate'; -import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode'; -import UnifiedJob from '~models/UnifiedJob'; - -import ModelsStrings from '~models/models.strings'; - -const MODULE_NAME = 'at.lib.models'; - -angular - .module(MODULE_NAME, [ - atLibServices - ]) - .service('ApplicationModel', Application) - .service('AdHocCommandModel', AdHocCommand) - .service('BaseModel', Base) - .service('ConfigModel', Config) - .service('CredentialModel', Credential) - .service('CredentialTypeModel', CredentialType) - .service('InstanceGroupModel', InstanceGroup) - .service('InstanceModel', Instance) - .service('InventoryModel', Inventory) - .service('InventoryScriptModel', InventoryScript) - .service('InventorySourceModel', InventorySource) - .service('InventoryUpdateModel', InventoryUpdate) - .service('JobEventModel', JobEvent) - .service('JobModel', Job) - .service('JobTemplateModel', JobTemplate) - .service('MeModel', Me) - .service('NotificationTemplate', NotificationTemplate) - .service('OrganizationModel', Organization) - .service('ProjectModel', Project) - .service('ScheduleModel', Schedule) - .service('UnifiedJobModel', UnifiedJob) - .service('ProjectUpdateModel', ProjectUpdate) - .service('SystemJobModel', SystemJob) - .service('UnifiedJobTemplateModel', UnifiedJobTemplate) - .service('WorkflowJobModel', WorkflowJob) - .service('WorkflowJobTemplateModel', WorkflowJobTemplate) - .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) - .service('ModelsStrings', ModelsStrings); - -export default MODULE_NAME; diff --git a/awx/ui/client/lib/models/models.strings.js b/awx/ui/client/lib/models/models.strings.js deleted file mode 100644 index acb2dd5bbf89..000000000000 --- a/awx/ui/client/lib/models/models.strings.js +++ /dev/null @@ -1,52 +0,0 @@ -function ModelsStrings (BaseString) { - BaseString.call(this, 'models'); - - const { t } = this; - const ns = this.models; - - ns.credentials = { - LABEL: t.s('Credentials') - }; - - ns.credential_types = { - LABEL: t.s('Credential Types') - }; - - ns.inventories = { - LABEL: t.s('Inventories') - }; - - ns.inventory_scripts = { - LABEL: t.s('Inventory Scripts') - - }; - - ns.inventory_sources = { - LABEL: t.s('Inventory Sources') - - }; - - ns.job_templates = { - LABEL: t.s('Job Templates') - - }; - - ns.organizations = { - LABEL: t.s('Organizations') - - }; - - ns.projects = { - LABEL: t.s('Projects') - - }; - - ns.workflow_job_template_nodes = { - LABEL: t.s('Workflow Job Template Nodes') - - }; -} - -ModelsStrings.$inject = ['BaseStringService']; - -export default ModelsStrings; diff --git a/awx/ui/client/lib/services/app.strings.js b/awx/ui/client/lib/services/app.strings.js deleted file mode 100644 index a84489730830..000000000000 --- a/awx/ui/client/lib/services/app.strings.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This service is used to access the app-wide strings defined in BaseStringService. - */ -function AppStrings (BaseString) { - BaseString.call(this, 'app'); -} - -AppStrings.$inject = ['BaseStringService']; - -export default AppStrings; diff --git a/awx/ui/client/lib/services/base-string.service.js b/awx/ui/client/lib/services/base-string.service.js deleted file mode 100644 index cab067700e4f..000000000000 --- a/awx/ui/client/lib/services/base-string.service.js +++ /dev/null @@ -1,137 +0,0 @@ -import defaults from '~assets/default.strings.json'; - -let i18n; - -function BaseStringService (namespace) { - const ERROR_NO_NAMESPACE = 'BaseString cannot be extended without providing a namespace'; - - if (!namespace) { - throw new Error(ERROR_NO_NAMESPACE); - } - - this[namespace] = {}; - this.t = {}; - - /** - * To translate a singular string by itself or a string with context data, use `translate`. - * For brevity, this is renamed as `t.s` (as in "translate singular"). `t.s` serves a dual - * purpose -- it's to mark strings for translation so they appear in the `.pot` file after - * the grunt-angular-gettext task is run AND it's used to fetch the translated string at - * runtime. - * - * NOTE: View ui/src/i18n.js for where these i18n methods are defined. i18n is a wrapper around - * the library angular-gettext. - * - * @arg {string} string - The string to be translated - * @arg {object=} context - A data object used to populate dynamic context data in a string. - * - * @returns {string} The translated string or the original string in the even the translation - * does not exist. - */ - this.t.s = i18n.translate; - - /** - * To translate a plural string use `t.p`. The `count` supplied will determine whether the - * singular or plural string is returned. - * - * @arg {number} count - The count of the plural object - * @arg {string} singular - The singular version of the string to be translated - * @arg {string} plural - The plural version of the string to be translated - * @arg {object=} context - A data object used to populate dynamic context data in a string. - * - * @returns {string} The translated string or the original string in the even the translation - * does not exist. - */ - this.t.p = i18n.translatePlural; - - const { t } = this; - - /* - * These strings are globally relevant and configured to give priority to values in - * default.strings.json and fall back to defaults defined inline. - */ - this.BRAND_NAME = defaults.BRAND_NAME || 'AWX'; - this.PENDO_API_KEY = defaults.PENDO_API_KEY || ''; - - /* - * Globally relevant strings should be defined here to avoid duplication of content across the - * the project. - */ - this.CANCEL = t.s('CANCEL'); - this.SAVE = t.s('SAVE'); - this.OK = t.s('OK'); - this.NEXT = t.s('NEXT'); - this.SHOW = t.s('SHOW'); - this.HIDE = t.s('HIDE'); - this.ON = t.s('ON'); - this.OFF = t.s('OFF'); - this.YAML = t.s('YAML'); - this.JSON = t.s('JSON'); - this.DELETE = t.s('DELETE'); - this.COPY = t.s('COPY'); - this.YES = t.s('YES'); - - this.deleteResource = { - HEADER: t.s('Delete'), - USED_BY: resourceType => t.s('The {{ resourceType }} is currently being used by other resources.', { resourceType }), - UNAVAILABLE: resourceType => t.s('Deleting this {{ resourceType }} will make the following resources unavailable.', { resourceType }), - CONFIRM: resourceType => t.s('Are you sure you want to delete this {{ resourceType }}?', { resourceType }) - }; - - this.cancelJob = { - HEADER: t.s('Cancel'), - SUBMIT_REQUEST: t.s('Are you sure you want to submit the request to cancel this job?'), - CANCEL_JOB: t.s('Cancel Job'), - RETURN: t.s('Return') - }; - - this.error = { - HEADER: t.s('Error!'), - CALL: ({ path, action, status }) => t.s('Call to {{ path }} failed. {{ action }} returned status: {{ status }}.', { path, action, status }), - }; - - this.ALERT = ({ header, body }) => t.s('{{ header }} {{ body }}', { header, body }); - - /** - * This getter searches the extending class' namespace first for a match then falls back to - * the more globally relevant strings defined here. Strings with with dots as delimeters are - * supported to give flexibility to extending classes to nest strings as necessary. - * - * - * The `t.s` and `t.p` calls should only be used where strings are defined in - * .strings.js` files. To use translated strings elsewhere, access them through this - * common interface. - * - * @arg {string} name - The property name of the string (e.g. 'CANCEL') - * @arg {number=} count - A count of objects referenced in your plural string - * @arg {object=} context - An object containing data to use in the interpolation of the string - */ - this.get = (name, ...args) => { - const keys = name.split('.'); - let value; - - keys.forEach(key => { - if (!value) { - value = this[namespace][key] || this[key]; - } else { - value = value[key]; - } - }); - - if (!value || typeof value === 'string') { - return value; - } - - return value(...args); - }; -} - -function BaseStringServiceLoader (_i18n_) { - i18n = _i18n_; - - return BaseStringService; -} - -BaseStringServiceLoader.$inject = ['i18n']; - -export default BaseStringServiceLoader; diff --git a/awx/ui/client/lib/services/cache.service.js b/awx/ui/client/lib/services/cache.service.js deleted file mode 100644 index 783b0e0d4cb3..000000000000 --- a/awx/ui/client/lib/services/cache.service.js +++ /dev/null @@ -1,32 +0,0 @@ -function CacheService ($cacheFactory, $q) { - const cache = $cacheFactory('api'); - - this.put = (key, data) => cache.put(key, data); - this.get = (key) => $q.resolve(cache.get(key)); - - this.remove = (key) => { - if (!key) { - return cache.removeAll(); - } - - return cache.remove(key); - }; - - this.createKey = (method, path, resource) => { - let key = `${method.toUpperCase()}.${path}`; - - if (resource) { - if (resource.id) { - key += `${resource.id}/`; - } else if (Number(resource)) { - key += `${resource}/`; - } - } - - return key; - }; -} - -CacheService.$inject = ['$cacheFactory', '$q']; - -export default CacheService; diff --git a/awx/ui/client/lib/services/event.service.js b/awx/ui/client/lib/services/event.service.js deleted file mode 100644 index d7b7a4053805..000000000000 --- a/awx/ui/client/lib/services/event.service.js +++ /dev/null @@ -1,37 +0,0 @@ -function EventService () { - this.addListeners = list => { - const listeners = []; - - list.forEach(args => listeners.push(this.addListener(...args))); - - return listeners; - }; - - this.addListener = (el, name, fn) => { - const listener = { - fn, - name, - el - }; - - if (Array.isArray(name)) { - name.forEach(e => listener.el.addEventListener(e, listener.fn)); - } else { - listener.el.addEventListener(listener.name, listener.fn); - } - - return listener; - }; - - this.remove = listeners => { - listeners.forEach(listener => { - if (Array.isArray(listener.name)) { - listener.name.forEach(name => listener.el.removeEventListener(name, listener.fn)); - } else { - listener.el.removeEventListener(listener.name, listener.fn); - } - }); - }; -} - -export default EventService; diff --git a/awx/ui/client/lib/services/index.js b/awx/ui/client/lib/services/index.js deleted file mode 100644 index 39ed1d82990c..000000000000 --- a/awx/ui/client/lib/services/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import AppStrings from '~services/app.strings'; -import BaseStringService from '~services/base-string.service'; -import CacheService from '~services/cache.service'; -import EventService from '~services/event.service'; - -const MODULE_NAME = 'at.lib.services'; - -angular - .module(MODULE_NAME, [ - 'I18N' - ]) - .service('AppStrings', AppStrings) - .service('BaseStringService', BaseStringService) - .service('CacheService', CacheService) - .service('EventService', EventService); - -export default MODULE_NAME; diff --git a/awx/ui/client/lib/theme/_global.less b/awx/ui/client/lib/theme/_global.less deleted file mode 100644 index 01690ab2dd5f..000000000000 --- a/awx/ui/client/lib/theme/_global.less +++ /dev/null @@ -1,73 +0,0 @@ -/** - * For styles that are used in more than one place throughout the application. - * - * 1. Buttons - * - */ - -// 1. Buttons ------------------------------------------------------------------------------------- - -.at-Button--success { - .at-mixin-Button(); - .at-mixin-ButtonColor('at-color-success', 'at-color-default'); - - &[disabled] { - background: @at-color-disabled; - border-color: @at-color-disabled; - } -} - -.at-Button--add { - &:extend(.at-Button--success all); - &:before { - content: "+"; - font-size: 20px; - } - border: none; - display: inline-flex; - margin-left: @at-space-4x; - - &[aria-expanded="true"] { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - } -} - -.at-Button--info { - .at-mixin-Button(); - .at-mixin-ButtonColor('at-color-info', 'at-color-default'); -} - -.at-Button--error { - .at-mixin-Button(); - .at-mixin-ButtonColor('at-color-error', 'at-color-default'); -} - -.at-ButtonHollow--default { - .at-mixin-Button(); - .at-mixin-ButtonHollow( - 'at-color-default', - 'at-color-button-border-default', - 'at-color-button-text-default' - ); -} - -.at-ButtonIcon { - padding: 4px @at-padding-button-horizontal; - font-size: @at-font-size-body; -} - -.at-ButtonIcon-noborder { - padding: 4px @at-padding-button-horizontal; - font-size: @at-font-size-body; - .at-mixin-Button(); - .at-mixin-ButtonHollow( - 'at-color-default', - 'at-color-default', - 'at-color-button-text-default' - ); -} - -.at-Button--expand { - width: 100%; -} diff --git a/awx/ui/client/lib/theme/_mixins.less b/awx/ui/client/lib/theme/_mixins.less deleted file mode 100644 index 701613a2ecd7..000000000000 --- a/awx/ui/client/lib/theme/_mixins.less +++ /dev/null @@ -1,105 +0,0 @@ -.at-mixin-Placeholder (@color) { - &:-moz-placeholder { - color: @color; - } - &:-ms-input-placeholder { - color: @color; - } - &::-webkit-input-placeholder { - color: @color; - } -} - -.at-mixin-Heading (@size) { - color: @at-color-body-text; - font-size: @size; - font-weight: @at-font-weight-heading; - line-height: @at-line-height-short; - text-transform: uppercase; - margin: 0; - padding: 0; -} - -.at-mixin-Button () { - border-radius: @at-border-radius; - height: @at-height-input; - padding: @at-padding-button-vertical @at-padding-button-horizontal; - font-size: @at-font-size-body; - line-height: 1; -} - -.at-mixin-InputButton () { - height: @at-height-button; - padding: 0 @at-padding-button-horizontal; - - &, &:active, &:hover, &:focus { - color: @at-color-button-text-default; - border-color: @at-color-input-border; - background-color: @at-color-input-button; - cursor: pointer; - } - - &:hover { - background-color: @at-color-input-button-hover; - } -} - -.at-mixin-ButtonColor (@background, @color, @hover: '@{background}-hover') { - background-color: @@background; - border-color: @@background; - - &, &:hover, &:focus { - color: @@color; - } - - &:hover, &:focus { - background-color: @@hover; - border-color: @@hover; - } - - &[disabled] { - background-color: fade(@@background, 60%); - } -} - -.at-mixin-ButtonHollow (@bg, @border, @text) { - @hover: '@{bg}-hover'; - - background-color: @@bg; - color: @@text; - border-color: @@border; - - &:hover, &:active { - color: @@text; - background-color: @@hover; - box-shadow: none; - } - - &:focus { - color: @@text; - background-color: @@hover; - border-color: @@border; - cursor: default; - } - - &[disabled] { - opacity: 0.65; - } -} - -.at-mixin-ButtonIcon () { - line-height: @at-line-height-short; - - & > i { - cursor: pointer; - transition: color @at-transition-icon-button; - } - - & > i:hover { - color: @at-color-icon-hover - } -} - -.at-mixin-FontFixedWidth () { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} \ No newline at end of file diff --git a/awx/ui/client/lib/theme/_resets.less b/awx/ui/client/lib/theme/_resets.less deleted file mode 100644 index e7070fa42d83..000000000000 --- a/awx/ui/client/lib/theme/_resets.less +++ /dev/null @@ -1,5 +0,0 @@ -// TODO (remove override on cleanup): - -.at-Panel-heading:hover { - cursor: default; -} diff --git a/awx/ui/client/lib/theme/_utility.less b/awx/ui/client/lib/theme/_utility.less deleted file mode 100644 index b3663b74a336..000000000000 --- a/awx/ui/client/lib/theme/_utility.less +++ /dev/null @@ -1,30 +0,0 @@ -.at-u-noSpace { - margin: 0; - padding: 0; -} - -.at-u-flat { - padding-top: 0; - padding-bottom: 0; - margin-top: 0; - margin-bottom: 0; -} - -.at-u-thin { - padding-left: 0; - padding-right: 0; - margin-left: 0; - margin-right: 0; -} - -.at-u-clear { - clear: both; -} - -.at-u-noBorder { - border: none; -} - -.at-u-floatRight { - float: right -} diff --git a/awx/ui/client/lib/theme/_variables.less b/awx/ui/client/lib/theme/_variables.less deleted file mode 100644 index 991bd62e61a6..000000000000 --- a/awx/ui/client/lib/theme/_variables.less +++ /dev/null @@ -1,319 +0,0 @@ -/** - * All base variables used. These should only be referenced by the contextual variables defined - * below. In development, unless you are intentionally making a fundamental change, these variables - * should not be modified, removed, or added to. - * - * These variables should not be used directly in development of components or features. If an - * alias doesn't exist for the context you're working within, check with UX to create a new alias - * or to define a more applicable alias. - * - * The goal is for UX to define the contexts for the contextual variables, so it's easy to make - * modifications like, "Change heading text to be smaller" or "Make all warnings a lighter shade - * of orange" - * - * 1. Colors - * 2. Typography - * 3. Layout - * 4. Breakpoints - * - */ - -// 1. Colors -------------------------------------------------------------------------------------- - -@at-gray-fc: #fcfcfc; -@at-gray-fa: #fafafa; -@at-gray-f2: #f2f2f2; -@at-gray-f6: #f6f6f6; -@at-gray-eb: #ebebeb; -@at-gray-e1: #e1e1e1; -@at-gray-d7: #d7d7d7; -@at-gray-b7: #b7b7b7; -@at-gray-a9: #a9a9a9; -@at-gray-848992: #848992; -@at-gray-70: #707070; -@at-gray-161b1f: #161b1f; - -@at-white: #ffffff; -@at-white-hover: #f2f2f2; - -@at-blue: #337ab7; -@at-blue-hover: #286090; - -@at-green: #5cb85c; -@at-green-hover: #449d44; - -@at-orange: #f0ad4e; -@at-orange-hover: #ec971f; - -@at-red: #d9534f; -@at-red-hover: #c9302c; - -@at-red-bright: #ff0000; -@at-red-bright-hover: #d81f1f; - -// 2. Typography ---------------------------------------------------------------------------------- - -@at-font-size: 12px; -@at-font-size-2x: 13px; -@at-font-size-3x: 14px; -@at-font-size-4x: 16px; -@at-font-size-5x: 20px; - -@at-font-weight: 400; -@at-font-weight-2x: 700; - -// 3. Layout -------------------------------------------------------------------------------------- - -@at-space: 5px; -@at-space-2x: 10px; -@at-space-3x: 15px; -@at-space-4x: 20px; -@at-space-5x: 25px; -@at-space-10x: 50px; - -// 4. Breakpoints --------------------------------------------------------------------------------- - -@at-breakpoint-sm: 700px; - -/** - * All variables used in the UI. Use these variables directly during the development of components - * and features. Be sure the context of the variable name applies to the work that's being done. - * For example, it wouldn't make sense to use `@at-input-height` to describe the height of a - * button. Either add an alias if it makes sense to use the same base variable, or add a new - * base variable to reference. - * - * Keep in mind the goal is to be able to modify an item by referencing its context instead of - * an arbitrary variable name. For example, tt should be a simple change when an ask comes in to - * "increase the height of inputs" - * - * 1. Colors - * 2. Typography - * 3. Layout - * 4. Buttons - * 5. Misc - * 6. Breakpoints - * - */ - -// 1. Colors -------------------------------------------------------------------------------------- - -@at-color-default: @at-white; -@at-color-default-hover: @at-white-hover; - -@at-color-unreachable: @at-red-bright; -@at-color-unreachable-hover: @at-red-bright-hover; - -@at-color-error: @at-red; -@at-color-error-hover: @at-red-hover; - -@at-color-warning: @at-orange; -@at-color-warning-hover: @at-orange-hover; - -@at-color-info: @at-blue; -@at-color-info-hover: @at-blue-hover; - -@at-color-success: @at-green; -@at-color-success-hover: @at-green-hover; - -@at-color-disabled: @at-gray-d7; - -@at-color-body-background-dark: @at-gray-70; -@at-color-body-background-light: @at-gray-eb; -@at-color-body-text-dark: @at-white; -@at-color-body-background: @at-gray-fc; -@at-color-body-text: @at-gray-70; - -@at-color-button-border-default: @at-gray-b7; -@at-color-button-text-default: @at-gray-70; - -@at-color-tab-default-active: @at-gray-848992; -@at-color-tab-border-default-active: @at-gray-848992; -@at-color-tab-text-default-active: @at-white; - -@at-color-tab-default-disabled: @at-white; -@at-color-tab-border-default-disabled: @at-gray-b7; -@at-color-tab-text-default-disabled: @at-gray-70; - -@at-color-form-label: @at-gray-70; - -@at-color-input-background: @at-gray-fc; -@at-color-input-border: @at-gray-b7; -@at-color-input-button: @at-gray-fc; -@at-color-input-button-hover: @at-gray-f2; -@at-color-input-disabled: @at-gray-eb; -@at-color-input-readonly: @at-color-input-background; - -@at-color-input-error: @at-color-error; -@at-color-input-focus: @at-color-info; -@at-color-input-hint: @at-gray-848992; -@at-color-input-icon: @at-gray-b7; -@at-color-input-placeholder: @at-gray-848992; -@at-color-input-text: @at-gray-161b1f; -@at-color-input-slider-thumb: @at-blue; -@at-color-input-slider-track: @at-gray-b7; - -@at-color-icon-dismiss: @at-gray-d7; -@at-color-icon-popover: @at-gray-848992; -@at-color-icon-hover: @at-gray-848992; - -@at-color-panel-heading: @at-gray-70; -@at-color-panel-border: @at-gray-b7; - -@at-color-search-key-active: @at-blue; - -@at-color-table-header-background: @at-gray-eb; -@at-color-line-separator: @at-gray-e1; - -@at-color-top-nav-background: @at-white; -@at-color-top-nav-border-bottom: @at-gray-b7; -@at-color-top-nav-item-text: @at-gray-70; -@at-color-top-nav-item-icon: @at-gray-848992; -@at-color-top-nav-item-icon-socket-outline: @at-white; -@at-color-top-nav-item-background-hover: @at-gray-fa; -@at-color-side-nav-background: @at-gray-848992; -@at-color-side-nav-content: @at-white; -@at-color-side-nav-item-background-hover: #ddd; -@at-color-side-nav-item-border-hover: @at-white; -@at-color-footer-background: @at-gray-fc; -@at-color-footer: @at-gray-70; - -@at-color-list-empty-border: @at-gray-d7; -@at-color-list-empty-background: @at-gray-f6; -@at-color-list-empty: @at-gray-848992; -@at-color-list-border: @at-gray-b7; -@at-color-list-row-item-tag-background: @at-gray-eb; -@at-color-list-row-item-tag: @at-gray-70; -@at-color-list-row-item-label: @at-gray-848992; -@at-color-list-row-action-background: @at-white; -@at-color-list-row-action-icon: @at-gray-848992; -@at-color-list-row-action-hover: @at-blue; -@at-color-list-row-action-hover-danger: @at-red; -@at-color-list-row-action-icon-hover: @at-white; -@at-color-list-row-item-tag-primary-background: @at-blue; -@at-color-list-row-item-tag-primary: @at-white; - -// 2. Typography ---------------------------------------------------------------------------------- - -@at-font-size-body: @at-font-size-3x; -@at-font-size-button: @at-font-size; -@at-font-size-breadcrumb: @at-font-size-3x; -@at-font-size-form-label: @at-font-size-2x; -@at-font-size-help-text: @at-font-size; -@at-font-size-icon: @at-font-size-4x; -@at-font-size-input: @at-font-size-3x; -@at-font-size-panel-heading: @at-font-size-3x; -@at-font-size-panel-inset-heading: @at-font-size-2x; -@at-font-size-modal-heading: @at-font-size-3x; -@at-font-size-modal-dismiss: @at-font-size-3x; -@at-font-size-navigation: @at-font-size-3x; -@at-font-size-table-heading: @at-font-size-3x; -@at-font-size-menu-icon: @at-font-size-5x; -@at-font-size-list-row-item-tag: 10px; -@at-font-size-list-row-action: 19px; -@at-font-size-list-row-action-icon: 19px; -@at-font-size-jumbotron-heading: 24px; -@at-font-size-jumbotron-text: @at-font-size-4x; - -@at-font-weight-body: @at-font-weight; -@at-font-weight-heading: @at-font-weight-2x; - -// 3. Layout -------------------------------------------------------------------------------------- - -@at-padding-button-horizontal: @at-space-2x; -@at-padding-button-vertical: @at-space; -@at-padding-inset: @at-space-3x; -@at-padding-panel: @at-space-4x; -@at-padding-popover: @at-space-2x; -@at-padding-well: @at-space-2x; -@at-padding-input: @at-space-2x; -@at-padding-top-nav-item-sides: @at-space-4x; -@at-padding-side-nav-item-icon: @at-space-3x; -@at-padding-between-side-nav-icon-text: @at-space-3x; -@at-padding-footer-right: @at-space-4x; -@at-padding-footer-bottom: @at-space-4x; -@at-padding-list-empty: @at-space-2x; -@at-padding-list-row-item-tag: 0 @at-space-2x; -@at-padding-list-row-action: 7px; -@at-padding-list-row: 10px 20px; - -@at-margin-input-message: @at-space; -@at-margin-item-column: @at-space-3x; -@at-margin-panel: @at-space-4x; -@at-margin-panel-inset: @at-space-3x; -@at-margin-popover: @at-space-2x; -@at-margin-tag: @at-space-2x; -@at-margin-form-label: @at-space; -@at-margin-form-label-hint: @at-space-2x; -@at-margin-top-nav-item-between-icon-and-name: @at-space-2x; -@at-margin-top-nav-item-icon-socket-top-makeup: -3px; -@at-margin-after-footer-link: @at-space; -@at-margin-footer-top: @at-space-4x; - -@at-margin-top-search-key: @at-space-2x; - -@at-margin-top-list: @at-space-5x; -@at-margin-bottom-list-toolbar: @at-space-4x; -@at-margin-left-toolbar-action: @at-space-4x; -@at-margin-left-toolbar-carat: @at-space; -@at-margin-bottom-list-header: @at-space; -@at-margin-left-list-row-item-tag: @at-space-2x; -@at-margin-top-list-row-item-tag: 2.25px; -@at-margin-left-list-row-action: @at-space-4x; -@at-margin-right-list-row-item-tag-icon: 8px; -@at-margin-left-list-row-item-tag-container: -10px; -@at-margin-list-row-action-mobile: 10px; -@at-margin-right-list-row-item-status: @at-space-2x; -@at-margin-right-list-row-item-inline: @at-space-4x; -@at-margin-right-list-row-item-inline-label: @at-space-2x; - -@at-height-divider: @at-margin-panel; -@at-height-input: 30px; -@at-height-textarea: 144px; -@at-height-button: 30px; -@at-height-tab: 30px; -@at-height-top-nav: 60px; -@at-height-top-nav-item-icon: 21px; -@at-height-top-nav-item-icon-socket: 18px; -@at-height-side-nav-item-icon: 20px; -@at-height-side-nav-spacer: 20px; -@at-height-top-side-nav-makeup: 55px; -@at-height-list-empty: 200px; -@at-height-toolbar-action: 30px; -@at-height-list-row-item: 27px; -@at-height-list-row-item-tag: 15px; -@at-height-list-row-action: 30px; - -@at-width-input-button-sm: 72px; -@at-width-input-button-md: 84px; -@at-width-collapsed-side-nav: 50px; -@at-width-expanded-side-nav: 200px; -@at-width-list-row-item-label: 120px; -@at-width-list-row-action: 30px; - -@at-line-height-list-row-item-header: @at-space-3x; -@at-line-height-list-row-item-labels: 17px; - -// 4. Transitions --------------------------------------------------------------------------------- - -@at-transition-icon-button: 0.2s; - -// 5. Misc ---------------------------------------------------------------------------------------- - -@at-border-radius: 5px; -@at-popover-maxwidth: 320px; -@at-line-height-short: 0.9; -@at-line-height-tall: 2; -@at-line-height: 24px; -@at-highlight-left-border-size: 5px; -@at-highlight-left-border-margin-makeup: -5px; -@at-z-index-nav: 1040; -@at-z-index-side-nav: 1030; -@at-z-index-footer: 1020; -@at-border-default-width: 1px; -@at-border-style-list-active-indicator: 5px solid @at-color-info; -@at-line-height-list-row-item-tag: 22px; - -// 6. Breakpoints --------------------------------------------------------------------------------- - -@at-breakpoint-mobile-layout: @at-breakpoint-sm; -@at-breakpoint-compact-list: @at-breakpoint-sm; diff --git a/awx/ui/client/lib/theme/index.less b/awx/ui/client/lib/theme/index.less deleted file mode 100644 index caf02e288294..000000000000 --- a/awx/ui/client/lib/theme/index.less +++ /dev/null @@ -1,175 +0,0 @@ -// Dependency Variables -@import '../../../node_modules/components-font-awesome/less/variables'; - -// App-specific Legacy Variables -@import '../../src/shared/branding/colors.default.less'; -@import '../../src/shared/branding/colors'; - -/** - * Override Variables - * - * NOTE: Used in conditional build scenarios and will need to persist after any refactoring effort. - */ -@import '../../assets/variables'; - -/** - * Legacy Styles - * - * NOTE: Styles below are a mix of 3rd-party dependencies and in-house code. For the 3rd-party - * stuff, we'd be better off managing them via npm where possible. - */ -@import '../../legacy/styles/fonts'; -@import '../../legacy/styles/animations'; -@import '../../legacy/styles/jquery-ui-overrides'; -@import '../../legacy/styles/codemirror'; -@import '../../legacy/styles/angular-scheduler'; -@import '../../legacy/styles/log-viewer'; -@import '../../legacy/styles/event-viewer'; -@import '../../legacy/styles/job-details'; -@import '../../legacy/styles/jobs'; -@import '../../legacy/styles/inventory-edit'; -@import '../../legacy/styles/stdout'; -@import '../../legacy/styles/lists'; -@import '../../legacy/styles/forms'; -@import '../../legacy/styles/dashboard'; -@import '../../legacy/styles/survey-maker'; -@import '../../legacy/styles/text-label'; -@import '../../legacy/styles/bootstrap-datepicker'; -@import '../../legacy/styles/ansible-ui'; - -// Dependency Style Overrides -@import '../../src/shared/bootstrap-settings'; - -// Legacy Utilities -@import '../../src/shared/utilities/alerts'; -@import '../../src/shared/utilities/hidden'; -@import '../../src/shared/utilities/icons'; -@import '../../src/shared/utilities/layer'; -@import '../../src/shared/utilities/truncated-text'; -@import '../../src/shared/utilities/unbold'; -@import '../../src/shared/utilities/wordwrap'; - -// Legacy Layout -@import '../../src/shared/layouts/one-plus-one'; -@import '../../src/shared/layouts/one-plus-two'; - -/** - * Legacy Features - * - * NOTE: "dot" namespacing interferes with Less' ability to infer the .less suffix, so it's - * explicitly added to the import statements below. - */ -@import '../../src/about/about.block.less'; -@import '../../src/access/rbac-role-column/roleList.block.less'; -@import '../../src/access/add-rbac.block.less'; -@import '../../src/activity-stream/streamDetailModal/streamDetailModal.block.less'; -@import '../../src/activity-stream/activitystream.block.less'; -@import '../../src/bread-crumb/bread-crumb.block.less'; -@import '../../src/configuration/configuration.block.less'; -@import '../../src/credentials/ownerList.block.less'; -@import '../../src/home/dashboard/counts/dashboard-counts.block.less'; -@import '../../src/home/dashboard/graphs/dashboard-graphs.block.less'; -@import '../../src/home/dashboard/lists/dashboard-list.block.less'; -@import '../../src/home/dashboard/dashboard.block.less'; -@import '../../src/instance-groups/capacity-bar/capacity-bar.block.less'; -@import '../../src/instance-groups/capacity-adjuster/capacity-adjuster.block.less'; -@import '../../src/instance-groups/instance-group.block.less'; -@import '../../src/instance-groups/instances/instance-modal.block.less'; -@import '../../src/inventories-hosts/inventories/insights/insights.block.less'; -@import '../../src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.block.less'; -@import '../../src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.block.less'; -@import '../../src/inventories-hosts/inventories/inventories.block.less'; -@import '../../src/inventories-hosts/shared/associate-groups/associate-groups.block.less'; -@import '../../src/inventories-hosts/shared/associate-hosts/associate-hosts.block.less'; -@import '../../src/job-submission/job-submission.block.less'; -@import '../../src/license/license.block.less'; -@import '../../src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less'; -@import '../../src/login/loginModal/loginModal.block.less'; -@import '../../src/login/loginModal/loginModalNotice.block.less'; -@import '../../src/management-jobs/card/mgmtcards.block.less'; -@import '../../src/notifications/notifications.block.less'; -@import '../../src/organizations/linkout/addUsers/addUsers.block.less'; -@import '../../src/organizations/orgcards.block.less'; -@import '../../src/portal-mode/portal-mode.block.less'; -@import '../../src/scheduler/repeatFrequencyOptions.block.less'; -@import '../../src/scheduler/schedulerForm.block.less'; -@import '../../src/scheduler/schedulerFormDetail.block.less'; -@import '../../src/scheduler/schedulertime.block.less'; -@import '../../src/scheduler/scheduleToggle.block.less'; -@import '../../src/scheduler/spinnerInput.block.less'; -@import '../../src/shared/container/container.block.less'; -@import '../../src/shared/detail-nav/detail-nav.block.less'; -@import '../../src/shared/icon/icon.block.less'; -@import '../../src/shared/instance-groups-multiselect/instance-groups.block.less'; -@import '../../src/shared/lookup/lookup-modal.block.less'; -@import '../../src/shared/modal/modal'; -@import '../../src/shared/multi-select-preview/multi-select-preview.block.less'; -@import '../../src/shared/paginate/paginate.block.less'; -@import '../../src/shared/prompt/prompt'; -@import '../../src/shared/smart-search/smart-search.block.less'; -@import '../../src/shared/button.block.less'; -@import '../../src/shared/download-standard-out.block.less'; -@import '../../src/shared/media-object.block.less'; -@import '../../src/shared/text-label'; -@import '../../src/shared/upgrade/upgrade.block.less'; -@import '../../src/smart-status/smart-status.block.less'; -@import '../../src/workflow-results/standard-out.block.less'; -@import '../../src/system-tracking/date-picker/date-picker.block.less'; -@import '../../src/system-tracking/fact-data-table/fact-data-table.block.less'; -@import '../../src/system-tracking/fact-module-filter.block.less'; -@import '../../src/system-tracking/fact-module-pickers.block.less'; -@import '../../src/system-tracking/system-tracking-container.block.less'; -@import '../../src/templates/prompt/prompt.block.less'; -@import '../../src/templates/job_templates/multi-credential/multi-credential.block.less'; -@import '../../src/templates/labels/labelsList.block.less'; -@import '../../src/templates/survey-maker/survey-maker.block.less'; -@import '../../src/templates/survey-maker/survey-maker.block.less'; -@import '../../src/templates/survey-maker/shared/survey-controls.block.less'; -@import '../../src/templates/survey-maker/survey-maker.block.less'; -@import '../../src/templates/workflows/workflow.block.less'; -@import '../../src/templates/workflows/workflow-chart/workflow-chart.block.less'; -@import '../../src/templates/workflows/workflow-controls/workflow-controls.block.less'; -@import '../../src/templates/workflows/workflow-maker/workflow-maker.block.less'; -@import '../../src/tooltip/tooltip.block.less'; -@import '../../src/workflow-results/workflow-status-bar/workflow-status-bar.block.less'; -@import '../../src/workflow-results/workflow-results.block.less'; - - -/** - * App-wide style - * - * NOTE: Variables, mixins, and classes below are useful in more than one place across the - * application. When working with Less, if the need for a variable, mixin, class, etc exists in - * more than one location, take a moment to move it to this more general location for easy reuse - * and to avoid duplication. - */ -@import '_variables'; -@import '_mixins'; -@import '_utility'; -@import '_global'; - -/** - * Component and Feature style - * - * NOTE: These index files are aggregation points for components and features. To view the more - * granular imports, view the contents of these files. Variables, classes, etc defined within - * these specific files ought to have no use elsewhere. As we shift to leverage components, very - * few feature-specific styles will exist. - */ -@import '../components/_index'; -@import '../../features/_index'; - -/* - * Resets - * - * NOTE: In some cases, the legacy classes override dependency styles explicitly. In those cases, - * it's necessary to override the overrides. This particular file will only be relevant during - * the transition. - */ -@import '_resets'; - -/** - * Network Visualization Style - * - */ -@import '../../src/network-ui/style.less'; diff --git a/awx/ui/client/src/about/about.block.less b/awx/ui/client/src/about/about.block.less deleted file mode 100644 index d4a178856436..000000000000 --- a/awx/ui/client/src/about/about.block.less +++ /dev/null @@ -1,64 +0,0 @@ -/** @define About */ -.About-ansibleVersion, -.About-cowsayCode { - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; -} - -.About-cowsayContainer { - width: 340px; - margin: 0 auto; -} -.About-cowsayCode { - background-color: @default-bg; - padding-left: 30px; - border-style: none; - max-width: 340px; - padding-left: 30px; -} -.About-modalHeader { - border: none; - padding-bottom: 0px; -} -.About-modalDialog { - max-width: 500px; -} - -.About-modalBody { - padding-top: 0px; - padding-bottom: 0px; -} - -.About-brandImg { - float: @about-modal-float; - width: @about-modal-width; - padding-top: @about-modal-padding-top; - margin-top: @about-modal-margin-top; - margin-left: @about-modal-margin-left; -} - -.About-close { - position: absolute; - top: 15px; - right: 15px; - z-index: 10; -} - -.About-modalFooter { - clear: both; -} - -.About-footerText { - text-align: right; - color: @default-interface-txt; - margin: 0; - font-size: 12px; - padding-top: 10px; -} - -.About-ansibleVersion { - color: @default-data-txt; -} - -.Copyright-text{ - opacity: @copyright-text; -} diff --git a/awx/ui/client/src/about/about.controller.js b/awx/ui/client/src/about/about.controller.js deleted file mode 100644 index 992279aedc87..000000000000 --- a/awx/ui/client/src/about/about.controller.js +++ /dev/null @@ -1,31 +0,0 @@ -export default ['$rootScope', '$scope', '$state', 'ConfigService', - ($rootScope, $scope, $state, ConfigService) => { - - ConfigService.getConfig() - .then(function(config){ - $scope.version = config.version.split('-')[0]; - $scope.ansible_version = config.ansible_version; - $scope.subscription = config.license_info.subscription_name; - $scope.speechBubble = createSpeechBubble($rootScope.BRAND_NAME, config.version); - $('#about-modal').modal('show'); - }); - - $('#about-modal').on('hidden.bs.modal', () => $state.go('dashboard')); - - function createSpeechBubble (brand, version) { - let text = `${brand} ${version}`; - let top = ''; - let bottom = ''; - - for (let i = 0; i < text.length; i++) { - top += '_'; - bottom += '-'; - } - - top = ` __${top}__ \n`; - text = `< ${text} >\n`; - bottom = ` --${bottom}-- `; - - return top + text + bottom; - } -}]; diff --git a/awx/ui/client/src/about/about.partial.html b/awx/ui/client/src/about/about.partial.html deleted file mode 100644 index 3f49a1551477..000000000000 --- a/awx/ui/client/src/about/about.partial.html +++ /dev/null @@ -1,35 +0,0 @@ - diff --git a/awx/ui/client/src/configuration/license.route.js b/awx/ui/client/src/configuration/license.route.js deleted file mode 100644 index 2efa23bcae61..000000000000 --- a/awx/ui/client/src/configuration/license.route.js +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../shared/template-url/template-url.factory'; -import { N_ } from '../i18n'; -import _ from 'lodash'; - -export default { - name: 'configuration.license', - route: '/license', - // templateUrl: templateUrl('license/license'), - // controller: 'licenseController', - data: {}, - ncyBreadcrumb: { - label: N_('LICENSE') - }, - onEnter: ['$state', 'ConfigService', (state, configService) => { - return configService.getConfig() - .then(config => { - if (_.get(config, 'license_info.license_type') === 'open') { - return state.go('setup'); - } - }); - }], - views: { - 'license@configuration': { - templateUrl: templateUrl('license/license'), - controller: 'licenseController' - }, - }, - resolve: { - features: ['CheckLicense', '$rootScope', - function(CheckLicense, $rootScope) { - if($rootScope.licenseMissing === undefined){ - return CheckLicense.notify(); - } - - }], - config: ['ConfigService', 'CheckLicense', '$rootScope', - function(ConfigService, CheckLicense, $rootScope) { - ConfigService.delete(); - return ConfigService.getConfig() - .then(function(config){ - $rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false; - return config; - }); - }] - }, -}; diff --git a/awx/ui/client/src/configuration/main.js b/awx/ui/client/src/configuration/main.js deleted file mode 100644 index 5e20fa830df9..000000000000 --- a/awx/ui/client/src/configuration/main.js +++ /dev/null @@ -1,71 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import configurationService from './configuration.service'; -import ConfigurationUtils from './configurationUtils.service'; -import configurationRoute from './configuration.route'; -import licenseRoute from './license.route'; -import configurationController from './configuration.controller.js'; - -// Import forms -//authorization sub-forms -import configurationAzureForm from './auth-form/sub-forms/auth-azure.form.js'; -import configurationGithubForm from './auth-form/sub-forms/auth-github.form.js'; -import configurationGithubOrgForm from './auth-form/sub-forms/auth-github-org.form'; -import configurationGithubTeamForm from './auth-form/sub-forms/auth-github-team.form'; -import configurationGoogleForm from './auth-form/sub-forms/auth-google-oauth2.form'; -import configurationLdapForm from './auth-form/sub-forms/auth-ldap.form.js'; -import configurationLdap1Form from './auth-form/sub-forms/auth-ldap1.form.js'; -import configurationLdap2Form from './auth-form/sub-forms/auth-ldap2.form.js'; -import configurationLdap3Form from './auth-form/sub-forms/auth-ldap3.form.js'; -import configurationLdap4Form from './auth-form/sub-forms/auth-ldap4.form.js'; -import configurationLdap5Form from './auth-form/sub-forms/auth-ldap5.form.js'; -import configurationRadiusForm from './auth-form/sub-forms/auth-radius.form.js'; -import configurationTacacsForm from './auth-form/sub-forms/auth-tacacs.form.js'; -import configurationSamlForm from './auth-form/sub-forms/auth-saml.form'; - -//system sub-forms -import systemActivityStreamForm from './system-form/sub-forms/system-activity-stream.form.js'; -import systemLoggingForm from './system-form/sub-forms/system-logging.form.js'; -import systemMiscForm from './system-form/sub-forms/system-misc.form.js'; - -import configurationJobsForm from './jobs-form/configuration-jobs.form'; -import configurationUiForm from './ui-form/configuration-ui.form'; - -export default -angular.module('configuration', []) - .controller('ConfigurationController', configurationController) - //auth forms - .factory('configurationAzureForm', configurationAzureForm) - .factory('configurationGithubForm', configurationGithubForm) - .factory('configurationGithubOrgForm', configurationGithubOrgForm) - .factory('configurationGithubTeamForm', configurationGithubTeamForm) - .factory('configurationGoogleForm', configurationGoogleForm) - .factory('configurationLdapForm', configurationLdapForm) - .factory('configurationLdap1Form', configurationLdap1Form) - .factory('configurationLdap2Form', configurationLdap2Form) - .factory('configurationLdap3Form', configurationLdap3Form) - .factory('configurationLdap4Form', configurationLdap4Form) - .factory('configurationLdap5Form', configurationLdap5Form) - .factory('configurationRadiusForm', configurationRadiusForm) - .factory('configurationTacacsForm', configurationTacacsForm) - .factory('configurationSamlForm', configurationSamlForm) - //system forms - .factory('systemActivityStreamForm', systemActivityStreamForm) - .factory('systemLoggingForm', systemLoggingForm) - .factory('systemMiscForm', systemMiscForm) - - //other forms - .factory('ConfigurationJobsForm', configurationJobsForm) - .factory('ConfigurationUiForm', configurationUiForm) - - //helpers and services - .factory('ConfigurationUtils', ConfigurationUtils) - .service('ConfigurationService', configurationService) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(configurationRoute); - $stateExtender.addState(licenseRoute); - }]); diff --git a/awx/ui/client/src/configuration/system-form/configuration-system.controller.js b/awx/ui/client/src/configuration/system-form/configuration-system.controller.js deleted file mode 100644 index 68a01f6a2c19..000000000000 --- a/awx/ui/client/src/configuration/system-form/configuration-system.controller.js +++ /dev/null @@ -1,248 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default [ - '$rootScope', '$scope', '$state', '$stateParams', '$timeout', - 'AngularCodeMirror', - 'systemActivityStreamForm', - 'systemLoggingForm', - 'systemMiscForm', - 'ConfigurationService', - 'ConfigurationUtils', - 'CreateSelect2', - 'GenerateForm', - 'i18n', - 'Rest', - 'ProcessErrors', - 'ngToast', - '$filter', - function( - $rootScope, $scope, $state, $stateParams, $timeout, - AngularCodeMirror, - systemActivityStreamForm, - systemLoggingForm, - systemMiscForm, - ConfigurationService, - ConfigurationUtils, - CreateSelect2, - GenerateForm, - i18n, - Rest, - ProcessErrors, - ngToast, - $filter - ) { - var systemVm = this; - - var generator = GenerateForm; - var formTracker = $scope.$parent.vm.formTracker; - var dropdownValue = 'misc'; - var activeSystemForm = 'misc'; - - if ($stateParams.currentTab === 'system') { - formTracker.setCurrentSystem(activeSystemForm); - } - - var activeForm = function() { - if(!_.get($scope.$parent, [formTracker.currentFormName(), '$dirty'])) { - systemVm.activeSystemForm = systemVm.dropdownValue; - formTracker.setCurrentSystem(systemVm.activeSystemForm); - } else { - var msg = i18n._('You have unsaved changes. Would you like to proceed without saving?'); - var title = i18n._('Warning: Unsaved Changes'); - var buttons = [{ - label: i18n._('Discard changes'), - "class": "btn Form-cancelButton", - "id": "formmodal-cancel-button", - onClick: function() { - $scope.$parent.vm.populateFromApi(); - $scope.$parent[formTracker.currentFormName()].$setPristine(); - systemVm.activeSystemForm = systemVm.dropdownValue; - formTracker.setCurrentSystem(systemVm.activeSystemForm); - $('#FormModal-dialog').dialog('close'); - } - }, { - label: i18n._('Save changes'), - onClick: function() { - $scope.$parent.vm.formSave() - .then(function() { - $scope.$parent[formTracker.currentFormName()].$setPristine(); - $scope.$parent.vm.populateFromApi(); - systemVm.activeSystemForm = systemVm.dropdownValue; - formTracker.setCurrentSystem(systemVm.activeSystemForm); - $('#FormModal-dialog').dialog('close'); - }); - }, - "class": "btn btn-primary", - "id": "formmodal-save-button" - }]; - $scope.$parent.vm.triggerModal(msg, title, buttons); - } - formTracker.setCurrentSystem(systemVm.activeSystemForm); - }; - - var dropdownOptions = [ - {label: i18n._('Activity Stream'), value: 'activity_stream'}, - {label: i18n._('Logging'), value: 'logging'}, - {label: i18n._('Misc. System'), value: 'misc'} - ]; - - CreateSelect2({ - element: '#system-configure-dropdown-nav', - multiple: false, - }); - - var systemForms = [{ - formDef: systemLoggingForm, - id: 'system-logging-form' - }, { - formDef: systemActivityStreamForm, - id: 'system-activity-stream-form' - }, { - formDef: systemMiscForm, - id: 'system-misc-form' - }]; - - var forms = _.pluck(systemForms, 'formDef'); - _.each(forms, function(form) { - var keys = _.keys(form.fields); - _.each(keys, function(key) { - if($scope.$parent.configDataResolve[key].type === 'choice') { - // Create options for dropdowns - var optionsGroup = key + '_options'; - $scope.$parent[optionsGroup] = []; - _.each($scope.$parent.configDataResolve[key].choices, function(choice){ - $scope.$parent[optionsGroup].push({ - name: choice[0], - label: choice[1], - value: choice[0] - }); - }); - } - addFieldInfo(form, key); - }); - // Disable the save button for system auditors - form.buttons.save.disabled = $rootScope.user_is_system_auditor; - }); - - function addFieldInfo(form, key) { - _.extend(form.fields[key], { - awPopOver: ($scope.$parent.configDataResolve[key].defined_in_file) ? - null: $scope.$parent.configDataResolve[key].help_text, - label: $scope.$parent.configDataResolve[key].label, - name: key, - toggleSource: key, - dataPlacement: 'top', - placeholder: ConfigurationUtils.formatPlaceholder($scope.$parent.configDataResolve[key].placeholder, key) || null, - dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required, - ngDisabled: $rootScope.user_is_system_auditor, - disabled: $scope.$parent.configDataResolve[key].disabled || null, - readonly: $scope.$parent.configDataResolve[key].readonly || null, - definedInFile: $scope.$parent.configDataResolve[key].defined_in_file || null - }); - } - - $scope.$parent.parseType = 'json'; - - _.each(systemForms, function(form) { - generator.inject(form.formDef, { - id: form.id, - mode: 'edit', - scope: $scope.$parent, - related: true, - noPanel: true - }); - }); - - var dropdownRendered = false; - - $scope.$on('populated', function() { - populateLogAggregator(false); - }); - - $scope.$on('LOG_AGGREGATOR_TYPE_populated', function(e, data, flag) { - populateLogAggregator(flag); - }); - - $scope.$on('LOG_AGGREGATOR_PROTOCOL_populated', function(e, data, flag) { - populateLogAggregator(flag); - }); - - function populateLogAggregator(flag){ - if($scope.$parent.LOG_AGGREGATOR_TYPE !== null) { - $scope.$parent.LOG_AGGREGATOR_TYPE = _.find($scope.$parent.LOG_AGGREGATOR_TYPE_options, { value: $scope.$parent.LOG_AGGREGATOR_TYPE }); - } - - if($scope.$parent.LOG_AGGREGATOR_PROTOCOL !== null) { - $scope.$parent.LOG_AGGREGATOR_PROTOCOL = _.find($scope.$parent.LOG_AGGREGATOR_PROTOCOL_options, { value: $scope.$parent.LOG_AGGREGATOR_PROTOCOL }); - } - - if($scope.$parent.LOG_AGGREGATOR_LEVEL !== null) { - $scope.$parent.LOG_AGGREGATOR_LEVEL = _.find($scope.$parent.LOG_AGGREGATOR_LEVEL_options, { value: $scope.$parent.LOG_AGGREGATOR_LEVEL }); - } - - if(flag !== undefined){ - dropdownRendered = flag; - } - - if(!dropdownRendered) { - dropdownRendered = true; - CreateSelect2({ - element: '#configuration_logging_template_LOG_AGGREGATOR_TYPE', - multiple: false, - placeholder: i18n._('Select types'), - }); - $scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_TYPE.$setPristine(); - $scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_PROTOCOL.$setPristine(); - $scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_LEVEL.$setPristine(); - } - } - - // Fix for bug where adding selected opts causes form to be $dirty and triggering modal - // TODO Find better solution for this bug - $timeout(function(){ - $scope.$parent.configuration_logging_template_form.$setPristine(); - }, 1000); - - $scope.$parent.vm.testLogging = function() { - Rest.setUrl("/api/v2/settings/logging/test/"); - Rest.post($scope.$parent.vm.getFormPayload()) - .then(() => { - ngToast.success({ - content: `` + - i18n._('Log aggregator test successful.') - }); - }) - .catch(({data, status}) => { - if (status === 500) { - ngToast.danger({ - content: '' + - i18n._('Log aggregator test failed.
Detail: ') + $filter('sanitize')(data.error), - additionalClasses: "LogAggregator-failedNotification" - }); - } else { - ProcessErrors($scope, data, status, null, - { - hdr: i18n._('Error!'), - msg: i18n._('There was an error testing the ' + - 'log aggregator. Returned status: ') + - status - }); - } - }); - }; - - angular.extend(systemVm, { - activeForm: activeForm, - activeSystemForm: activeSystemForm, - dropdownOptions: dropdownOptions, - dropdownValue: dropdownValue, - systemForms: systemForms - }); - } -]; diff --git a/awx/ui/client/src/configuration/system-form/configuration-system.partial.html b/awx/ui/client/src/configuration/system-form/configuration-system.partial.html deleted file mode 100644 index 2b92cc119759..000000000000 --- a/awx/ui/client/src/configuration/system-form/configuration-system.partial.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
-
Sub Category
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
-
-
- -
- - -
-
-
- -
-
-
-
-
- diff --git a/awx/ui/client/src/configuration/system-form/sub-forms/system-activity-stream.form.js b/awx/ui/client/src/configuration/system-form/sub-forms/system-activity-stream.form.js deleted file mode 100644 index 2cc39299ef14..000000000000 --- a/awx/ui/client/src/configuration/system-form/sub-forms/system-activity-stream.form.js +++ /dev/null @@ -1,39 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'configuration_activity_stream_template', - showActions: true, - showHeader: false, - - fields: { - ACTIVITY_STREAM_ENABLED: { - type: 'toggleSwitch', - }, - ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: { - type: 'toggleSwitch' - } - }, - - buttons: { - reset: { - ngShow: '!user_is_system_auditor', - ngClick: 'vm.resetAllConfirm()', - label: i18n._('Revert all to default'), - class: 'Form-resetAll' - }, - cancel: { - ngClick: 'vm.formCancel()', - }, - save: { - ngClick: 'vm.formSave()', - ngDisabled: true - } - } - }; - } -]; diff --git a/awx/ui/client/src/configuration/system-form/sub-forms/system-logging.form.js b/awx/ui/client/src/configuration/system-form/sub-forms/system-logging.form.js deleted file mode 100644 index 388cfb00f85b..000000000000 --- a/awx/ui/client/src/configuration/system-form/sub-forms/system-logging.form.js +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'configuration_logging_template', - showActions: true, - showHeader: false, - - fields: { - LOG_AGGREGATOR_HOST: { - type: 'text', - reset: 'LOG_AGGREGATOR_HOST' - }, - LOG_AGGREGATOR_PORT: { - type: 'text', - reset: 'LOG_AGGREGATOR_PORT' - }, - LOG_AGGREGATOR_TYPE: { - type: 'select', - reset: 'LOG_AGGREGATOR_TYPE', - ngOptions: 'type.label for type in LOG_AGGREGATOR_TYPE_options track by type.value', - }, - LOG_AGGREGATOR_USERNAME: { - type: 'text', - reset: 'LOG_AGGREGATOR_USERNAME' - }, - LOG_AGGREGATOR_PASSWORD: { - type: 'sensitive', - hasShowInputButton: true, - reset: 'LOG_AGGREGATOR_PASSWORD' - }, - LOG_AGGREGATOR_LOGGERS: { - type: 'textarea', - reset: 'LOG_AGGREGATOR_LOGGERS' - }, - LOG_AGGREGATOR_INDIVIDUAL_FACTS: { - type: 'toggleSwitch', - }, - LOG_AGGREGATOR_PROTOCOL: { - type: 'select', - reset: 'LOG_AGGREGATOR_PROTOCOL', - ngOptions: 'type.label for type in LOG_AGGREGATOR_PROTOCOL_options track by type.value', - disableChooseOption: true - }, - LOG_AGGREGATOR_TCP_TIMEOUT: { - type: 'text', - reset: 'LOG_AGGREGATOR_TCP_TIMEOUT', - ngShow: 'LOG_AGGREGATOR_PROTOCOL.value === "tcp" || LOG_AGGREGATOR_PROTOCOL.value === "https"', - awRequiredWhen: { - reqExpression: "LOG_AGGREGATOR_PROTOCOL.value === 'tcp' || LOG_AGGREGATOR_PROTOCOL.value === 'https'", - init: "false" - }, - }, - LOG_AGGREGATOR_LEVEL: { - type: 'select', - reset: 'LOG_AGGREGATOR_LEVEL', - ngOptions: 'type.label for type in LOG_AGGREGATOR_LEVEL_options track by type.value', - disableChooseOption: true - }, - LOG_AGGREGATOR_VERIFY_CERT: { - type: 'toggleSwitch', - ngShow: "LOG_AGGREGATOR_PROTOCOL.value === 'https'" - } - }, - - buttons: { - reset: { - ngShow: '!user_is_system_auditor', - ngClick: 'vm.resetAllConfirm()', - label: i18n._('Revert all to default'), - class: 'Form-resetAll' - }, - testLogging: { - ngClick: 'vm.testLogging()', - label: i18n._('Test'), - class: 'btn-primary', - ngDisabled: 'configuration_logging_template_form.$invalid' - }, - cancel: { - ngClick: 'vm.formCancel()', - }, - save: { - ngClick: 'vm.formSave()', - ngDisabled: true - } - } - }; - } -]; diff --git a/awx/ui/client/src/configuration/system-form/sub-forms/system-misc.form.js b/awx/ui/client/src/configuration/system-form/sub-forms/system-misc.form.js deleted file mode 100644 index 02b71edaec45..000000000000 --- a/awx/ui/client/src/configuration/system-form/sub-forms/system-misc.form.js +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - name: 'configuration_misc_template', - showHeader: false, - showActions: true, - - fields: { - TOWER_URL_BASE: { - type: 'text', - reset: 'TOWER_URL_BASE', - }, - TOWER_ADMIN_ALERTS: { - type: 'toggleSwitch', - }, - ORG_ADMINS_CAN_SEE_ALL_USERS: { - type: 'toggleSwitch', - }, - MANAGE_ORGANIZATION_AUTH: { - type: 'toggleSwitch', - }, - SESSION_COOKIE_AGE: { - type: 'number', - integer: true, - min: 60, - reset: 'SESSION_COOKIE_AGE', - }, - SESSIONS_PER_USER: { - type: 'number', - integer: true, - spinner: true, - min: -1, - reset: 'SESSIONS_PER_USER', - }, - AUTH_BASIC_ENABLED: { - type: 'toggleSwitch', - }, - REMOTE_HOST_HEADERS: { - type: 'textarea', - reset: 'REMOTE_HOST_HEADERS' - } - }, - - buttons: { - reset: { - ngShow: '!user_is_system_auditor', - ngClick: 'vm.resetAllConfirm()', - label: i18n._('Revert all to default'), - class: 'Form-resetAll' - }, - cancel: { - ngClick: 'vm.formCancel()', - }, - save: { - ngClick: 'vm.formSave()', - ngDisabled: true - } - } - }; -} -]; diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js b/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js deleted file mode 100644 index 000b265b936b..000000000000 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js +++ /dev/null @@ -1,113 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default [ - '$scope', - '$rootScope', - '$state', - '$timeout', - 'ConfigurationUiForm', - 'ConfigurationService', - 'CreateSelect2', - 'GenerateForm', - 'i18n', - function( - $scope, - $rootScope, - $state, - $timeout, - ConfigurationUiForm, - ConfigurationService, - CreateSelect2, - GenerateForm, - i18n - ) { - var uiVm = this; - var generator = GenerateForm; - var form = ConfigurationUiForm; - - - var keys = _.keys(form.fields); - _.each(keys, function(key) { - if($scope.$parent.configDataResolve[key].type === 'choice') { - // Create options for dropdowns - var optionsGroup = key + '_options'; - $scope.$parent[optionsGroup] = []; - _.each($scope.$parent.configDataResolve[key].choices, function(choice){ - $scope.$parent[optionsGroup].push({ - name: choice[0], - label: choice[1], - value: choice[0] - }); - }); - } - addFieldInfo(form, key); - }); - - // Disable the save button for system auditors - form.buttons.save.disabled = $rootScope.user_is_system_auditor; - - function addFieldInfo(form, key) { - _.extend(form.fields[key], { - awPopOver: ($scope.$parent.configDataResolve[key].defined_in_file) ? - null: $scope.$parent.configDataResolve[key].help_text, - label: $scope.$parent.configDataResolve[key].label, - name: key, - toggleSource: key, - dataPlacement: 'top', - dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required, - ngDisabled: $rootScope.user_is_system_auditor, - disabled: $scope.$parent.configDataResolve[key].disabled || null, - readonly: $scope.$parent.configDataResolve[key].readonly || null, - definedInFile: $scope.$parent.configDataResolve[key].defined_in_file || null - }); - } - - generator.inject(form, { - id: 'configure-ui-form', - mode: 'edit', - scope: $scope.$parent, - related: true, - noPanel: true - }); - - // Flag to avoid re-rendering and breaking Select2 dropdowns on tab switching - var dropdownRendered = false; - - function populatePendoTrackingState(flag){ - if($scope.$parent.PENDO_TRACKING_STATE !== null) { - $scope.$parent.PENDO_TRACKING_STATE = _.find($scope.$parent.PENDO_TRACKING_STATE_options, { value: $scope.$parent.PENDO_TRACKING_STATE }); - } - - if(flag !== undefined){ - dropdownRendered = flag; - } - - if(!dropdownRendered) { - dropdownRendered = true; - CreateSelect2({ - element: '#configuration_ui_template_PENDO_TRACKING_STATE', - multiple: false, - placeholder: i18n._('Select commands') - }); - } - } - - $scope.$on('PENDO_TRACKING_STATE_populated', function(e, data, flag) { - populatePendoTrackingState(flag); - }); - - $scope.$on('populated', function(){ - populatePendoTrackingState(false); - }); - - angular.extend(uiVm, { - - }); - - } - ]; diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js b/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js deleted file mode 100644 index 4bb9fd34018f..000000000000 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js +++ /dev/null @@ -1,49 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - showHeader: false, - name: 'configuration_ui_template', - showActions: true, - - fields: { - PENDO_TRACKING_STATE: { - type: 'select', - ngChange: 'changedPendo()', - ngOptions: 'choice.label for choice in PENDO_TRACKING_STATE_options track by choice.value', - reset: 'PENDO_TRACKING_STATE' - }, - CUSTOM_LOGO: { - type: 'custom', - reset: 'CUSTOM_LOGO', - control: `` - }, - CUSTOM_LOGIN_INFO: { - type: 'textarea', - reset: 'CUSTOM_LOGIN_INFO', - rows: 6 - } - }, - - buttons: { - reset: { - ngShow: '!user_is_system_auditor', - ngClick: 'vm.resetAllConfirm()', - label: i18n._('Revert all to default'), - class: 'Form-resetAll' - }, - cancel: { - ngClick: 'vm.formCancel()', - }, - save: { - ngClick: 'vm.formSave()', - ngDisabled: true - } - } - }; -} -]; diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html b/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html deleted file mode 100644 index 82ab146e93a8..000000000000 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
-
-
-
-
-
- diff --git a/awx/ui/client/src/credential-types/add/add.controller.js b/awx/ui/client/src/credential-types/add/add.controller.js deleted file mode 100644 index 1e01e1673693..000000000000 --- a/awx/ui/client/src/credential-types/add/add.controller.js +++ /dev/null @@ -1,124 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'Wait', - 'CredentialTypesForm', 'ProcessErrors', 'GetBasePath', - 'GenerateForm', '$scope', '$state', 'Alert', 'GetChoices', 'ParseTypeChange', 'ToJSON', 'CreateSelect2', - function(Rest, Wait, - CredentialTypesForm, ProcessErrors, GetBasePath, - GenerateForm, $scope, $state, Alert, GetChoices, ParseTypeChange, ToJSON, CreateSelect2 - ) { - var form = CredentialTypesForm, - url = GetBasePath('credential_types'); - - init(); - - function init() { - - // for add, don't show ssh - $scope.$on('loadCredentialKindOptions', function() { - $scope.credential_kind_options = $scope.credential_kind_options - .filter(val => val.value === 'net' || - val.value === 'cloud'); - }); - - // Load the list of options for Kind - $scope.$parent.optionsDefer.promise - .then(function(options) { - GetChoices({ - scope: $scope, - url: url, - field: 'kind', - variable: 'credential_kind_options', - options: options, - callback: 'loadCredentialKindOptions' - }); - - const docs_url = 'https://docs.ansible.com/ansible-tower/latest/html/userguide/credential_types.html#getting-started-with-credential-types'; - const docs_help_text = `

Getting Started with Credential Types`; - - const api_inputs_help_text = _.get(options, 'actions.POST.inputs.help_text', "Specification for credential type inputs."); - const api_injectors_help_text = _.get(options, 'actions.POST.injectors.help_text', "Specification for credential type injector."); - - $scope.inputs_help_text = api_inputs_help_text + docs_help_text; - $scope.injectors_help_text = api_injectors_help_text + docs_help_text; - - if (!options.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a credential type.', 'alert-info'); - } - }); - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - // @issue @jmitchell - this setting probably collides with new RBAC can* implementation? - $scope.canEdit = true; - - var callback = function() { - // Make sure the form controller knows there was a change - $scope[form.name + '_form'].$setDirty(); - }; - $scope.parseTypeInputs = 'yaml'; - $scope.parseTypeInjectors = 'yaml'; - ParseTypeChange({ - scope: $scope, - field_id: 'credential_type_inputs', - variable: 'inputs', - onChange: callback, - parse_variable: 'parseTypeInputs' - }); - ParseTypeChange({ - scope: $scope, - field_id: 'credential_type_injectors', - variable: 'injectors', - onChange: callback, - parse_variable: 'parseTypeInjectors' - }); - - CreateSelect2({ - element: '#credential_type_kind', - multiple: false, - }); - } - - // Save - $scope.formSave = function() { - GenerateForm.clearApiErrors($scope); - Wait('start'); - Rest.setUrl(url); - var inputs = ToJSON($scope.parseTypeInputs, $scope.inputs); - var injectors = ToJSON($scope.parseTypeInjectors, $scope.injectors); - if (inputs === null) { - inputs = {}; - } - if (injectors === null) { - injectors = {}; - } - Rest.post({ - name: $scope.name, - description: $scope.description, - kind: "cloud", - inputs: inputs, - injectors: injectors - }) - .then(({data}) => { - $state.go('credentialTypes.edit', { credential_type_id: data.id }, { reload: true }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new credential type. PUT returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('^'); - }; - } -]; diff --git a/awx/ui/client/src/credential-types/add/main.js b/awx/ui/client/src/credential-types/add/main.js deleted file mode 100644 index 9344da0e9856..000000000000 --- a/awx/ui/client/src/credential-types/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './add.controller'; - -export default - angular.module('credentialTypesAdd', []) - .controller('CredentialTypesAddController', controller); diff --git a/awx/ui/client/src/credential-types/credential-types.form.js b/awx/ui/client/src/credential-types/credential-types.form.js deleted file mode 100644 index 6f554654788d..000000000000 --- a/awx/ui/client/src/credential-types/credential-types.form.js +++ /dev/null @@ -1,84 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:CredentialType - * @description This form is for adding/editing a credential type -*/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW CREDENTIAL TYPE'), - editTitle: '{{ name }}', - name: 'credential_type', - basePath: 'credential_types', - stateTree: 'credentialTypes', - breadcrumbName: i18n._('CREDENTIAL TYPE'), - showActions: true, - - // TODO: update fields to be the schema for credential types instead of inventory scripts - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(credential_type.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(credential_type.summary_fields.user_capabilities.edit || canAdd)' - }, - inputs: { - label: i18n._('Input Configuration'), - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - type: 'textarea', - rows: 6, - default: '---', - showParseTypeToggle: true, - parseTypeName: 'parseTypeInputs', - awPopOverWatch: "inputs_help_text", - dataTitle: i18n._('Input Configuration'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(credential_type.summary_fields.user_capabilities.edit || canAdd)' - }, - injectors: { - label: i18n._('Injector Configuration'), - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - type: 'textarea', - rows: 6, - default: '---', - showParseTypeToggle: true, - parseTypeName: 'parseTypeInjectors', - awPopOverWatch: "injectors_help_text", - dataTitle: i18n._('Injector Configuration'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(credential_type.summary_fields.user_capabilities.edit || canAdd)' - }, - }, - - buttons: { //for now always generates - - - - - - \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.block.less b/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.block.less deleted file mode 100644 index a524c3b1a819..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.block.less +++ /dev/null @@ -1,22 +0,0 @@ -.CapacityAdjuster { - margin-right: @at-space-4x; - position: relative; - - &-valueLabel { - bottom: @at-space-5x; - color: @at-color-body-text; - font-size: @at-font-size; - position: absolute; - text-align: center; - width: 100%; - } - - .at-InputSlider { - align-items: center; - } - - .at-InputSlider p { - white-space: nowrap; - margin: 0 10px; - } -} \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.directive.js b/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.directive.js deleted file mode 100644 index e36916aca863..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.directive.js +++ /dev/null @@ -1,57 +0,0 @@ -function CapacityAdjuster (templateUrl, ProcessErrors, Wait) { - return { - scope: { - state: '=', - disabled: '@' - }, - templateUrl: templateUrl('instance-groups/capacity-adjuster/capacity-adjuster'), - restrict: 'E', - replace: true, - link: function(scope) { - const adjustment_values = [{ - label: 'CPU', - value: scope.state.cpu_capacity, - },{ - label: 'RAM', - value: scope.state.mem_capacity - }]; - - scope.min_capacity = _.min(adjustment_values, 'value'); - scope.max_capacity = _.max(adjustment_values, 'value'); - }, - controller: function($http) { - const vm = this || {}; - - vm.slide = (state) => { - Wait('start'); - const data = { - "capacity_adjustment": `${state.capacity_adjustment}` - }; - const req = { - method: 'PUT', - url: state.url, - data - }; - $http(req) - .catch(({data, status}) => { - ProcessErrors(data, status, null, { - hdr: 'Error!', - msg: 'Call failed. Return status: ' + status - }); - }) - .finally(() => { - Wait('stop'); - }); - }; - }, - controllerAs: 'vm' - }; -} - -CapacityAdjuster.$inject = [ - 'templateUrl', - 'ProcessErrors', - 'Wait' -]; - -export default CapacityAdjuster; \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.partial.html b/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.partial.html deleted file mode 100644 index f486745fae22..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-adjuster/capacity-adjuster.partial.html +++ /dev/null @@ -1,15 +0,0 @@ -
- {{ state.capacity_adjustment }} -
-

{{min_capacity.label}} {{min_capacity.value}}

- -

{{max_capacity.label}} {{max_capacity.value}}

-
-
diff --git a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.block.less b/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.block.less deleted file mode 100644 index daee752b84c6..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.block.less +++ /dev/null @@ -1,53 +0,0 @@ -capacity-bar { - align-items: center; - color: @at-color-body-background-dark; - display: flex; - font-size: @at-font-size; - min-width: 100px; - white-space: nowrap; - - .CapacityBar { - background-color: @default-bg; - border-radius: 100vw; - border: 1px solid @default-link; - display: flex; - flex: 1; - height: 10px; - margin-right: @at-space-2x; - min-width: 100px; - overflow: hidden; - width: 100%; - } - - .CapacityBar-remaining { - background-color: @default-link; - flex: 0 0 auto; - } - - .CapacityBar-consumed { - flex: 0 0 auto; - } - - .CapacityBar--offline { - color: @at-red; - border-color: @at-gray-a9; - - .CapacityBar-remaining { - background-color: @at-gray-b7; - } - } - - .Capacity-details--label { - margin-right: @at-space-2x; - text-align: right; - text-transform: uppercase; - } - - .Capacity-details--percentage { - width: 40px; - } - - &:only-child { - margin-right: 50px; - } -} \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.directive.js b/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.directive.js deleted file mode 100644 index e1aea6a50f6b..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.directive.js +++ /dev/null @@ -1,52 +0,0 @@ -function CapacityBar (templateUrl, strings) { - return { - scope: { - capacity: '=', - totalCapacity: '=', - labelValue: '@', - badge: '=' - }, - templateUrl: templateUrl('instance-groups/capacity-bar/capacity-bar'), - restrict: 'E', - link: function(scope) { - scope.isOffline = false; - - scope.$watch('totalCapacity', function(val) { - if (val === 0) { - scope.isOffline = true; - scope.labelValue = strings.get(`capacityBar.IS_OFFLINE_LABEL`); - scope.offlineTip = strings.get(`capacityBar.IS_OFFLINE`); - } else { - scope.isOffline = false; - scope.offlineTip = null; - } - }, true); - - scope.$watch('capacity', function() { - if (scope.totalCapacity !== 0) { - var percentageCapacity = Math - .round(scope.capacity / scope.totalCapacity * 1000) / 10; - - scope.CapacityStyle = { - 'flex-grow': percentageCapacity * 0.01 - }; - - scope.consumedCapacity = `${percentageCapacity}%`; - } else { - scope.CapacityStyle = { - 'flex-grow': 1 - }; - - scope.consumedCapacity = null; - } - }, true); - } - }; -} - -CapacityBar.$inject = [ - 'templateUrl', - 'InstanceGroupsStrings' -]; - -export default CapacityBar; \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.partial.html b/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.partial.html deleted file mode 100644 index a708bb87d021..000000000000 --- a/awx/ui/client/src/instance-groups/capacity-bar/capacity-bar.partial.html +++ /dev/null @@ -1,20 +0,0 @@ - - {{ labelValue }} - - -
-
-
-
- - - {{ consumedCapacity }} - \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/instance-group.block.less b/awx/ui/client/src/instance-groups/instance-group.block.less deleted file mode 100644 index 22b81417ea9e..000000000000 --- a/awx/ui/client/src/instance-groups/instance-group.block.less +++ /dev/null @@ -1,51 +0,0 @@ -.InstanceGroups { - - .BreadCrumb-menuLinkImage:hover { - color: @default-link; - } - - .List-details { - align-self: flex-end; - color: @default-interface-txt; - display: flex; - flex: 0 0 auto; - font-size: 12px; - margin-right:20px; - text-transform: uppercase; - } - - .Capacity-details { - display: flex; - margin-right: 20px; - align-items: center; - - .Capacity-details--label { - color: @default-interface-txt; - margin: 0 10px 0 0; - width: 100px; - } - } - - .RunningJobs-details { - align-items: center; - display: flex; - - .RunningJobs-details--label { - margin: 0 10px 0 0; - } - } - - .List-tableCell--capacityColumn { - display: flex; - height: 40px; - align-items: center; - } - - .List-noItems { - margin-top: 20px; - } - - .List-tableRow .List-titleBadge { - margin: 0 0 0 5px; - } -} diff --git a/awx/ui/client/src/instance-groups/instance-groups.list.js b/awx/ui/client/src/instance-groups/instance-groups.list.js deleted file mode 100644 index 6d22e6cd39ce..000000000000 --- a/awx/ui/client/src/instance-groups/instance-groups.list.js +++ /dev/null @@ -1,31 +0,0 @@ -export default ['i18n', function(i18n) { - return { - name: 'instance_groups' , - basePath: 'instance_groups', - iterator: 'instance_group', - editTitle: i18n._('INSTANCE GROUPS'), - listTitle: i18n._('INSTANCE GROUPS'), - emptyListText: i18n._('THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED'), - index: false, - hover: false, - - fields: { - name: { - key: true, - label: i18n._('Name'), - columnClass: 'col-md-3 col-sm-9 col-xs-9', - modalColumnClass: 'col-md-8', - uiSref: 'instanceGroups.instances.list({instance_group_id: instance_group.id})', - ngClass: "{'isActive' : isActive()}" - }, - consumed_capacity: { - label: i18n._('Capacity'), - nosort: true, - }, - jobs_running: { - label: i18n._('Running Jobs'), - nosort: true, - }, - } - }; -}]; diff --git a/awx/ui/client/src/instance-groups/instance-groups.partial.html b/awx/ui/client/src/instance-groups/instance-groups.partial.html deleted file mode 100644 index bdc05274b6f2..000000000000 --- a/awx/ui/client/src/instance-groups/instance-groups.partial.html +++ /dev/null @@ -1,15 +0,0 @@ -
- -
-
- -
- -
- -
- -
- -
-
diff --git a/awx/ui/client/src/instance-groups/instance-groups.service.js b/awx/ui/client/src/instance-groups/instance-groups.service.js deleted file mode 100644 index 84605bca53b5..000000000000 --- a/awx/ui/client/src/instance-groups/instance-groups.service.js +++ /dev/null @@ -1,41 +0,0 @@ -export default - ['Rest', function(Rest) { - return { - addInstanceGroups: function(url, instance_groups) { - let groups = (instance_groups || []); - Rest.setUrl(url); - let defers = groups.map((group) => Rest.post(group)); - return Promise.all(defers); - }, - editInstanceGroups: function(url, instance_groups) { - Rest.setUrl(url); - let currentGroups = Rest.get() - .then(({data}) => { - return data.results.map((i) => i.id); - }); - - return currentGroups.then(function(current) { - - let groupsToAdd = (instance_groups || []) - .map(val => val.id); - - let groupsToDisassociate = current - .filter(val => groupsToAdd - .indexOf(val) === -1) - .map(val => ({id: val, disassociate: true})); - - let groupsToAssociate = groupsToAdd - .filter(val => current - .indexOf(val) === -1) - .map(val => ({id: val, associate: true})); - - let pass = groupsToDisassociate - .concat(groupsToAssociate); - - Rest.setUrl(url); - let defers = pass.map((group) => Rest.post(group)); - Promise.resolve(defers); - }); - } - }; -}]; \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/instance-groups.strings.js b/awx/ui/client/src/instance-groups/instance-groups.strings.js deleted file mode 100644 index e21ff78396d4..000000000000 --- a/awx/ui/client/src/instance-groups/instance-groups.strings.js +++ /dev/null @@ -1,54 +0,0 @@ -function InstanceGroupsStrings (BaseString) { - BaseString.call(this, 'instanceGroups'); - - const { t } = this; - const ns = this.instanceGroups; - - ns.state = { - ADD_BREADCRUMB_LABEL: t.s('CREATE INSTANCE GROUP'), - EDIT_BREADCRUMB_LABEL: t.s('EDIT INSTANCE GROUP') - }; - - ns.list = { - PANEL_TITLE: t.s('INSTANCE GROUPS') - }; - - ns.tab = { - DETAILS: t.s('DETAILS'), - INSTANCES: t.s('INSTANCES'), - JOBS: t.s('JOBS') - }; - - ns.tooltips = { - ADD_INSTANCE_GROUP: t.s('Create a new Instance Group'), - ASSOCIATE_INSTANCES: t.s('Associate an existing Instance') - }; - - ns.instance = { - PANEL_TITLE: t.s('SELECT INSTANCE') - }; - - ns.capacityBar = { - IS_OFFLINE: t.s('Unavailable to run jobs.'), - IS_OFFLINE_LABEL: t.s('Unavailable') - }; - - ns.jobs = { - PANEL_TITLE: t.s('Jobs') - }; - - ns.error = { - HEADER: this.error.HEADER, - CALL: this.error.CALL, - DELETE: t.s('Unable to delete instance group.'), - }; - - ns.alert = { - MISSING_PARAMETER: t.s('Instance Group parameter is missing.'), - }; - -} - -InstanceGroupsStrings.$inject = ['BaseStringService']; - -export default InstanceGroupsStrings; diff --git a/awx/ui/client/src/instance-groups/instances/instance-modal.block.less b/awx/ui/client/src/instance-groups/instances/instance-modal.block.less deleted file mode 100644 index 64456c768bb8..000000000000 --- a/awx/ui/client/src/instance-groups/instances/instance-modal.block.less +++ /dev/null @@ -1,25 +0,0 @@ -.Modal-backdrop { - position: fixed; - top: 0px; - left: 0px; - height:100%; - width:100%; - background: #000; - z-index: 2; - opacity: 0.5; -} - -.Modal-holder { - position: fixed; - top: 1; - left: 0px; - right: 0px; - top: 0px; - bottom: 0px; - z-index: 3; - overflow-y: scroll; - - .modal-dialog { - padding-top: 100px; - } -} diff --git a/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js b/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js deleted file mode 100644 index 4d492c65b89b..000000000000 --- a/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js +++ /dev/null @@ -1,84 +0,0 @@ -function InstanceModalController ($scope, $state, models, strings, ProcessErrors, Wait) { - const { instance, instanceGroup } = models; - const vm = this || {}; - - vm.setInstances = () => { - vm.instances = instance.get('results').map(instance => { - instance.isSelected = false; - return instance; - }); - }; - - vm.setRelatedInstances = () => { - vm.instanceGroupName = instanceGroup.get('name'); - vm.relatedInstances = instanceGroup.get('related.instances.results'); - vm.relatedInstanceIds = vm.relatedInstances.map(instance => instance.id); - vm.instances = instance.get('results').map(instance => { - instance.isSelected = vm.relatedInstanceIds.includes(instance.id); - return instance; - }); - }; - - init(); - - function init() { - vm.strings = strings; - vm.panelTitle = strings.get('instance.PANEL_TITLE'); - vm.instanceGroupId = instanceGroup.get('id'); - - if (vm.instanceGroupId === undefined) { - vm.setInstances(); - } else { - vm.setRelatedInstances(); - } - } - - $scope.$watch('vm.instances', function() { - vm.selectedRows = _.filter(vm.instances, 'isSelected'); - vm.deselectedRows = _.filter(vm.instances, 'isSelected', false); - }, true); - - vm.submit = () => { - Wait('start'); - const associate = vm.selectedRows - .map(instance => ({id: instance.id})); - const disassociate = vm.deselectedRows - .map(instance => ({id: instance.id, disassociate: true})); - - const all = associate.concat(disassociate); - const defers = all.map((data) => { - const config = { - url: `${vm.instanceGroupId}/instances/`, - data: data - }; - return instanceGroup.http.post(config); - }); - - Promise.all(defers) - .then(vm.onSaveSuccess) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call failed. Return status: ' + status - }); - }) - .finally(() => { - Wait('stop'); - }); - }; - - vm.onSaveSuccess = () => { - $state.go('instanceGroups.instances', {}, {reload: 'instanceGroups.instances'}); - }; -} - -InstanceModalController.$inject = [ - '$scope', - '$state', - 'resolvedModels', - 'InstanceGroupsStrings', - 'ProcessErrors', - 'Wait' -]; - -export default InstanceModalController; diff --git a/awx/ui/client/src/instance-groups/instances/instance-modal.partial.html b/awx/ui/client/src/instance-groups/instances/instance-modal.partial.html deleted file mode 100644 index 15c614a1dff1..000000000000 --- a/awx/ui/client/src/instance-groups/instances/instance-modal.partial.html +++ /dev/null @@ -1,55 +0,0 @@ - \ No newline at end of file diff --git a/awx/ui/client/src/instance-groups/instances/instances-list.partial.html b/awx/ui/client/src/instance-groups/instances/instances-list.partial.html deleted file mode 100644 index 01868ef35de5..000000000000 --- a/awx/ui/client/src/instance-groups/instances/instances-list.partial.html +++ /dev/null @@ -1,79 +0,0 @@ - - - {{ vm.panelTitle }} - - - - {{:: vm.strings.get('tab.DETAILS') }} - {{:: vm.strings.get('tab.INSTANCES') }} - {{:: vm.strings.get('tab.JOBS') }} - - - -
- - - -
- -
-
-
- - -
-
- - -
-
- -
- - - -
- -
- - -
-
-
-
-
diff --git a/awx/ui/client/src/instance-groups/instances/instances.controller.js b/awx/ui/client/src/instance-groups/instances/instances.controller.js deleted file mode 100644 index e81f9c106e50..000000000000 --- a/awx/ui/client/src/instance-groups/instances/instances.controller.js +++ /dev/null @@ -1,111 +0,0 @@ -function InstancesController ($scope, $state, $http, models, Instance, strings, Dataset, ProcessErrors) { - const { instanceGroup } = models; - const vm = this || {}; - vm.strings = strings; - vm.panelTitle = instanceGroup.get('name'); - vm.instances = instanceGroup.get('related.instances.results'); - vm.instance_group_id = instanceGroup.get('id'); - vm.isSuperuser = $scope.$root.user_is_superuser; - - init(); - - function init() { - $scope.list = { - name: 'instances', - iterator: 'instance', - basePath: `/api/v2/instance_groups/${vm.instance_group_id}/instances/` - }; - - $scope.collection = { - iterator: 'instance', - basePath: `/api/v2/instance_groups/${vm.instance_group_id}/instances/` - }; - - $scope[`${$scope.list.iterator}_dataset`] = Dataset.data; - $scope[$scope.list.name] = $scope[`${$scope.list.iterator}_dataset`].results; - $scope.instances = vm.instances; - - $scope.$on('updateDataset', function(e, dataset) { - $scope[`${$scope.list.iterator}_dataset`] = dataset; - $scope[$scope.list.name] = dataset.results; - vm.instances = dataset.results; - }); - } - - vm.tab = { - details: { - _go: 'instanceGroups.edit', - _params: { instance_group_id: vm.instance_group_id } - }, - instances: { - _active: true, - _go: 'instanceGroups.instances', - _params: { instance_group_id: vm.instance_group_id } - }, - jobs: { - _go: 'instanceGroups.jobs', - _params: { instance_group_id: vm.instance_group_id } - } - }; - - vm.tooltips = { - add: strings.get('tooltips.ASSOCIATE_INSTANCES') - }; - - vm.rowAction = { - toggle: { - _disabled: !vm.isSuperuser - }, - capacity_adjustment: { - _disabled: !vm.isSuperuser - } - }; - - vm.toggle = (toggled) => { - const instance = _.find(vm.instances, 'id', toggled.id); - instance.enabled = !instance.enabled; - - const data = { - "capacity_adjustment": instance.capacity_adjustment, - "enabled": instance.enabled - }; - - const req = { - method: 'PUT', - url: instance.url, - data - }; - - $http(req).then(vm.onSaveSuccess) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call failed. Return status: ' + status - }); - }); - }; - - vm.onSaveSuccess = () => { - $state.transitionTo($state.current, $state.params, { - reload: true, location: true, inherit: false, notify: true - }); - }; - - $scope.isActive = function(id) { - let selected = parseInt($state.params.instance_id); - return id === selected; - }; -} - -InstancesController.$inject = [ - '$scope', - '$state', - '$http', - 'resolvedModels', - 'InstanceModel', - 'InstanceGroupsStrings', - 'Dataset', - 'ProcessErrors' -]; - -export default InstancesController; diff --git a/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.controller.js b/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.controller.js deleted file mode 100644 index 62fb924efe35..000000000000 --- a/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.controller.js +++ /dev/null @@ -1,38 +0,0 @@ - -function InstanceGroupJobsContainerController (strings, $state) { - const vm = this || {}; - - init(); - function init() { - const instanceGroupId = $state.params.instance_group_id; - - vm.panelTitle = strings.get('jobs.PANEL_TITLE'); - vm.strings = strings; - - vm.tab = { - details: { - _go: 'instanceGroups.edit', - _params: { instance_group_id: instanceGroupId }, - _label: strings.get('tab.DETAILS') - }, - instances: { - _go: 'instanceGroups.instances', - _params: { instance_group_id: instanceGroupId }, - _label: strings.get('tab.INSTANCES') - }, - jobs: { - _active: true, - _params: { instance_group_id: instanceGroupId }, - _label: strings.get('tab.JOBS') - } - }; - } - -} - -InstanceGroupJobsContainerController.$inject = [ - 'InstanceGroupsStrings', - '$state' -]; - -export default InstanceGroupJobsContainerController; diff --git a/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.partial.html b/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.partial.html deleted file mode 100644 index 8b3f6e5bfd60..000000000000 --- a/awx/ui/client/src/instance-groups/jobs/instanceGroupsJobsListContainer.partial.html +++ /dev/null @@ -1,11 +0,0 @@ - - - {{ vm.panelTitle }} - - - {{:: vm.strings.get('tab.DETAILS') }} - {{:: vm.strings.get('tab.INSTANCES') }} - {{:: vm.strings.get('tab.JOBS') }} - -
-
diff --git a/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.controller.js b/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.controller.js deleted file mode 100644 index 306249f8420b..000000000000 --- a/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.controller.js +++ /dev/null @@ -1,17 +0,0 @@ - -function InstanceGroupJobsContainerController (strings) { - const vm = this || {}; - - init(); - function init() { - vm.panelTitle = strings.get('jobs.PANEL_TITLE'); - vm.strings = strings; - } - -} - -InstanceGroupJobsContainerController.$inject = [ - 'InstanceGroupsStrings' -]; - -export default InstanceGroupJobsContainerController; diff --git a/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.partial.html b/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.partial.html deleted file mode 100644 index 1104ee954896..000000000000 --- a/awx/ui/client/src/instance-groups/jobs/instanceJobsListContainer.partial.html +++ /dev/null @@ -1,6 +0,0 @@ - - - {{ vm.panelTitle }} - -
-
diff --git a/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js b/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js deleted file mode 100644 index 85689196164a..000000000000 --- a/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js +++ /dev/null @@ -1,88 +0,0 @@ -export default ['$scope', '$filter', '$state', 'Alert', 'resolvedModels', 'Dataset', 'InstanceGroupsStrings','ProcessErrors', 'Prompt', 'Wait', - function($scope, $filter, $state, Alert, resolvedModels, Dataset, strings, ProcessErrors, Prompt, Wait) { - const vm = this; - const { instanceGroup } = resolvedModels; - - vm.strings = strings; - vm.isSuperuser = $scope.$root.user_is_superuser; - - init(); - - function init(){ - $scope.list = { - iterator: 'instance_group', - name: 'instance_groups' - }; - - $scope.collection = { - basePath: 'instance_groups', - iterator: 'instance_group' - }; - - $scope[`${$scope.list.iterator}_dataset`] = Dataset.data; - $scope[$scope.list.name] = $scope[`${$scope.list.iterator}_dataset`].results; - $scope.instanceGroupCount = Dataset.data.count; - - $scope.$on('updateDataset', function(e, dataset) { - $scope[`${$scope.list.iterator}_dataset`] = dataset; - $scope[$scope.list.name] = dataset.results; - }); - } - - $scope.$watch('$state.params.instance_group_id', () => { - vm.activeId = parseInt($state.params.instance_group_id); - }); - - vm.tooltips = { - add: strings.get('tooltips.ADD_INSTANCE_GROUP') - }; - - vm.rowAction = { - trash: instance_group => { - return vm.isSuperuser && instance_group.name !== 'tower'; - } - }; - - vm.deleteInstanceGroup = instance_group => { - if (!instance_group) { - Alert(strings.get('error.DELETE'), strings.get('alert.MISSING_PARAMETER')); - return; - } - - Prompt({ - action() { - $('#prompt-modal').modal('hide'); - Wait('start'); - instanceGroup - .request('delete', instance_group.id) - .then(() => handleSuccessfulDelete(instance_group)) - .catch(createErrorHandler('delete instance group', 'DELETE')) - .finally(() => Wait('stop')); - }, - hdr: strings.get('DELETE'), - resourceName: $filter('sanitize')(instance_group.name), - body: `${strings.get('deleteResource.CONFIRM', 'instance group')}` - }); - }; - - function handleSuccessfulDelete(instance_group) { - if (parseInt($state.params.instance_group_id, 0) === instance_group.id) { - $state.go('instanceGroups', $state.params, { reload: true }); - } else { - $state.go('.', $state.params, { reload: true }); - } - } - - function createErrorHandler(path, action) { - return ({ data, status }) => { - const hdr = strings.get('error.HEADER'); - const msg = strings.get('error.CALL', { path, action, status }); - ProcessErrors($scope, data, status, null, { hdr, msg }); - }; - } - - $scope.createInstanceGroup = () => { - $state.go('instanceGroups.add'); - }; - } -]; diff --git a/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html b/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html deleted file mode 100644 index 5aa48b1f29ad..000000000000 --- a/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html +++ /dev/null @@ -1,81 +0,0 @@ - - - {{ vm.strings.get('list.PANEL_TITLE') }} - - {{ instanceGroupCount }} - - - - -
- - -
- -
-
- - - - -
- - - -
- - - - - -
-
- -
- - - -
-
-
-
- - -
- diff --git a/awx/ui/client/src/instance-groups/main.js b/awx/ui/client/src/instance-groups/main.js deleted file mode 100644 index 387a0740dc5a..000000000000 --- a/awx/ui/client/src/instance-groups/main.js +++ /dev/null @@ -1,310 +0,0 @@ -import { templateUrl } from '../shared/template-url/template-url.factory'; -import CapacityAdjuster from './capacity-adjuster/capacity-adjuster.directive'; -import CapacityBar from './capacity-bar/capacity-bar.directive'; -import instanceGroupsMultiselect from '../shared/instance-groups-multiselect/instance-groups.directive'; -import instanceGroupsModal from '../shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive'; - -import AddEditTemplate from './add-edit/add-edit-instance-groups.view.html'; -import AddInstanceGroupController from './add-edit/add-instance-group.controller'; -import EditInstanceGroupController from './add-edit/edit-instance-group.controller'; -import InstanceListPolicy from './add-edit/instance-list-policy.directive.js'; - -import InstanceGroupsTemplate from './list/instance-groups-list.partial.html'; -import InstanceGroupsListController from './list/instance-groups-list.controller'; - -import InstancesTemplate from './instances/instances-list.partial.html'; -import InstanceListController from './instances/instances.controller'; - -import InstanceModalTemplate from './instances/instance-modal.partial.html'; -import InstanceModalController from './instances/instance-modal.controller.js'; - -import list from './instance-groups.list'; -import service from './instance-groups.service'; - -import InstanceGroupsStrings from './instance-groups.strings'; - -import instanceGroupJobsRoute from '~features/jobs/routes/instanceGroupJobs.route.js'; -import instanceJobsRoute from '~features/jobs/routes/instanceJobs.route.js'; - -const MODULE_NAME = 'instanceGroups'; - -function InstanceGroupsResolve ($q, $stateParams, InstanceGroup, Instance) { - const instanceGroupId = $stateParams.instance_group_id; - const instanceId = $stateParams.instance_id; - let promises = {}; - - if (!instanceGroupId && !instanceId) { - promises.instanceGroup = new InstanceGroup(['get', 'options']); - return $q.all(promises); - } - - if (instanceGroupId && instanceId) { - promises.instance = new Instance(['get', 'options'], [instanceId, instanceId]) - .then((instance) => instance.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}})); - return $q.all(promises); - } - - promises.instanceGroup = new InstanceGroup(['get', 'options'], [instanceGroupId, instanceGroupId]) - .then((instanceGroup) => instanceGroup.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}})) - .then((instanceGroup) => instanceGroup.extend('get', 'instances')); - promises.instance = new Instance('get'); - - - return $q.all(promises) - .then(models => models); -} - -InstanceGroupsResolve.$inject = [ - '$q', - '$stateParams', - 'InstanceGroupModel', - 'InstanceModel' -]; - -function InstanceGroupsRun ($stateExtender, strings, ComponentsStrings) { - $stateExtender.addState({ - name: 'instanceGroups', - url: '/instance_groups', - searchPrefix: 'instance_group', - ncyBreadcrumb: { - label: ComponentsStrings.get('layout.INSTANCE_GROUPS') - }, - params: { - instance_group_search: { - value: { - page_size: '10', - order_by: 'name' - }, - dynamic: true - } - }, - data: { - alwaysShowRefreshButton: true, - }, - views: { - '@': { - templateUrl: templateUrl('./instance-groups/instance-groups'), - }, - 'list@instanceGroups': { - templateUrl: InstanceGroupsTemplate, - controller: 'InstanceGroupsListController', - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: InstanceGroupsResolve, - Dataset: ['InstanceGroupList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.add', - url: '/add', - ncyBreadcrumb: { - label: strings.get('state.ADD_BREADCRUMB_LABEL') - }, - params: { - instance_search: { - value: { - order_by: 'hostname', - page_size: '10' - } - } - }, - views: { - 'add@instanceGroups': { - templateUrl: AddEditTemplate, - controller: AddInstanceGroupController, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: InstanceGroupsResolve, - Dataset: [ - '$stateParams', - 'GetBasePath', - 'QuerySet', - ($stateParams, GetBasePath, qs) => { - const searchParams = $stateParams.instance_search; - const searchPath = GetBasePath('instances'); - return qs.search(searchPath, searchParams); - } - ] - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.add.modal', - abstract: true, - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - template: ` - `, - } - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.add.modal.instances', - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - template: '', - } - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.edit', - route: '/:instance_group_id', - ncyBreadcrumb: { - label: strings.get('state.EDIT_BREADCRUMB_LABEL') - }, - params: { - instance_search: { - value: { - order_by: 'hostname', - page_size: '10' - } - } - }, - views: { - 'edit@instanceGroups': { - templateUrl: AddEditTemplate, - controller: EditInstanceGroupController, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: InstanceGroupsResolve, - Dataset: [ - '$stateParams', - 'GetBasePath', - 'QuerySet', - ($stateParams, GetBasePath, qs) => { - const searchParams = $stateParams.instance_search; - const searchPath = GetBasePath('instances'); - return qs.search(searchPath, searchParams); - } - ] - } - }); - - - $stateExtender.addState({ - name: 'instanceGroups.edit.modal', - abstract: true, - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - template: ` - `, - } - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.edit.modal.instances', - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - template: '', - } - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.instances', - url: '/:instance_group_id/instances', - ncyBreadcrumb: { - parent: 'instanceGroups.edit', - label: ComponentsStrings.get('layout.INSTANCES') - }, - params: { - instance_search: { - value: { - page_size: '10', - order_by: 'hostname' - }, - dynamic: true - } - }, - views: { - 'instances@instanceGroups': { - templateUrl: InstancesTemplate, - controller: 'InstanceListController', - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: InstanceGroupsResolve - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.instances.modal', - abstract: true, - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - template: ` - `, - } - } - }); - - $stateExtender.addState({ - name: 'instanceGroups.instances.modal.add', - ncyBreadcrumb: { - skip: true, - }, - views: { - "modal": { - templateUrl: InstanceModalTemplate, - controller: InstanceModalController, - controllerAs: 'vm' - } - }, - resolvedModels: InstanceGroupsResolve - }); - - $stateExtender.addState(instanceJobsRoute); - $stateExtender.addState(instanceGroupJobsRoute); -} - -InstanceGroupsRun.$inject = [ - '$stateExtender', - 'InstanceGroupsStrings', - 'ComponentsStrings' -]; - -angular.module(MODULE_NAME, []) - .service('InstanceGroupsService', service) - .factory('InstanceGroupList', list) - .controller('InstanceGroupsListController', InstanceGroupsListController) - .controller('InstanceListController', InstanceListController) - .directive('instanceListPolicy', InstanceListPolicy) - .directive('instanceGroupsMultiselect', instanceGroupsMultiselect) - .directive('instanceGroupsModal', instanceGroupsModal) - .directive('capacityAdjuster', CapacityAdjuster) - .directive('capacityBar', CapacityBar) - .service('InstanceGroupsStrings', InstanceGroupsStrings) - .run(InstanceGroupsRun); - -export default MODULE_NAME; diff --git a/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js b/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js deleted file mode 100644 index 3cd6a00c288e..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js +++ /dev/null @@ -1,84 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostsService', 'host', '$rootScope', - function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostsService, host, $rootScope){ - $scope.parseType = 'yaml'; - $scope.formCancel = function(){ - $state.go('^', null, {reload: true}); - }; - $scope.toggleHostEnabled = function(){ - if ($scope.host.has_inventory_sources){ - return; - } - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.toggleEnabled = function(){ - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.groupsTab = function(){ - let id = $scope.host.summary_fields.inventory.id; - $state.go('hosts.edit.nested_groups', {inventory_id: id}); - }; - $scope.formSave = function(){ - var host = { - id: $scope.host.id, - variables: $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables, - name: $scope.name, - description: $scope.description, - enabled: $scope.host.enabled - }; - HostsService.put(host).then(function(){ - $state.go('.', null, {reload: true}); - }); - - }; - var init = function(){ - $scope.host = host.data; - $rootScope.breadcrumb.host_name = host.data.name; - $scope.name = host.data.name; - $scope.description = host.data.description; - $scope.variables = getVars(host.data.variables); - ParseTypeChange({ - scope: $scope, - field_id: 'host_variables', - variable: 'variables', - }); - }; - - // Adding this function b/c sometimes extra vars are returned to the - // UI as a string (ex: "foo: bar"), and other times as a - // json-object-string (ex: "{"foo": "bar"}"). CodeMirror wouldn't know - // how to prettify the latter. The latter occurs when host vars were - // system generated and not user-input (such as adding a cloud host); - function getVars(str){ - - // Quick function to test if the host vars are a json-object-string, - // by testing if they can be converted to a JSON object w/o error. - function IsJsonString(str) { - try { - JSON.parse(str); - } catch (e) { - return false; - } - return true; - } - - if(str === ''){ - return '---'; - } - else if(IsJsonString(str)){ - str = JSON.parse(str); - return jsyaml.safeDump(str); - } - else if(!IsJsonString(str)){ - return str; - } - } - - init(); - }]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/edit/main.js b/awx/ui/client/src/inventories-hosts/hosts/edit/main.js deleted file mode 100644 index 2f0c5aee3988..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './host-edit.controller'; - -export default -angular.module('hostsEdit', []) - .controller('HostEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/hosts/host.form.js b/awx/ui/client/src/inventories-hosts/hosts/host.form.js deleted file mode 100644 index 52c6f0d8c1d4..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/host.form.js +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Hosts - * @description This form is for adding/editing a host on the inventory page -*/ - -export default ['i18n', -function(i18n) { - return { - - addTitle: i18n._('CREATE HOST'), - editTitle: '{{ host.name }}', - name: 'host', - basePath: 'hosts', - well: false, - formLabelSize: 'col-lg-3', - formFieldSize: 'col-lg-9', - iterator: 'host', - detailsClick: "$state.go('hosts.edit', null, {reload:true})", - activeEditState: 'hosts.edit', - stateTree: 'hosts', - headerFields:{ - enabled: { - class: 'Form-header-field', - ngClick: 'toggleHostEnabled(host)', - type: 'toggle', - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataTitle: i18n._('Host Enabled'), - ngDisabled: 'host.has_inventory_sources' - } - }, - fields: { - name: { - label: i18n._('Host Name'), - type: 'text', - required: true, - awPopOver: "

" + - i18n._("Provide a host name, ip address, or ip address:port. Examples include:") + - "

" + - "
myserver.domain.com
" + - "127.0.0.1
" + - "10.1.0.140:25
" + - "server.example.com:25" + - "
", - dataTitle: i18n._('Host Name'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)' - }, - description: { - label: i18n._('Description'), - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)', - type: 'text' - }, - variables: { - label: i18n._('Variables'), - type: 'textarea', - rows: 6, - class: 'Form-formGroup--fullWidth', - "default": "---", - awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Host Variables'), - dataPlacement: 'right', - dataContainer: 'body' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - ansible_facts: { - name: 'ansible_facts', - awToolTip: i18n._('Please save before viewing facts.'), - dataPlacement: 'top', - title: i18n._('Facts'), - skipGenerator: true - }, - groups: { - name: 'groups', - awToolTip: i18n._('Please save before defining groups.'), - dataPlacement: 'top', - ngClick: "$state.go('hosts.edit.groups')", - title: i18n._('Groups'), - iterator: 'group', - skipGenerator: true - }, - insights: { - name: 'insights', - awToolTip: i18n._('Please save before viewing Insights.'), - dataPlacement: 'top', - title: i18n._('Insights'), - skipGenerator: true, - ngIf: "host.insights_system_id!==null && host.summary_fields.inventory.hasOwnProperty('insights_credential_id')" - } - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/host.list.js b/awx/ui/client/src/inventories-hosts/hosts/host.list.js deleted file mode 100644 index 1e9347a37752..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/host.list.js +++ /dev/null @@ -1,118 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - name: 'hosts', - iterator: 'host', - editTitle: '{{ selected_group }}', - singleSearchParam: { - param: 'host_filter' - }, - showTitle: false, - well: true, - index: false, - hover: true, - hasChildren: true, - 'class': 'table-no-border', - trackBy: 'host.id', - basePath: 'hosts', - title: false, - actionHolderClass: 'List-actionHolder', - - fields: { - toggleHost: { - ngDisabled: 'host.has_inventory_sources', - label: '', - columnClass: 'List-staticColumn--toggle', - type: "toggle", - ngClick: "toggleHost($event, host)", - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataPlacement: "right", - nosort: true, - }, - active_failures: { - label: '', - iconOnly: true, - nosort: true, - // do not remove this ng-click directive - // the list generator case to handle fields without ng-click - // cannot handle the aw-* directives - ngClick: 'noop()', - awPopOver: "{{ host.job_status_html }}", - dataTitle: "{{ host.job_status_title }}", - awToolTip: "{{ host.badgeToolTip }}", - dataPlacement: 'top', - icon: "{{ 'fa icon-job-' + host.active_failures }}", - id: 'active-failures-action', - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - key: true, - label: i18n._('Name'), - ngClick: "editHost(host.id)", - columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', - dataHostId: "{{ host.id }}", - dataType: "host", - class: 'InventoryManage-breakWord' - }, - inventory: { - label: i18n._('Inventory'), - sourceModel: 'inventory', - sourceField: 'name', - columnClass: 'col-lg-5 col-md-4 col-sm-4 hidden-xs elllipsis', - ngClick: "editInventory(host)" - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', - edit: { - ngClick: "editHost(host.id)", - icon: 'icon-edit', - awToolTip: i18n._('Edit host'), - dataPlacement: 'top', - ngShow: 'host.summary_fields.user_capabilities.edit' - }, - view: { - ngClick: "editHost(host.id)", - awToolTip: i18n._('View host'), - dataPlacement: 'top', - ngShow: '!host.summary_fields.user_capabilities.edit' - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - smart_inventory: { - mode: 'all', - ngClick: "smartInventory()", - awToolTip: "{{ smartInventoryButtonTooltip }}", - dataTipWatch: 'smartInventoryButtonTooltip', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('SMART INVENTORY'), - ngShow: 'canAdd && (hosts.length > 0 || !(searchTags | isEmpty))', - dataPlacement: "top", - ngDisabled: '!enableSmartInventoryButton', - showTipWhenDisabled: true - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/hosts.partial.html b/awx/ui/client/src/inventories-hosts/hosts/hosts.partial.html deleted file mode 100644 index d366b306878d..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/hosts.partial.html +++ /dev/null @@ -1,100 +0,0 @@ -
- -
-
-
-
-
-
INVENTORIES
-
HOSTS
-
-
-
-
-
-
-
-
-
-
- - -
- -
-
No records matched your search.
-
-
NO HOSTS HAVE BEEN CREATED
-
- - - - - - - - - - - - - - - - - - - -
Actions
-
- - -
-
-
- - - -
-
- - -
- - - -
-
-
- - -
-
-
diff --git a/awx/ui/client/src/inventories-hosts/hosts/list/host-list.controller.js b/awx/ui/client/src/inventories-hosts/hosts/list/host-list.controller.js deleted file mode 100644 index bdb7607389a5..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/list/host-list.controller.js +++ /dev/null @@ -1,108 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -function HostsList($scope, HostsList, $rootScope, GetBasePath, - rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostsService, SetStatus, canAdd, $transitions, InventoryHostsStrings) { - - let list = HostsList; - - init(); - - function init(){ - $scope.canAdd = canAdd; - $scope.enableSmartInventoryButton = false; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $rootScope.flashMessage = null; - - $scope.$watchCollection(list.name, function() { - $scope[list.name] = _.map($scope.hosts, function(value) { - value.inventory_name = value.summary_fields.inventory.name; - value.inventory_id = value.summary_fields.inventory.id; - return value; - }); - setJobStatus(); - }); - - $transitions.onSuccess({}, function(trans) { - if(trans.params('to') && trans.params('to').host_search) { - let hasMoreThanDefaultKeys = false; - angular.forEach(trans.params('to').host_search, function(value, key) { - if(key !== 'order_by' && key !== 'page_size' && key !== 'page') { - hasMoreThanDefaultKeys = true; - } - }); - $scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false; - $scope.smartInventoryButtonTooltip = hasMoreThanDefaultKeys ? InventoryHostsStrings.get('smartinventorybutton.ENABLED_INSTRUCTIONS') : InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - else { - $scope.enableSmartInventoryButton = false; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - }); - - } - - function setJobStatus(){ - _.forEach($scope.hosts, function(value) { - SetStatus({ - scope: $scope, - host: value - }); - }); - } - - $scope.createHost = function(){ - $state.go('hosts.add'); - }; - $scope.editHost = function(id){ - $state.go('hosts.edit', {host_id: id}); - }; - $scope.goToInsights = function(id){ - $state.go('hosts.edit.insights', {host_id:id}); - }; - $scope.toggleHost = function(event, host) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - - host.enabled = !host.enabled; - - HostsService.put(host).then(function(){ - $state.go($state.current, null, {reload: true}); - }); - }; - - $scope.smartInventory = function() { - $state.go('inventories.addSmartInventory', {hostfilter: JSON.stringify({"host_filter":`${$state.params.host_search.host_filter}`})}); - }; - - $scope.editInventory = function(host) { - if(host.summary_fields && host.summary_fields.inventory) { - if(host.summary_fields.inventory.kind && host.summary_fields.inventory.kind === 'smart') { - $state.go('inventories.editSmartInventory', {smartinventory_id: host.inventory}); - } - else { - $state.go('inventories.edit', {inventory_id: host.inventory}); - } - } - }; - -} - -export default ['$scope', 'HostsList', '$rootScope', 'GetBasePath', - 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostsService', 'SetStatus', 'canAdd', '$transitions', 'InventoryHostsStrings', HostsList -]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/list/main.js b/awx/ui/client/src/inventories-hosts/hosts/list/main.js deleted file mode 100644 index 068289849492..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/list/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './host-list.controller'; - -export default -angular.module('hostsList', []) - .controller('HostListController', controller); diff --git a/awx/ui/client/src/inventories-hosts/hosts/main.js b/awx/ui/client/src/inventories-hosts/hosts/main.js deleted file mode 100644 index c2675c2fda3f..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/main.js +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import hostEdit from './edit/main'; - import hostList from './list/main'; - import HostsList from './host.list'; - import HostsForm from './host.form'; - import { templateUrl } from '../../shared/template-url/template-url.factory'; - import { N_ } from '../../i18n'; - import ansibleFactsRoute from '../shared/ansible-facts/ansible-facts.route'; - import insightsRoute from '../inventories/insights/insights.route'; - import hostGroupsRoute from './related/groups/hosts-related-groups.route'; - import hostGroupsAssociateRoute from './related/groups/hosts-related-groups-associate.route'; - import hostGroups from './related/groups/main'; - -export default -angular.module('host', [ - hostEdit.name, - hostList.name, - hostGroups.name - ]) - .factory('HostsForm', HostsForm) - .factory('HostsList', HostsList) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(), - stateExtender = $stateExtenderProvider.$get(); - - let generateHostStates = function(){ - let hostTree = stateDefinitions.generateTree({ - parent: 'hosts', // top-most node in the generated tree (will replace this state definition) - modes: ['edit'], - list: 'HostsList', - form: 'HostsForm', - controllers: { - edit: 'HostEditController' - }, - breadcrumbs: { - edit: '{{breadcrumb.host_name}}' - }, - urls: { - list: '/hosts' - }, - data: { - activityStream: true, - activityStreamTarget: 'host' - }, - resolve: { - edit: { - host: ['Rest', '$stateParams', 'GetBasePath', - function(Rest, $stateParams, GetBasePath) { - let path = GetBasePath('hosts') + $stateParams.host_id; - Rest.setUrl(path); - return Rest.get(); - } - ] - }, - list: { - canAdd: ['rbacUiControlService', function(rbacUiControlService) { - return rbacUiControlService.canAdd('hosts') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } - }, - views: { - '@': { - templateUrl: templateUrl('inventories-hosts/hosts/hosts'), - controller: 'HostListController' - } - }, - ncyBreadcrumb: { - label: N_('HOSTS') - } - }); - - let hostAnsibleFacts = _.cloneDeep(ansibleFactsRoute); - hostAnsibleFacts.name = 'hosts.edit.ansible_facts'; - - let hostInsights = _.cloneDeep(insightsRoute); - hostInsights.name = 'hosts.edit.insights'; - - return Promise.all([ - hostTree - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(hostAnsibleFacts), - stateExtender.buildDefinition(hostInsights), - stateExtender.buildDefinition(hostGroupsRoute), - stateExtender.buildDefinition(hostGroupsAssociateRoute) - ]) - }; - }); - }; - - $stateProvider.state({ - name: 'hosts.**', - url: '/hosts', - lazyLoad: () => generateHostStates() - }); - } - ]); diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js deleted file mode 100644 index 9ed6dbfa0b9b..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - name: 'hosts.edit.groups.associate', - squashSearchUrl: true, - url: '/associate?inventory_id', - ncyBreadcrumb:{ - skip:true - }, - views: { - 'modal@hosts.edit': { - templateProvider: function() { - return ``; - }, - controller: function($scope, $q, GroupsService, $state){ - $scope.associateGroups = function(selectedItems){ - var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) ) - .then( () =>{ - deferred.resolve(); - }, (error) => { - deferred.reject(error); - }); - }; - } - } - }, - onExit: function($state) { - if ($state.transition) { - $('#associate-groups-modal').modal('hide'); - $('body').removeClass('modal-open'); - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.controller.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.controller.js deleted file mode 100644 index 81ae0ff8822a..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.controller.js +++ /dev/null @@ -1,96 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'HostsRelatedGroupsList', 'InventoryUpdate', - 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'host', 'GroupsService', - function($scope, $rootScope, $state, $stateParams, HostsRelatedGroupsList, InventoryUpdate, - CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData, host, GroupsService){ - - let list = HostsRelatedGroupsList; - - init(); - - function init(){ - $scope.inventory_id = inventoryData.id; - $scope.canAdd = false; - - rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watchCollection(list.name, function(){ - _.forEach($scope[list.name], buildStatusIndicators); - }); - } - - function buildStatusIndicators(group){ - if (group === undefined || group === null) { - group = {}; - } - - let hosts_status; - - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory_id, - group_id: group.id - }); - _.assign(group, - {hosts_status_tip: hosts_status.tooltip}, - {hosts_status_class: hosts_status.class}); - } - - $scope.editGroup = function(id){ - $state.go('inventories.edit.groups.edit', {inventory_id: $scope.inventory_id, group_id: id}); - }; - - $scope.goToGroupGroups = function(id){ - $state.go('inventories.edit.groups.edit.nested_groups', {inventory_id: $scope.inventory_id, group_id: id}); - }; - - $scope.associateGroup = function() { - $state.go('.associate', {inventory_id: $scope.inventory_id}); - }; - - $scope.disassociateHost = function(group){ - $scope.disassociateGroup = {}; - angular.extend($scope.disassociateGroup, group); - $('#host-disassociate-modal').modal('show'); - }; - - $scope.confirmDisassociate = function(){ - - $('#host-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () { - $('#host-disassociate-modal').off('hidden.bs.modal'); - - let reloadListStateParams = null; - - if($scope.groups.length === 1 && $state.params.group_search && !_.isEmpty($state.params.group_search.page) && $state.params.group_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.group_search.page = (parseInt(reloadListStateParams.group_search.page)-1).toString(); - } - - $state.go('.', reloadListStateParams, {reload: true}); - }); - - GroupsService.disassociateHost(host.id, $scope.disassociateGroup.id).then(() => { - $state.go($state.current, null, {reload: true}); - $('#host-disassociate-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }); - - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js deleted file mode 100644 index b51f233f4a1e..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - name: 'groups', - iterator: 'group', - editTitle: '{{ host.name }}', - well: true, - wellOverride: true, - index: false, - hover: true, - trackBy: 'group.id', - basePath: 'api/v2/hosts/{{$stateParams.host_id}}/groups/', - - fields: { - failed_hosts: { - label: '', - nosort: true, - mode: 'all', - iconOnly: true, - awToolTip: "{{ group.hosts_status_tip }}", - dataPlacement: "top", - icon: "{{ 'fa icon-job-' + group.hosts_status_class }}", - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - label: i18n._('Groups'), - key: true, - ngClick: "goToGroupGroups(group.id)", - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6', - class: 'InventoryManage-breakWord', - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - associate: { - mode: 'all', - ngClick: "associateGroup()", - awToolTip: i18n._("Associate this host with a new group"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - } - }, - - fieldActions: { - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', - "delete": { - //label: 'Delete', - mode: 'all', - ngClick: "disassociateHost(group)", - awToolTip: i18n._('Disassociate group'), - iconClass: 'fa fa-times', - dataPlacement: "top", - ngShow: "group.summary_fields.user_capabilities.delete" - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html deleted file mode 100644 index 94038cfb834d..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html +++ /dev/null @@ -1,34 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js deleted file mode 100644 index fd21ff7b1d60..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js +++ /dev/null @@ -1,62 +0,0 @@ -import { N_ } from '../../../../i18n'; -import {templateUrl} from '../../../../shared/template-url/template-url.factory'; - -export default { - name: "hosts.edit.groups", - url: "/groups?{group_search:queryset}", - resolve: { - Dataset: ['HostsRelatedGroupsList', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - host: ['$stateParams', 'HostsService', function($stateParams, HostsService) { - if($stateParams.host_id){ - return HostsService.get({ id: $stateParams.host_id }).then(function(res) { - return res.data.results[0]; - }); - } - }], - inventoryData: ['InventoriesService', '$stateParams', 'host', function(InventoriesService, $stateParams, host) { - var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id; - return InventoriesService.getInventory(id).then(res => res.data); - }] - }, - params: { - group_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: "" - } - }, - ncyBreadcrumb: { - parent: "hosts.edit", - label: N_("GROUPS") - }, - views: { - 'related': { - templateProvider: function(HostsRelatedGroupsList, generateList, $templateRequest) { - let html = generateList.build({ - list: HostsRelatedGroupsList, - mode: 'edit' - }); - - return $templateRequest(templateUrl('inventories-hosts/hosts/related/groups/hosts-related-groups')).then((template) => { - return html.concat(template); - }); - }, - controller: 'HostsRelatedGroupsController' - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js deleted file mode 100644 index 7caaa49f4122..000000000000 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js +++ /dev/null @@ -1,14 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './hosts-related-groups.controller'; -import hostGroupsDefinition from './hosts-related-groups.list'; - - -export default - angular.module('hostGroups', []) - .factory('HostsRelatedGroupsList', hostGroupsDefinition) - .controller('HostsRelatedGroupsController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js b/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js deleted file mode 100644 index 82f3321652ff..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js +++ /dev/null @@ -1,53 +0,0 @@ -export default { - searchPrefix: 'credential', - url: '/credential', - data: { - formChildState: true - }, - params: { - credential_search: { - value: { - page_size: '5', - credential_type: null - }, - squash: true, - dynamic: true - } - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'related': { - templateProvider: function(ListDefinition, generateList) { - let list_html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - return `${list_html}`; - - } - } - }, - resolve: { - ListDefinition: ['CredentialList', 'i18n', function(CredentialList, i18n) { - let list = _.cloneDeep(CredentialList); - list.lookupConfirmText = i18n._('SELECT'); - return list; - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - let path = GetBasePath(list.name) || GetBasePath(list.basePath); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.controller.js b/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.controller.js deleted file mode 100644 index 0d98739305f4..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.controller.js +++ /dev/null @@ -1,323 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Adhoc - * @description This controller controls the adhoc form creation, command launching and navigating to standard out after command has been succesfully ran. -*/ -function adhocController($q, $scope, $stateParams, - $state, CheckPasswords, PromptForPasswords, CreateLaunchDialog, CreateSelect2, adhocForm, - GenerateForm, Rest, ProcessErrors, GetBasePath, GetChoices, - KindChange, Wait, ParseTypeChange, credentialTypes) { - - // this is done so that we can access private functions for testing, but - // we don't want to populate the "public" scope with these internal - // functions - var privateFn = {}; - this.privateFn = privateFn; - - var id = $stateParams.inventory_id ? $stateParams.inventory_id : $stateParams.smartinventory_id, - hostPattern = $stateParams.pattern; - - // note: put any urls that the controller will use in here!!!! - privateFn.setAvailableUrls = function() { - return { - adhocUrl: GetBasePath('inventory') + id + '/ad_hoc_commands/', - inventoryUrl: GetBasePath('inventory') + id + '/', - machineCredentialUrl: GetBasePath('credentials') + '?kind=ssh' - }; - }; - - var urls = privateFn.setAvailableUrls(); - - // set the default options for the selects of the adhoc form - privateFn.setFieldDefaults = function(verbosity_options, forks_default) { - var verbosity; - for (verbosity in verbosity_options) { - if (verbosity_options[verbosity].isDefault) { - $scope.verbosity = verbosity_options[verbosity]; - } - } - if (forks_default !== 0) { - $("#forks-number").spinner("value", forks_default); - $scope.forks = forks_default; - } - }; - - // set when "working" starts and stops - privateFn.setLoadingStartStop = function() { - var asyncHelper = {}, - formReadyPromise = 0; - - Wait('start'); - - if (asyncHelper.removeChoicesReady) { - asyncHelper.removeChoicesReady(); - } - asyncHelper.removeChoicesReady = $scope.$on('adhocFormReady', - isFormDone); - - // check to see if all requests have completed - function isFormDone() { - formReadyPromise++; - - if (formReadyPromise === 2) { - privateFn.setFieldDefaults($scope.adhoc_verbosity_options, - $scope.forks_field.default); - - CreateSelect2({ - element: '#adhoc_module_name', - multiple: false - }); - - CreateSelect2({ - element: '#adhoc_verbosity', - multiple: false - }); - - Wait('stop'); - } - } - }; - - // set the arguments help to watch on change of the module - privateFn.instantiateArgumentHelp = function() { - $scope.$watch('module_name', function(val) { - if (val) { - // give the docs for the selected module in the popover - $scope.argsPopOver = '

These arguments are used with the ' + - 'specified module. You can find information about the ' + - val.value + ' module here.

'; - } else { - // no module selected - $scope.argsPopOver = "

These arguments are used with the" + - " specified module.

"; - } - }, true); - - // initially set to the same as no module selected - $scope.argsPopOver = "

These arguments are used with the " + - "specified module.

"; - }; - - // pre-populate host patterns from the inventory page and - // delete the value off of rootScope - privateFn.instantiateHostPatterns = function(hostPattern) { - $scope.limit = hostPattern; - $scope.providedHostPatterns = $scope.limit; - }; - - // call helpers to initialize lookup and select fields through get - // requests - privateFn.initializeFields = function(machineCredentialUrl, adhocUrl) { - - // setup module name select - GetChoices({ - scope: $scope, - url: adhocUrl, - field: 'module_name', - variable: 'adhoc_module_options', - callback: 'adhocFormReady' - }); - - // setup verbosity options select - GetChoices({ - scope: $scope, - url: adhocUrl, - field: 'verbosity', - variable: 'adhoc_verbosity_options', - callback: 'adhocFormReady' - }); - }; - - // instantiate all variables on scope for display in the partial - privateFn.initializeForm = function(id, urls, hostPattern) { - // inject the adhoc command form - GenerateForm.inject(adhocForm, - { mode: 'add', related: true, scope: $scope }); - - // set when "working" starts and stops - privateFn.setLoadingStartStop(); - - // put the inventory id on scope for the partial to use - $scope.inv_id = id; - - // set the arguments help to watch on change of the module - privateFn.instantiateArgumentHelp(); - - // pre-populate host patterns from the inventory page and - // delete the value off of rootScope - privateFn.instantiateHostPatterns(hostPattern); - - privateFn.initializeFields(urls.machineCredentialUrl, urls.adhocUrl); - }; - - privateFn.initializeForm(id, urls, hostPattern); - - // init codemirror - $scope.extra_vars = '---'; - $scope.parseType = 'yaml'; - $scope.envParseType = 'yaml'; - ParseTypeChange({ scope: $scope, field_id: 'adhoc_extra_vars' , variable: "extra_vars"}); - - $scope.toggleForm = function(key) { - $scope[key] = !$scope[key]; - }; - - $scope.formCancel = function(){ - $state.go('^'); - }; - - // remove all data input into the form and reset the form back to defaults - $scope.formReset = function () { - GenerateForm.reset(); - - // pre-populate host patterns from the inventory page and - // delete the value off of rootScope - privateFn.instantiateHostPatterns($scope.providedHostPatterns); - - KindChange({ scope: $scope, form: adhocForm, reset: false }); - - // set the default options for the selects of the adhoc form - privateFn.setFieldDefaults($scope.adhoc_verbosity_options, - $scope.forks_default); - }; - - // launch the job with the provided form data - $scope.launchJob = function () { - var adhocUrl = GetBasePath('inventory') + id + - '/ad_hoc_commands/', fld, data={}, html; - - html = '
'; - - // stub the payload with defaults from DRF - data = { - "job_type": "run", - "limit": "", - "credential": "", - "module_name": "command", - "module_args": "", - "forks": 0, - "verbosity": 0, - "extra_vars": "", - "privilege_escalation": "" - }; - - GenerateForm.clearApiErrors($scope); - - // populate data with the relevant form values - for (fld in adhocForm.fields) { - if (adhocForm.fields[fld].type === 'select') { - data[fld] = $scope[fld].value; - } else if ($scope[fld]) { - data[fld] = $scope[fld]; - } - } - - Wait('start'); - - if ($scope.removeStartAdhocRun) { - $scope.removeStartAdhocRun(); - } - $scope.removeStartAdhocRun = $scope.$on('StartAdhocRun', function() { - var password; - for (password in $scope.passwords) { - data[$scope.passwords[password]] = $scope[ - $scope.passwords[password] - ]; - } - // Launch the adhoc job - Rest.setUrl(GetBasePath('inventory') + id + '/ad_hoc_commands/'); - Rest.post(data) - .then(({data}) => { - Wait('stop'); - $state.go('output', {id: data.id, type: 'command'}); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, adhocForm, { - hdr: 'Error!', - msg: 'Failed to launch adhoc command. POST ' + - 'returned status: ' + status }); - }); - }); - - if ($scope.removeCreateLaunchDialog) { - $scope.removeCreateLaunchDialog(); - } - $scope.removeCreateLaunchDialog = $scope.$on('CreateLaunchDialog', - function(e, html, url) { - CreateLaunchDialog({ - scope: $scope, - html: html, - url: url, - callback: 'StartAdhocRun' - }); - }); - - if ($scope.removePromptForPasswords) { - $scope.removePromptForPasswords(); - } - $scope.removePromptForPasswords = $scope.$on('PromptForPasswords', - function(e, passwords_needed_to_start,html, url) { - PromptForPasswords({ scope: $scope, - passwords: passwords_needed_to_start, - callback: 'CreateLaunchDialog', - html: html, - url: url - }); - }); - - if ($scope.removeContinueCred) { - $scope.removeContinueCred(); - } - $scope.removeContinueCred = $scope.$on('ContinueCred', function(e, - passwords) { - if(passwords.length>0){ - $scope.passwords_needed_to_start = passwords; - // only go through the password prompting steps if there are - // passwords to prompt for - $scope.$emit('PromptForPasswords', passwords, html, adhocUrl); - } else { - // if not, go straight to trying to run the job. - $scope.$emit('StartAdhocRun', adhocUrl); - } - }); - - // start adhoc launching routine - CheckPasswords({ - scope: $scope, - credential: $scope.credential, - callback: 'ContinueCred' - }); - }; - - $scope.lookupCredential = function(){ - let credType = _.filter(credentialTypes, function(credType){ - return credType.kind === "ssh"; - }); - $state.go('.credential', { - credential_search: { - credential_type: credType[0].id, - page_size: '5', - page: '1' - } - }); - }; - -} - -export default ['$q', '$scope', '$stateParams', - '$state', 'CheckPasswords', 'PromptForPasswords', 'CreateLaunchDialog', 'CreateSelect2', - 'adhocForm', 'GenerateForm', 'Rest', 'ProcessErrors', 'GetBasePath', - 'GetChoices', 'KindChange', 'Wait', 'ParseTypeChange', 'credentialTypes', - adhocController]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.form.js b/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.form.js deleted file mode 100644 index e3cd25263d47..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.form.js +++ /dev/null @@ -1,167 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Adhoc - * @description This form is for executing an adhoc command -*/ - -export default ['i18n', function(i18n) { - return { - addTitle: i18n._('EXECUTE COMMAND'), - name: 'adhoc', - well: true, - forceListeners: true, - - fields: { - module_name: { - label: i18n._('Module'), - excludeModal: true, - type: 'select', - ngOptions: 'module.label for module in adhoc_module_options' + - ' track by module.value', - ngChange: 'moduleChange()', - required: true, - awPopOver: i18n._('These are the modules that {{BRAND_NAME}} supports running commands against.'), - dataTitle: i18n._('Module'), - dataPlacement: 'right', - dataContainer: 'body' - }, - module_args: { - label: 'Arguments', - type: 'text', - awPopOverWatch: 'argsPopOver', - awPopOver: '{{ argsPopOver }}', - dataTitle: i18n._('Arguments'), - dataPlacement: 'right', - dataContainer: 'body', - autocomplete: false - }, - limit: { - label: i18n._('Limit'), - type: 'text', - - awPopOver: '

The pattern used to target hosts in the ' + - 'inventory. Leaving the field blank, all, and * will ' + - 'all target all hosts in the inventory. You can find ' + - 'more information about Ansible\'s host patterns ' + - 'here.

', - dataTitle: i18n._('Limit'), - dataPlacement: 'right', - dataContainer: 'body' - }, - credential: { - label: i18n._('Machine Credential'), - type: 'lookup', - list: 'CredentialList', - basePath: 'credentials', - sourceModel: 'credential', - sourceField: 'name', - class: 'squeeze', - ngClick: 'lookupCredential()', - awPopOver: '

Select the credential you want to use when ' + - 'accessing the remote hosts to run the command. ' + - 'Choose the credential containing ' + - 'the username and SSH key or password that Ansbile ' + - 'will need to log into the remote hosts.

', - dataTitle: i18n._('Credential'), - dataPlacement: 'right', - dataContainer: 'body', - awRequiredWhen: { - reqExpression: 'credRequired', - init: 'false' - } - }, - verbosity: { - label: i18n._('Verbosity'), - excludeModal: true, - type: 'select', - ngOptions: 'verbosity.label for verbosity in ' + - 'adhoc_verbosity_options ' + - 'track by verbosity.value', - required: true, - awPopOver:'

These are the verbosity levels for standard ' + - 'out of the command run that are supported.', - dataTitle: i18n._('Verbosity'), - dataPlacement: 'right', - dataContainer: 'body', - "default": 1 - }, - forks: { - label: i18n._('Forks'), - id: 'forks-number', - type: 'number', - integer: true, - min: 1, - spinner: true, - 'class': "input-small", - column: 1, - awPopOver: '

' + i18n.sprintf(i18n._('The number of parallel or simultaneous processes to use while executing the playbook. Inputting no value will use ' + - 'the default value from the %sansible configuration file%s.'), '' + - '', '') +'

', - placeholder: 'DEFAULT', - dataTitle: i18n._('Forks'), - dataPlacement: 'right', - dataContainer: "body" - }, - diff_mode: { - label: i18n._('Show Changes'), - type: 'toggleSwitch', - toggleSource: 'diff_mode', - dataTitle: i18n._('Show Changes'), - dataPlacement: 'right', - dataContainer: 'body', - awPopOver: "

" + i18n._("If enabled, show the changes made by Ansible tasks, where supported. This is equivalent to Ansible’s --diff mode.") + "

", - }, - become_enabled: { - label: i18n._('Enable Privilege Escalation'), - type: 'checkbox', - column: 2, - awPopOver: "

If enabled, run this playbook as an administrator. This is the equivalent of passing the --become option to the ansible command.

", - dataPlacement: 'right', - dataTitle: i18n._('Become Privilege Escalation'), - dataContainer: "body" - }, - extra_vars: { - label: i18n._('Extra Variables'), - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - "default": "---", - column: 2, - awPopOver: "

" + i18n.sprintf(i18n._("Pass extra command line variables. This is the %s or %s command line parameter " + - "for %s. Provide key/value pairs using either YAML or JSON."), '-e', '--extra-vars', 'ansible') + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n", - dataTitle: i18n._('Extra Variables'), - dataPlacement: 'right', - dataContainer: "body" - } - }, - buttons: { - reset: { - ngClick: 'formReset()', - ngDisabled: true, - label: i18n._('Reset'), - 'class': 'btn btn-sm Form-cancelButton' - }, - launch: { - label: i18n._('Save'), - ngClick: 'launchJob()', - ngDisabled: true, - 'class': 'btn btn-sm List-buttonSubmit launchButton' - } - }, - - related: {} - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.partial.html b/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.partial.html deleted file mode 100644 index 7d2a01483605..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.partial.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.route.js b/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.route.js deleted file mode 100644 index 30d1f400a5f4..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/adhoc.route.js +++ /dev/null @@ -1,39 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import {templateUrl} from '../../../shared/template-url/template-url.factory'; - import { N_ } from '../../../i18n'; - -export default { - url: '/adhoc', - params:{ - pattern: { - value: 'all', - squash: true - } - }, - data: { - formChildState: true - }, - views: { - 'adhocForm@inventories': { - templateUrl: templateUrl('inventories-hosts/inventories/adhoc/adhoc'), - controller: 'adhocController' - } - }, - ncyBreadcrumb: { - label: N_("RUN COMMAND") - }, - resolve: { - credentialTypes: ['CredentialTypeModel', (CredentialType) => - new CredentialType('get') - .then((model) => { - const credentialTypeRes = model.get(); - return credentialTypeRes.results; - }) - ] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/adhoc/main.js b/awx/ui/client/src/inventories-hosts/inventories/adhoc/main.js deleted file mode 100644 index 1931e8f1d153..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/adhoc/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import adhocController from './adhoc.controller'; -import form from './adhoc.form'; - -export default - angular.module('adhoc', []) - .controller('adhocController', adhocController) - .factory('adhocForm', form); diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.block.less b/awx/ui/client/src/inventories-hosts/inventories/insights/insights.block.less deleted file mode 100644 index 6f3684ef5963..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.block.less +++ /dev/null @@ -1,145 +0,0 @@ -.InsightsLastCheck{ - display: flex; - justify-content: flex-end; - padding-bottom: 20px; - align-items: baseline; -} - -.InsightsNav{ - width: 100%; - display: flex; - border: 1px solid #B7B7B7; - border-radius:5px; - flex-wrap: wrap; - font-size: 14px; - font-weight: bold; -} - -.InsightsNav-rightSide{ - align-items: center; - display: flex; - flex: 1 0 auto; - flex-wrap: wrap; - max-width: 100%; - padding-left: 10px; -} - -.InsightsNav-leftSide{ - align-items: center; - display: flex; - flex: 1 0 auto; - justify-content: flex-end; - flex-wrap: wrap; - max-width: 100%; - padding-right: 10px; -} - -.InsightsNav-badgeTitle{ - color: #707070; - font-size: 14px; - margin-right: 10px; - font-weight: normal; - text-transform: uppercase; - margin-left: 10px; -} - -.InsightsIcon{ - height: 30px; - width:30px; -} - -.InsightsIcon-warning{ - color:@default-warning; - padding-right: 7px; -} - -.InsightsNav-anchor{ - display:flex; - align-items: center; - cursor:pointer; - height: 40px; - padding-right:10px; -} - -.InsightsNav-anchor.is-currentFilter{ - background-color: @f2grey; - padding-top: 5px; - border-bottom: 5px solid @b7grey; -} - -.InsightsNav-anchor:hover{ - background-color: @f2grey; - padding-top: 5px; - border-bottom: 5px solid @b7grey; -} - -.InsightsNav-totalIssues{ - background-color: @default-link; - color: @default-bg; -} - -.InsightsNav-criticalIssues{ - background-color: @default-err; -} - -.InsightsNav-highIssues{ - background-color:@default-warning; -} - -.InsightsNav-mediumIssues{ - background-color: @insights-yellow; -} - -.InsightsNav-lowIssues{ - background-color: @default-succ; -} - -.InsightsNav-solvableBadge{ - background-color: @b7grey; -} - -.InsightsNav-refresh{ - color: @default-icon; - cursor: pointer; - margin-left: 10px; - margin-right: 10px; -} - -.InsightsNav-refresh:hover{ - color: @default-link; -} - -.InsightsBody-missingIssues{ - color: @default-icon; - margin: 10px 0px 10px 0px; -} - -.InsightsRow{ - margin-top:10px; -} -.InsightsRow-title{ - display: flex; - align-items: center; -} - -.InsightsRow-description{ - font-size:14px; - font-weight: bold; - padding-left: 5px; -} - -.InsightsRow-category{ - margin-left: 10px; -} - -.InsightsRow-body{ - padding-left: 35px; -} - -.InsightsRow-plan{ - padding-left: 35px; -} - -.Insights-cancelButton{ - margin-left: 0px!important; -} diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.controller.js b/awx/ui/client/src/inventories-hosts/inventories/insights/insights.controller.js deleted file mode 100644 index 5022fc519d26..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.controller.js +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default [ 'InsightsData', '$scope', 'moment', '$state', 'InventoryData', - 'InsightsService', 'CanRemediate', -function (data, $scope, moment, $state, InventoryData, InsightsService, - CanRemediate) { - - function init() { - $scope.reports = (data && data.reports) ? data.reports : []; - $scope.reports_dataset = (data) ? data : {}; - $scope.currentFilter = "total"; - $scope.solvable_count = filter('solvable').length; - $scope.not_solvable_count = filter('not_solvable').length; - $scope.critical_count = filter('critical').length; - $scope.high_count = filter('high').length; - $scope.med_count = filter('medium').length; - $scope.low_count =filter('low').length; - let a = moment(), b = moment($scope.reports_dataset.last_check_in); - $scope.last_check_in = a.diff(b, 'hours'); - $scope.inventory = (InventoryData) ? InventoryData : {}; - $scope.insights_credential = (InventoryData && InventoryData.summary_fields && - InventoryData.summary_fields.insights_credential && InventoryData.summary_fields.insights_credential.id) ? - InventoryData.summary_fields.insights_credential.id : null; - $scope.canRemediate = CanRemediate; - } - - function filter(str){ - return InsightsService.filter(str, $scope.reports_dataset.reports); - } - - init(); - - $scope.filterReports = function(str){ - $scope.currentFilter = str; - $scope.reports = filter(str); - }; - - $scope.viewDataInInsights = function(){ - window.open(`https://access.redhat.com/insights/inventory?machine=${$scope.$parent.host.insights_system_id}`, '_blank'); - }; - - $scope.remediateInventory = function(inv_id, insights_credential){ - $state.go('templates.addJobTemplate', {inventory_id: inv_id, credential_id: insights_credential}); - }; - - $scope.formCancel = function(){ - $state.go('inventories', null, {reload: true}); - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.partial.html b/awx/ui/client/src/inventories-hosts/inventories/insights/insights.partial.html deleted file mode 100644 index 986decd7b222..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.partial.html +++ /dev/null @@ -1,93 +0,0 @@ -
- - This machine has not checked in with Insights in {{last_check_in}} hours -
-
-
-
-
Total Issues
- {{reports_dataset.reports.length}} -
- -
-
Critical
- {{critical_count}} -
-
-
High
- {{high_count}} -
-
-
Medium
- {{med_count}} -
-
-
Low
- {{low_count}} -
-
-
- -
-
Solvable With Playbook
- {{solvable_count}} -
-
-
No Remediation Playbook Available
- {{not_solvable_count}} -
-
- - -
-
-
- -
-
- No data is available. There are no issues to report. -
-
- The Insights Credential for {{inventory.name}} was not found. -
-
-
- - - - -
ISSUE: {{report.rule.description}}
- {{report.rule.category}} -
-
{{report.rule.summary}}
-
-
-
-
-
- -
- - - -
diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.route.js b/awx/ui/client/src/inventories-hosts/inventories/insights/insights.route.js deleted file mode 100644 index cd116fa06294..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.route.js +++ /dev/null @@ -1,98 +0,0 @@ -import {templateUrl} from '../../../shared/template-url/template-url.factory'; -import { N_ } from '../../../i18n'; - -export default { - url: '/insights', - ncyBreadcrumb: { - label: N_("INSIGHTS") - }, - views: { - 'related': { - controller: 'InsightsController', - templateUrl: templateUrl('inventories-hosts/inventories/insights/insights') - } - }, - resolve: { - InsightsData: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', - (Rest, $stateParams, GetBasePath, ProcessErrors) => { - var path = `${GetBasePath('hosts')}${$stateParams.host_id}/insights`; - Rest.setUrl(path); - return Rest.get() - .then(function(data) { - return (data.data.insights_content); - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get insights info. GET returned status: ' + - response.status - }); - }); - } - ], - InventoryData: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'resourceData', - (Rest, $stateParams, GetBasePath, ProcessErrors, resourceData) => { - if(resourceData.data.type === "host"){ - var path = `${GetBasePath('inventory')}${resourceData.data.inventory}`; - Rest.setUrl(path); - return Rest.get() - .then(function(data) { - return (data.data); - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get insights info. GET returned status: ' + - response.status - }); - }); - } - else if(resourceData.data.type === 'inventory'){ - return resourceData.data; - } - } - ], - checkProjectPermission: ['InventoryData', '$stateParams', 'Rest', 'GetBasePath', - function(InventoryData, $stateParams, Rest, GetBasePath){ - if(_.has(InventoryData, 'summary_fields.insights_credential')){ - let credential_id = InventoryData.summary_fields.insights_credential.id, - path = `${GetBasePath('projects')}?credential__id=${credential_id}&role_level=use_role`; - Rest.setUrl(path); - return Rest.get().then(({data}) => { - if (data.results.length > 0){ - return true; - } - else { - return false; - } - }).catch(() => { - return false; - }); - } - else { - return false; - } - }], - checkInventoryPermission: ['InventoryData', '$stateParams', 'Rest', 'GetBasePath', - function(InventoryData, $stateParams, Rest, GetBasePath){ - if(_.has(InventoryData, 'summary_fields.insights_credential')){ - let path = `${GetBasePath('inventory')}${InventoryData.id}/?role_level=use_role`; - Rest.setUrl(path); - return Rest.get().then(() => { - return true; - }).catch(() => { - return false; - }); - } - else { - return false; - } - }], - CanRemediate: ['checkProjectPermission', 'checkInventoryPermission', - function(checkProjectPermission, checkInventoryPermission){ - // the user can remediate an insights - // inv if the user has "use" permission on - // an insights project and the inventory - // being edited: - return checkProjectPermission === true && checkInventoryPermission === true; - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.service.js b/awx/ui/client/src/inventories-hosts/inventories/insights/insights.service.js deleted file mode 100644 index 36082a71ed79..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/insights.service.js +++ /dev/null @@ -1,36 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default [ () => { - var val = { - filter: function(str, reports_dataset){ - let filteredSet; - if(str === "total"){ - filteredSet = reports_dataset; - } - if(str === "solvable"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.maintenance_actions.length > 0);}); - } - if(str === "not_solvable"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.maintenance_actions.length === 0);}); - } - if(str === "critical"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.rule.severity === 'CRITICAL');}); - } - if(str === "high"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.rule.severity === 'ERROR');}); - } - if(str === "medium"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.rule.severity === 'WARN');}); - } - if(str === "low"){ - filteredSet = _.filter(reports_dataset, (report)=>{return (report.rule.severity === 'INFO');}); - } - return filteredSet; - } - }; - return val; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/main.js b/awx/ui/client/src/inventories-hosts/inventories/insights/main.js deleted file mode 100644 index 03fde02a8ea5..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './insights.controller'; -import planFilter from './plan-filter'; -import service from './insights.service'; - -export default -angular.module('insightsDashboard', []) - .filter('planFilter', planFilter) - .controller('InsightsController', controller) - .service('InsightsService', service); diff --git a/awx/ui/client/src/inventories-hosts/inventories/insights/plan-filter.js b/awx/ui/client/src/inventories-hosts/inventories/insights/plan-filter.js deleted file mode 100644 index 40916cd5eceb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/insights/plan-filter.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default function(){ - return function(plan) { - if(plan === null || plan === undefined){ - return "PLAN: Not Available CREATE A NEW PLAN IN INSIGHTS"; - } else { - let name = (plan.maintenance_plan.name === null) ? "Unnamed Plan" : plan.maintenance_plan.name; - return `${name} (${plan.maintenance_plan.maintenance_id})`; - } - }; - } diff --git a/awx/ui/client/src/inventories-hosts/inventories/inventories.block.less b/awx/ui/client/src/inventories-hosts/inventories/inventories.block.less deleted file mode 100644 index 0121cae5a9e3..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/inventories.block.less +++ /dev/null @@ -1,12 +0,0 @@ -.Inventories-hostStatus { - margin-left: 5px; -} -#inventories-panel { - .completed_jobsList.List-well { - margin: 0; - - .List-noItems { - margin: 0; - } - } -} \ No newline at end of file diff --git a/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html b/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html deleted file mode 100644 index 282fa47ad261..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html +++ /dev/null @@ -1,21 +0,0 @@ -
- -
-
-
-
-
-
-
-
-
-
-
-
INVENTORIES
-
HOSTS
-
-
-
-
-
-
diff --git a/awx/ui/client/src/inventories-hosts/inventories/inventories.route.js b/awx/ui/client/src/inventories-hosts/inventories/inventories.route.js deleted file mode 100644 index fc2888a2ebf1..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/inventories.route.js +++ /dev/null @@ -1,66 +0,0 @@ -import {templateUrl} from '../../shared/template-url/template-url.factory'; -import { N_ } from '../../i18n'; - -export default { - name: 'inventories', // top-most node in the generated tree (will replace this state definition) - route: '/inventories', - ncyBreadcrumb: { - label: N_('INVENTORIES') - }, - data: { - activityStream: true, - activityStreamTarget: 'inventory', - socket: { - "groups": { - "inventories": ["status_changed"] - } - } - }, - views: { - '@': { - templateUrl: templateUrl('inventories-hosts/inventories/inventories') - }, - 'list@inventories': { - templateProvider: function(InventoryList, generateList) { - let html = generateList.build({ - list: InventoryList, - mode: 'edit' - }); - return html; - }, - controller: 'InventoryListController' - } - }, - searchPrefix: 'inventory', - resolve: { - Dataset: ['InventoryList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - canAdd: ['rbacUiControlService', function(rbacUiControlService) { - return rbacUiControlService.canAdd('inventory') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }], - InstanceGroupsData: ['Rest', 'GetBasePath', 'ProcessErrors', (Rest, GetBasePath, ProcessErrors) => { - const url = GetBasePath('instance_groups'); - Rest.setUrl(url); - return Rest.get() - .then(({data}) => { - return data.results.map((i) => ({name: i.name, id: i.id})); - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get instance groups info. GET returned status: ' + status - }); - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/inventory.list.js b/awx/ui/client/src/inventories-hosts/inventories/inventory.list.js deleted file mode 100644 index abcb526d58ba..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/inventory.list.js +++ /dev/null @@ -1,137 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['i18n', function(i18n) { - return { - - name: 'inventories', - iterator: 'inventory', - selectTitle: i18n._('Add Inventories'), - editTitle: i18n._('INVENTORIES'), - listTitle: i18n._('INVENTORIES'), - selectInstructions: i18n.sprintf(i18n._("Click on a row to select it, and click Finished when done. Click the %s button to create a new inventory."), " "), - index: false, - hover: true, - basePath: 'inventory', - title: false, - disableRow: "{{ inventory.pending_deletion }}", - - fields: { - status: { - label: '', - columnClass: 'List-staticColumn--mediumStatus', - nosort: true, - ngClick: "null", - iconOnly: true, - excludeModal: true, - template: ``, - icons: [{ - icon: "{{ 'icon-cloud-' + inventory.syncStatus }}", - awToolTip: "{{ inventory.syncTip }}", - awTipPlacement: "right", - ngClick: "showSourceSummary($event, inventory.id)", - ngClass: "inventory.launch_class" - },{ - icon: "{{ 'icon-job-' + inventory.hostsStatus }}", - awToolTip: false, - ngClick: "showHostSummary($event, inventory.id)", - ngClass: "inventory.host_status_class" - }] - }, - name: { - key: true, - label: i18n._('Name'), - columnClass: 'col-md-4 col-sm-3 col-xs-6 List-staticColumnAdjacent', - modalColumnClass: 'col-md-12', - awToolTip: "{{ inventory.description | sanitize }}", - awTipPlacement: "top", - uiSref: '{{inventory.linkToDetails}}' - }, - kind: { - label: i18n._('Type'), - ngBind: 'inventory.kind_label', - columnClass: 'col-md-2 col-sm-2 hidden-xs' - }, - organization: { - label: i18n._('Organization'), - ngBind: 'inventory.summary_fields.organization.name', - linkTo: '/#/organizations/{{ inventory.organization }}', - sourceModel: 'organization', - sourceField: 'name', - excludeModal: true, - columnClass: 'col-md-3 col-sm-2 hidden-xs' - } - }, - - actions: { - add: { - mode: 'all', // One of: edit, select, all - type: 'buttonDropdown', - basePaths: ['inventories'], - awToolTip: i18n._('Create a new inventory'), - actionClass: 'at-Button--add', - actionId: 'button-add', - options: [ - { - optionContent: i18n._('Inventory'), - optionSref: 'inventories.add', - ngShow: 'canAddInventory' - }, - { - optionContent: i18n._('Smart Inventory'), - optionSref: 'inventories.addSmartInventory', - ngShow: 'canAddInventory' - } - ], - ngShow: 'canAddInventory' - } - }, - - fieldActions: { - columnClass: 'col-md-2 col-sm-3 col-xs-4', - edit: { - label: i18n._('Edit'), - ngClick: 'editInventory(inventory)', - awToolTip: i18n._('Edit inventory'), - dataPlacement: 'top', - ngShow: '!inventory.pending_deletion && inventory.summary_fields.user_capabilities.edit' - }, - network: { - label: i18n._('Network Visualization'), - ngClick: 'goToGraph(inventory)', - awToolTip: i18n._('Network Visualization'), - dataPlacement: 'top', - ngShow: '!inventory.pending_deletion' - }, - copy: { - label: i18n._('Copy'), - ngClick: 'copyInventory(inventory)', - "class": 'btn-danger btn-xs', - awToolTip: i18n._('Copy inventory'), - dataPlacement: 'top', - ngShow: '!inventory.pending_deletion && inventory.summary_fields.user_capabilities.copy' - }, - view: { - label: i18n._('View'), - ngClick: 'editInventory(inventory)', - awToolTip: i18n._('View inventory'), - dataPlacement: 'top', - ngShow: '!inventory.summary_fields.user_capabilities.edit' - }, - "delete": { - label: i18n._('Delete'), - ngClick: "deleteInventory(inventory.id, inventory.name)", - awToolTip: i18n._('Delete inventory'), - dataPlacement: 'top', - ngShow: '!inventory.pending_deletion && inventory.summary_fields.user_capabilities.delete' - - }, - pending_deletion: { - label: i18n._('Pending Delete'), - } - } - };}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.block.less b/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.block.less deleted file mode 100644 index 5d04f3b55821..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.block.less +++ /dev/null @@ -1,3 +0,0 @@ -.HostSummaryPopover-noSourceSummary { - margin-left: 19px; -} diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.controller.js b/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.controller.js deleted file mode 100644 index 77bab5de67b6..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.controller.js +++ /dev/null @@ -1,30 +0,0 @@ -export default [ '$scope', 'Empty', 'Wait', 'GetBasePath', 'Rest', 'ProcessErrors', '$state', - function($scope, Empty, Wait, GetBasePath, Rest, ProcessErrors, $state) { - - $scope.gatherRecentJobs = function(event) { - if (!Empty($scope.inventory.id)) { - if ($scope.inventory.total_hosts > 0) { - Wait('start'); - let url = GetBasePath('jobs') + "?type=job&inventory=" + $scope.inventory.id + "&failed="; - url += ($scope.inventory.has_active_failures) ? "true" : "false"; - url += "&order_by=-finished&page_size=5"; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - $scope.generateTable(data, event); - }) - .catch(({data, status}) => { - ProcessErrors( $scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status - }); - }); - } - } - }; - - $scope.viewJob = function(jobId) { - $state.go('output', { id: jobId, type: 'playbook' }); - }; - - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js b/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js deleted file mode 100644 index 7e6ae14f79f8..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js +++ /dev/null @@ -1,96 +0,0 @@ -export default ['templateUrl', 'Wait', '$filter', '$compile', 'i18n', - function(templateUrl, Wait, $filter, $compile, i18n) { - return { - restrict: 'E', - replace: false, - scope: { - inventory: '=' - }, - controller: 'HostSummaryPopoverController', - templateUrl: templateUrl('inventories-hosts/inventories/list/host-summary-popover/host-summary-popover'), - link: function(scope) { - - function ellipsis(a) { - if (a.length > 20) { - return a.substr(0,20) + '...'; - } - return a; - } - - function attachElem(event, html, title) { - var elem = $(event.target).parent(); - try { - elem.tooltip('hide'); - elem.popover('destroy'); - } - catch(err) { - //ignore - } - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - $('.tooltip').each( function() { - // close any lingering tool tipss - $(this).hide(); - }); - elem.attr({ - "aw-pop-over": html, - "data-popover-title": title, - "data-placement": "right" }); - elem.removeAttr('ng-click'); - $compile(elem)(scope); - scope.triggerPopover(event); - } - - scope.generateTable = function(data, event){ - var html, title = (scope.inventory.has_active_failures) ? "Recent Failed Jobs" : "Recent Successful Jobs"; - Wait('stop'); - if (data.count > 0) { - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - html += "\n"; - - data.results.forEach(function(row) { - if ((scope.inventory.has_active_failures && row.status === 'failed') || (!scope.inventory.has_active_failures && row.status === 'successful')) { - html += "\n"; - html += "\n"; - html += ""; - html += ""; - html += "\n"; - } - }); - html += "\n"; - html += "
" + i18n._("Status") + "" + i18n._("Finished") + "" + i18n._("Name") + "
" + ($filter('longDate')(row.finished)) + "" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; - } - else { - html = "

" + i18n._("No recent job data available for this inventory.") + "

\n"; - } - attachElem(event, html, title); - }; - - scope.showHostSummary = function(event) { - try{ - var elem = $(event.target).parent(); - // if the popover is visible already, then exit the function here - if(elem.data()['bs.popover'].tip().hasClass('in')){ - return; - } - } - catch(err){ - scope.gatherRecentJobs(event); - } - }; - - } - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.partial.html b/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.partial.html deleted file mode 100644 index d990230dcb85..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.partial.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/main.js b/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/main.js deleted file mode 100644 index e2b88a1d06de..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/host-summary-popover/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import directive from './host-summary-popover.directive'; -import controller from './host-summary-popover.controller'; - -export default -angular.module('HostSummaryPopoverModule', []) - .directive('hostSummaryPopover', directive) - .controller('HostSummaryPopoverController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js deleted file mode 100644 index 9fc16afdd060..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js +++ /dev/null @@ -1,175 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Inventories - * @description This controller's for the Inventory page - */ - -function InventoriesList($scope, - $filter, Rest, InventoryList, Prompt, - ProcessErrors, GetBasePath, Wait, $state, - Dataset, canAdd, i18n, Inventory, InventoryHostsStrings) { - - let inventory = new Inventory(); - - let list = InventoryList, - defaultUrl = GetBasePath('inventory'); - - init(); - - function init(){ - $scope.canAddInventory = canAdd; - - $scope.$watchCollection(list.name, function(){ - _.forEach($scope[list.name], processInventoryRow); - }); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - } - - function processInventoryRow(inventory) { - inventory.launch_class = ""; - inventory.host_status_class = "Inventories-hostStatus"; - - if (inventory.has_inventory_sources) { - if (inventory.inventory_sources_with_failures > 0) { - inventory.syncStatus = 'error'; - inventory.syncTip = inventory.inventory_sources_with_failures + i18n._(' sources with sync failures. Click for details'); - } - else { - inventory.syncStatus = 'successful'; - inventory.syncTip = i18n._('No inventory sync failures. Click for details.'); - } - } - else { - inventory.syncStatus = 'na'; - inventory.syncTip = i18n._('Not configured for inventory sync.'); - inventory.launch_class = "btn-disabled"; - } - - if (inventory.has_active_failures) { - inventory.hostsStatus = 'error'; - inventory.hostsTip = inventory.hosts_with_active_failures + i18n._(' hosts with failures. Click for details.'); - } - else if (inventory.total_hosts) { - inventory.hostsStatus = 'successful'; - inventory.hostsTip = i18n._('No hosts with failures. Click for details.'); - } - else { - inventory.hostsStatus = 'none'; - inventory.hostsTip = i18n._('Inventory contains 0 hosts.'); - } - - inventory.kind_label = inventory.kind === '' ? 'Inventory' : (inventory.kind === 'smart' ? i18n._('Smart Inventory'): i18n._('Inventory')); - - inventory.linkToDetails = (inventory.kind && inventory.kind === 'smart') ? `inventories.editSmartInventory({smartinventory_id:${inventory.id}})` : `inventories.edit({inventory_id:${inventory.id}})`; - } - - $scope.copyInventory = inventory => { - Wait('start'); - new Inventory('get', inventory.id) - .then(model => model.copy()) - .then(copy => $scope.editInventory(copy, true)) - .catch(({ data, status }) => { - const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; - ProcessErrors($scope, data, status, null, params); - }) - .finally(() => Wait('stop')); - }; - - $scope.goToGraph = function(inventory){ - $state.go('inventories.edit.networking', {inventory_id: inventory.id, inventory_name: inventory.name}); - }; - - $scope.editInventory = function (inventory, reload) { - const goOptions = reload ? { reload: true } : null; - if(inventory.kind && inventory.kind === 'smart') { - $state.go('inventories.editSmartInventory', {smartinventory_id: inventory.id}, goOptions); - } - else { - $state.go('inventories.edit', {inventory_id: inventory.id}, goOptions); - } - }; - - $scope.deleteInventory = function (id, name) { - var action = function () { - var url = defaultUrl + id + '/'; - Wait('start'); - $('#prompt-modal').modal('hide'); - inventory.request('delete', id) - .then(() => { - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors( $scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - inventory.getDependentResourceCounts(id) - .then((counts) => { - const invalidateRelatedLines = []; - let deleteModalBody = `
${InventoryHostsStrings.get('deleteResource.CONFIRM', 'inventory')}
`; - - counts.forEach(countObj => { - if(countObj.count && countObj.count > 0) { - invalidateRelatedLines.push(`
${countObj.label}${countObj.count}
`); - } - }); - - if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { - deleteModalBody = `
${InventoryHostsStrings.get('deleteResource.USED_BY', 'inventory')} ${InventoryHostsStrings.get('deleteResource.CONFIRM', 'inventory')}
`; - invalidateRelatedLines.forEach(invalidateRelatedLine => { - deleteModalBody += invalidateRelatedLine; - }); - } - - deleteModalBody += '
Note: ' + i18n._('The inventory will be in a pending status until the final delete is processed.') + '
'; - - Prompt({ - hdr: i18n._('Delete'), - resourceName: $filter('sanitize')(name), - body: deleteModalBody, - action: action, - actionText: 'DELETE' - }); - }); - }; - - $scope.$on(`ws-inventories`, function(e, data){ - let inventory = $scope.inventories.find((inventory) => inventory.id === data.inventory_id); - if (data.status === 'pending_deletion' && inventory !== undefined) { - inventory.pending_deletion = true; - } - if (data.status === 'deleted') { - let reloadListStateParams = null; - - if($scope.inventories.length === 1 && $state.params.inventory_search && !_.isEmpty($state.params.inventory_search.page) && $state.params.inventory_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.inventory_search.page = (parseInt(reloadListStateParams.inventory_search.page)-1).toString(); - } - - if (parseInt($state.params.inventory_id) === data.inventory_id) { - $state.go("^", reloadListStateParams, {reload: true}); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - } - }); -} - -export default ['$scope', - '$filter', 'Rest', 'InventoryList', 'Prompt', - 'ProcessErrors', 'GetBasePath', 'Wait', - '$state', 'Dataset', 'canAdd', 'i18n', 'InventoryModel', - 'InventoryHostsStrings', InventoriesList -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/main.js b/awx/ui/client/src/inventories-hosts/inventories/list/main.js deleted file mode 100644 index 4df9ff834f70..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/main.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './inventory-list.controller'; -import hostSummaryPopover from './host-summary-popover/main'; -import sourceSummaryPopover from './source-summary-popover/main'; - -export default -angular.module('InventoryList', [ - hostSummaryPopover.name, - sourceSummaryPopover.name - ]) - .controller('InventoryListController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/main.js b/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/main.js deleted file mode 100644 index 4b6659f51029..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import directive from './source-summary-popover.directive'; -import controller from './source-summary-popover.controller'; - -export default -angular.module('SourceSummaryPopoverModule', []) - .directive('sourceSummaryPopover', directive) - .controller('SourceSummaryPopoverController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.controller.js b/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.controller.js deleted file mode 100644 index 70ae7aeacda3..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.controller.js +++ /dev/null @@ -1,27 +0,0 @@ -export default [ '$scope', 'Wait', 'Empty', 'Rest', 'ProcessErrors', '$state', - function($scope, Wait, Empty, Rest, ProcessErrors, $state) { - - $scope.gatherSourceJobs = function(event) { - if (!Empty($scope.inventory.id)) { - Wait('start'); - Rest.setUrl($scope.inventory.related.inventory_sources + '?order_by=-last_job_run&page_size=5'); - Rest.get() - .then(({data}) => { - $scope.generateTable(data, event); - }) - .catch(({data, status}) => { - ProcessErrors( $scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + $scope.inventory.related.inventory_sources + ' failed. GET returned status: ' + status - }); - }); - } - }; - - $scope.viewJob = function(url) { - // Pull the id out of the URL - var id = url.replace(/^\//, '').split('/')[3]; - $state.go('output', { id, type: 'inventory' } ); - }; - - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js b/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js deleted file mode 100644 index 391c9d20a8ba..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js +++ /dev/null @@ -1,98 +0,0 @@ -export default ['templateUrl', '$compile', 'Wait', '$filter', 'i18n', - function(templateUrl, $compile, Wait, $filter, i18n) { - return { - restrict: 'E', - replace: false, - scope: { - inventory: '=' - }, - controller: 'SourceSummaryPopoverController', - templateUrl: templateUrl('inventories-hosts/inventories/list/source-summary-popover/source-summary-popover'), - link: function(scope) { - - function ellipsis(a) { - if (a.length > 20) { - return a.substr(0,20) + '...'; - } - return a; - } - - function attachElem(event, html, title) { - var elem = $(event.target).parent(); - try { - elem.tooltip('hide'); - elem.popover('destroy'); - } - catch(err) { - //ignore - } - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - $('.tooltip').each( function() { - // close any lingering tool tipss - $(this).hide(); - }); - elem.attr({ - "aw-pop-over": html, - "data-popover-title": title, - "data-placement": "right" }); - elem.removeAttr('ng-click'); - $compile(elem)(scope); - scope.triggerPopover(event); - } - - scope.generateTable = function(data, event) { - var html, title; - - Wait('stop'); - - // Build the html for our popover - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - data.results.forEach( function(row) { - if (row.related.last_update) { - html += ""; - html += ``; - html += ""; - html += ""; - html += "\n"; - } - else { - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - } - }); - html += "\n"; - html += "
" + i18n._("Status") + "" + i18n._("Last Sync") + "" + i18n._("Source") + "
" + ($filter('longDate')(row.last_updated)) + "" + $filter('sanitize')(ellipsis(row.name)) + "
NA" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; - title = "Sync Status"; - attachElem(event, html, title); - }; - - scope.showSourceSummary = function(event) { - try{ - var elem = $(event.target).parent(); - // if the popover is visible already, then exit the function here - if(elem.data()['bs.popover'].tip().hasClass('in')){ - return; - } - } - catch(err){ - scope.gatherSourceJobs(event); - } - }; - } - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.partial.html b/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.partial.html deleted file mode 100644 index 87fd35ef0084..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.partial.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/awx/ui/client/src/inventories-hosts/inventories/main.js b/awx/ui/client/src/inventories-hosts/inventories/main.js deleted file mode 100644 index 66ff152d2310..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/main.js +++ /dev/null @@ -1,356 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import adhoc from './adhoc/main'; -import group from './related/groups/main'; -import sources from './related/sources/main'; -import relatedHost from './related/hosts/main'; -import inventoryList from './list/main'; -import InventoryList from './inventory.list'; -import adHocRoute from './adhoc/adhoc.route'; -import insights from './insights/main'; -import completedJobsRoute from '~features/jobs/routes/inventoryCompletedJobs.route.js'; -import inventorySourceEditRoute from './related/sources/edit/sources-edit.route'; -import inventorySourceEditNotificationsRoute from './related/sources/edit/sources-notifications.route'; -import inventorySourceAddRoute from './related/sources/add/sources-add.route'; -import inventorySourceListRoute from './related/sources/list/sources-list.route'; -import inventorySourceListScheduleRoute from './related/sources/list/schedule/sources-schedule.route'; -import inventorySourceListScheduleAddRoute from './related/sources/list/schedule/sources-schedule-add.route'; -import inventorySourceListScheduleEditRoute from './related/sources/list/schedule/sources-schedule-edit.route'; -import adhocCredentialRoute from './adhoc/adhoc-credential.route'; -import inventoryGroupsList from './related/groups/list/groups-list.route'; -import inventoryGroupsAdd from './related/groups/add/groups-add.route'; -import inventoryGroupsEdit from './related/groups/edit/groups-edit.route'; -import groupNestedGroupsRoute from './related/groups/related/nested-groups/group-nested-groups.route'; -import hostNestedGroupsRoute from './related/hosts/related/nested-groups/host-nested-groups.route'; -import nestedGroupsAdd from './related/groups/related/nested-groups/group-nested-groups-add.route'; -import nestedHostsRoute from './related/groups/related/nested-hosts/group-nested-hosts.route'; -import inventoryHosts from './related/hosts/related-host.route'; -import smartInventoryHosts from './smart-inventory/smart-inventory-hosts.route'; -import inventoriesList from './inventories.route'; -import inventoryHostsAdd from './related/hosts/add/host-add.route'; -import inventoryHostsEdit from './related/hosts/edit/standard-host-edit.route'; -import smartInventoryHostsEdit from './related/hosts/edit/smart-host-edit.route'; -import ansibleFactsRoute from '../shared/ansible-facts/ansible-facts.route'; -import insightsRoute from './insights/insights.route'; -import inventorySourcesCredentialRoute from './related/sources/lookup/sources-lookup-credential.route'; -import inventorySourcesInventoryScriptRoute from './related/sources/lookup/sources-lookup-inventory-script.route'; -import inventorySourcesProjectRoute from './related/sources/lookup/sources-lookup-project.route'; -import SmartInventory from './smart-inventory/main'; -import StandardInventory from './standard-inventory/main'; -import hostNestedGroupsAssociateRoute from './related/hosts/related/nested-groups/host-nested-groups-associate.route'; -import groupNestedGroupsAssociateRoute from './related/groups/related/nested-groups/group-nested-groups-associate.route'; -import nestedHostsAssociateRoute from './related/groups/related/nested-hosts/group-nested-hosts-associate.route'; -import nestedHostsAddRoute from './related/groups/related/nested-hosts/group-nested-hosts-add.route'; - -export default -angular.module('inventory', [ - adhoc.name, - group.name, - sources.name, - relatedHost.name, - inventoryList.name, - insights.name, - SmartInventory.name, - StandardInventory.name, - ]) - .factory('InventoryList', InventoryList) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(), - stateExtender = $stateExtenderProvider.$get(); - - function generateInventoryStates() { - - let standardInventoryAdd = stateDefinitions.generateTree({ - name: 'inventories.add', // top-most node in the generated tree (will replace this state definition) - url: '/inventory/add', - modes: ['add'], - form: 'InventoryForm', - controllers: { - add: 'InventoryAddController' - }, - resolve: { - add: { - canAdd: ['rbacUiControlService', '$state', function(rbacUiControlService, $state) { - return rbacUiControlService.canAdd('inventory') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - $state.go('inventories'); - }); - }] - } - } - }); - - let standardInventoryEdit = stateDefinitions.generateTree({ - name: 'inventories.edit', - url: '/inventory/:inventory_id', - modes: ['edit'], - form: 'InventoryForm', - controllers: { - edit: 'InventoryEditController' - }, - breadcrumbs: { - edit: '{{breadcrumb.inventory_name}}' - }, - data: { - activityStream: true, - activityStreamTarget: 'inventory' - }, - resolve: { - edit: { - smartInventoryRedirect: ['resourceData', '$state', '$stateParams', - function(resourceData, $state, $stateParams){ - if(resourceData.data.kind === "smart"){ - $state.go("inventories.editSmartInventory", {"smartinventory_id": $stateParams.inventory_id}, {reload: true}); - } - }], - InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - let path = `${GetBasePath('inventory')}${$stateParams.inventory_id}/instance_groups/`; - Rest.setUrl(path); - return Rest.get() - .then(({data}) => { - if (data.results.length > 0) { - return data.results; - } - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get instance groups. GET returned ' + - 'status: ' + status - }); - }); - }], - checkProjectPermission: ['resourceData', '$stateParams', 'Rest', 'GetBasePath', 'credentialTypesLookup', - function(resourceData, $stateParams, Rest, GetBasePath, credentialTypesLookup){ - if(_.has(resourceData, 'data.summary_fields.insights_credential')){ - return credentialTypesLookup() - .then(kinds => { - let insightsKind = kinds.Insights; - let path = `${GetBasePath('projects')}?credential__credential_type=${insightsKind}&role_level=use_role`; - Rest.setUrl(path); - return Rest.get().then(({data}) => { - if (data.results.length > 0){ - return true; - } - else { - return false; - } - }).catch(() => { - return false; - }); - }); - } - else { - return false; - } - }], - checkInventoryPermission: ['resourceData', '$stateParams', 'Rest', 'GetBasePath', - function(resourceData, $stateParams, Rest, GetBasePath){ - if(_.has(resourceData, 'data.summary_fields.insights_credential')){ - let path = `${GetBasePath('inventory')}${$stateParams.inventory_id}/?role_level=use_role`; - Rest.setUrl(path); - return Rest.get().then(() => { - return true; - }).catch(() => { - return false; - }); - } - else { - return false; - } - }], - CanRemediate: ['checkProjectPermission', 'checkInventoryPermission', - function(checkProjectPermission, checkInventoryPermission){ - // the user can remediate an insights - // inv if the user has "use" permission on - // an insights project and the inventory - // being edited: - return checkProjectPermission === true && checkInventoryPermission === true; - }] - }, - - } - }); - - let smartInventoryAdd = stateDefinitions.generateTree({ - name: 'inventories.addSmartInventory', // top-most node in the generated tree (will replace this state definition) - url: '/smart/add?hostfilter', - modes: ['add'], - form: 'smartInventoryForm', - controllers: { - add: 'SmartInventoryAddController' - }, - resolve: { - add: { - canAdd: ['rbacUiControlService', '$state', function(rbacUiControlService, $state) { - return rbacUiControlService.canAdd('inventory') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - $state.go('inventories'); - }); - }] - } - } - }); - - let smartInventoryEdit = stateDefinitions.generateTree({ - name: 'inventories.editSmartInventory', - url: '/smart/:smartinventory_id', - modes: ['edit'], - form: 'smartInventoryForm', - controllers: { - edit: 'SmartInventoryEditController' - }, - breadcrumbs: { - edit: '{{breadcrumb.inventory_name}}' - }, - data: { - activityStream: true, - activityStreamTarget: 'inventory', - activityStreamId: 'smartinventory_id' - }, - resolve: { - edit: { - InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - let path = `${GetBasePath('inventory')}${$stateParams.smartinventory_id}/instance_groups/`; - Rest.setUrl(path); - return Rest.get() - .then(({data}) => { - if (data.results.length > 0) { - return data.results; - } - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get instance groups. GET returned ' + - 'status: ' + status - }); - }); - }] - } - } - }); - - let relatedHostsAnsibleFacts = _.cloneDeep(ansibleFactsRoute); - relatedHostsAnsibleFacts.name = 'inventories.edit.hosts.edit.ansible_facts'; - - let relatedHostsInsights = _.cloneDeep(insightsRoute); - relatedHostsInsights.name = 'inventories.edit.hosts.edit.insights'; - - let addSourceCredential = _.cloneDeep(inventorySourcesCredentialRoute); - addSourceCredential.name = 'inventories.edit.inventory_sources.add.credential'; - addSourceCredential.url = '/credential'; - - let addSourceInventoryScript = _.cloneDeep(inventorySourcesInventoryScriptRoute); - addSourceInventoryScript.name = 'inventories.edit.inventory_sources.add.inventory_script'; - addSourceInventoryScript.url = '/inventory_script'; - - let editSourceCredential = _.cloneDeep(inventorySourcesCredentialRoute); - editSourceCredential.name = 'inventories.edit.inventory_sources.edit.credential'; - editSourceCredential.url = '/credential'; - - let addSourceProject = _.cloneDeep(inventorySourcesProjectRoute); - addSourceProject.name = 'inventories.edit.inventory_sources.add.project'; - addSourceProject.url = '/project'; - - let editSourceProject = _.cloneDeep(inventorySourcesProjectRoute); - editSourceProject.name = 'inventories.edit.inventory_sources.edit.project'; - editSourceProject.url = '/project'; - - let editSourceInventoryScript = _.cloneDeep(inventorySourcesInventoryScriptRoute); - editSourceInventoryScript.name = 'inventories.edit.inventory_sources.edit.inventory_script'; - editSourceInventoryScript.url = '/inventory_script'; - - let inventoryCompletedJobsRoute = _.cloneDeep(completedJobsRoute); - inventoryCompletedJobsRoute.name = 'inventories.edit.completed_jobs'; - - let smartInventoryCompletedJobsRoute = _.cloneDeep(completedJobsRoute); - smartInventoryCompletedJobsRoute.name = 'inventories.editSmartInventory.completed_jobs'; - - let inventoryAdhocRoute = _.cloneDeep(adHocRoute); - inventoryAdhocRoute.name = 'inventories.edit.adhoc'; - - let smartInventoryAdhocRoute = _.cloneDeep(adHocRoute); - smartInventoryAdhocRoute.name = 'inventories.editSmartInventory.adhoc'; - - let inventoryAdhocCredential = _.cloneDeep(adhocCredentialRoute); - inventoryAdhocCredential.name = 'inventories.edit.adhoc.credential'; - - let smartInventoryAdhocCredential = _.cloneDeep(adhocCredentialRoute); - smartInventoryAdhocCredential.name = 'inventories.editSmartInventory.adhoc.credential'; - - return Promise.all([ - standardInventoryAdd, - standardInventoryEdit, - smartInventoryAdd, - smartInventoryEdit - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(inventoriesList), - stateExtender.buildDefinition(inventoryAdhocRoute), - stateExtender.buildDefinition(smartInventoryAdhocRoute), - stateExtender.buildDefinition(inventoryAdhocCredential), - stateExtender.buildDefinition(smartInventoryAdhocCredential), - stateExtender.buildDefinition(inventorySourceListScheduleRoute), - stateExtender.buildDefinition(inventorySourceListScheduleAddRoute), - stateExtender.buildDefinition(inventorySourceListScheduleEditRoute), - stateExtender.buildDefinition(relatedHostsAnsibleFacts), - stateExtender.buildDefinition(relatedHostsInsights), - stateExtender.buildDefinition(inventoryGroupsList), - stateExtender.buildDefinition(inventoryGroupsAdd), - stateExtender.buildDefinition(inventoryGroupsEdit), - stateExtender.buildDefinition(groupNestedGroupsRoute), - stateExtender.buildDefinition(nestedHostsRoute), - stateExtender.buildDefinition(inventoryHosts), - stateExtender.buildDefinition(smartInventoryHosts), - stateExtender.buildDefinition(inventoryHostsAdd), - stateExtender.buildDefinition(inventoryHostsEdit), - stateExtender.buildDefinition(smartInventoryHostsEdit), - stateExtender.buildDefinition(hostNestedGroupsRoute), - stateExtender.buildDefinition(inventorySourceListRoute), - stateExtender.buildDefinition(inventorySourceAddRoute), - stateExtender.buildDefinition(inventorySourceEditRoute), - stateExtender.buildDefinition(inventorySourceEditNotificationsRoute), - stateExtender.buildDefinition(inventoryCompletedJobsRoute), - stateExtender.buildDefinition(smartInventoryCompletedJobsRoute), - stateExtender.buildDefinition(addSourceCredential), - stateExtender.buildDefinition(addSourceInventoryScript), - stateExtender.buildDefinition(editSourceCredential), - stateExtender.buildDefinition(editSourceInventoryScript), - stateExtender.buildDefinition(addSourceProject), - stateExtender.buildDefinition(editSourceProject), - stateExtender.buildDefinition(groupNestedGroupsAssociateRoute), - stateExtender.buildDefinition(hostNestedGroupsAssociateRoute), - stateExtender.buildDefinition(nestedHostsAssociateRoute), - stateExtender.buildDefinition(nestedGroupsAdd), - stateExtender.buildDefinition(nestedHostsAddRoute) - ]) - }; - }); - - } - - $stateProvider.state({ - name: 'inventories.**', - url: '/inventories', - reloadOnSearch: true, - lazyLoad: () => generateInventoryStates() - }); - } - ]); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.controller.js deleted file mode 100644 index 80a1d917b738..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.controller.js +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'GroupForm', - 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService', - 'GetChoices', 'GetBasePath', 'CreateSelect2', - 'rbacUiControlService', 'ToJSON', - function($state, $stateParams, $scope, GroupForm, ParseTypeChange, - GenerateForm, inventoryData, GroupsService, GetChoices, - GetBasePath, CreateSelect2, rbacUiControlService, - ToJSON) { - - let form = GroupForm; - init(); - - function init() { - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - $scope.parseType = 'yaml'; - $scope.envParseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - field_id: 'group_group_variables', - variable: 'group_variables', - }); - } - - $scope.formCancel = function() { - $state.go('^'); - }; - - $scope.formSave = function() { - var json_data; - json_data = ToJSON($scope.parseType, $scope.group_variables, true); - - var group = { - variables: json_data, - name: $scope.name, - description: $scope.description, - inventory: inventoryData.id - }; - - GroupsService.post(group).then(res => { - if ($stateParams.group_id && _.has(res, 'data')) { - return GroupsService.associateGroup(res.data, $stateParams.group_id) - .then(() => $state.go('^', null, { reload: true })); - } else if(_.has(res, 'data.id')){ - $state.go('^.edit', { group_id: res.data.id }, { reload: true }); - } - }); - - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js deleted file mode 100644 index 7f9e58ff9f68..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js +++ /dev/null @@ -1,22 +0,0 @@ -import { N_ } from '../../../../../i18n'; - -export default { - name: "inventories.edit.groups.add", - url: "/add", - ncyBreadcrumb: { - parent: "inventories.edit.groups", - label: N_("CREATE GROUP") - }, - views: { - 'groupForm@inventories': { - templateProvider: function(GenerateForm, GroupForm) { - let form = GroupForm; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: 'GroupAddController' - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/main.js deleted file mode 100644 index 8de2bc98de29..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './groups-add.controller'; - -export default -angular.module('groupAdd', []) - .controller('GroupAddController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.controller.js deleted file mode 100644 index b185bf9c9917..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.controller.js +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'ParseVariableString', 'rbacUiControlService', 'ToJSON', - 'ParseTypeChange', 'GroupsService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'groupData', '$rootScope', - function($state, $stateParams, $scope, ParseVariableString, rbacUiControlService, ToJSON, - ParseTypeChange, GroupsService, GetChoices, GetBasePath, CreateSelect2, groupData, $rootScope) { - - init(); - - function init() { - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - - $scope = angular.extend($scope, groupData); - - $rootScope.breadcrumb.group_name = groupData.name; - - $scope.$watch('summary_fields.user_capabilities.edit', function(val) { - $scope.canAdd = val; - }); - - // init codemirror(s) - $scope.group_variables = $scope.variables === null || $scope.variables === '' ? '---' : ParseVariableString($scope.variables); - $scope.parseType = 'yaml'; - $scope.envParseType = 'yaml'; - - - ParseTypeChange({ - scope: $scope, - field_id: 'group_group_variables', - variable: 'group_variables', - }); - } - - $scope.formCancel = function() { - $state.go('^'); - }; - - $scope.formSave = function() { - var json_data; - json_data = ToJSON($scope.parseType, $scope.group_variables, true); - // group fields - var group = { - variables: json_data, - name: $scope.name, - description: $scope.description, - inventory: $scope.inventory, - id: groupData.id - }; - GroupsService.put(group).then(() => $state.go($state.current, null, { reload: true })); - }; - - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js deleted file mode 100644 index 0fbdd763c77f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js +++ /dev/null @@ -1,25 +0,0 @@ -export default { - name: "inventories.edit.groups.edit", - url: "/edit/:group_id", - ncyBreadcrumb: { - parent: "inventories.edit.groups", - label: "{{breadcrumb.group_name}}" - }, - views: { - 'groupForm@inventories': { - templateProvider: function(GenerateForm, GroupForm) { - let form = GroupForm; - return GenerateForm.buildHTML(form, { - mode: 'edit', - related: false - }); - }, - controller: 'GroupEditController' - } - }, - resolve: { - groupData: ['$stateParams', 'GroupsService', function($stateParams, GroupsService) { - return GroupsService.get({ id: $stateParams.group_id }).then(response => response.data.results[0]); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/main.js deleted file mode 100644 index 0c52e2d6b974..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './groups-edit.controller'; - -export default -angular.module('groupEdit', []) - .controller('GroupEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js deleted file mode 100644 index 43ddedb58494..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js +++ /dev/null @@ -1,33 +0,0 @@ -export default - ['i18n', function(i18n) { - return function(params) { - var active_failures = params.active_failures, - total_hosts = params.total_hosts, - tip, failures, html_class; - - // Return values for use on host status indicator - - if (active_failures > 0) { - tip = total_hosts + ((total_hosts === 1) ? ' host' : ' hosts') + '. ' + active_failures + i18n._(' with failed jobs.'); - html_class = 'error'; - failures = true; - } else { - failures = false; - if (total_hosts === 0) { - // no hosts - tip = i18n._("Contains 0 hosts."); - html_class = 'none'; - } else { - // many hosts with 0 failures - tip = total_hosts + ((total_hosts === 1) ? ' host' : ' hosts') + '. ' + i18n._('No job failures'); - html_class = 'success'; - } - } - - return { - tooltip: tip, - failures: failures, - 'class': html_class - }; - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js deleted file mode 100644 index 1e4c05574198..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js +++ /dev/null @@ -1,104 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Groups - * @description This form is for adding/editing a Group on the inventory page -*/ - -export default ['i18n', -function(i18n){ - return { - addTitle: i18n._('CREATE GROUP'), - editTitle: '{{ name }}', - showTitle: true, - name: 'group', - basePath: 'groups', - parent: 'inventories.edit.groups', - // the parent node this generated state definition tree expects to attach to - stateTree: 'inventories', - // form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab - // this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit - activeEditState: 'inventories.edit.groups.edit', - detailsClick: "$state.go('inventories.edit.groups.edit')", - well: false, - tabs: true, - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - tab: 'properties' - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', - tab: 'properties' - }, - group_variables: { - realName: 'variables', - label: i18n._('Variables'), - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - dataTitle: i18n._('Group Variables'), - dataPlacement: 'right', - parseTypeName: 'parseType', - awPopOver: "

Variables defined here apply to all child groups and hosts.

" + - "

Enter variables using either JSON or YAML syntax. Use the " + - "radio button to toggle between the two.

" + - "JSON:
\n" + - "
{
  \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

View JSON examples at www.json.org

' + - '

View YAML examples at docs.ansible.com

', - dataContainer: 'body', - tab: 'properties' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - related: { - nested_groups: { - name: 'nested_groups', - awToolTip: i18n._('Please save before defining groups.'), - dataPlacement: 'top', - ngClick: "$state.go('inventories.edit.groups.edit.nested_groups')", - title: i18n._('Groups'), - iterator: 'nested_group' - }, - nested_hosts: { - name: 'nested_hosts', - awToolTip: i18n._('Please save before defining hosts.'), - dataPlacement: 'top', - ngClick: "$state.go('inventories.edit.groups.edit.nested_hosts')", - include: "NestedHostsListDefinition", - title: i18n._('Hosts'), - iterator: 'nested_hosts' - }, - - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js deleted file mode 100644 index 971ff36c97cb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'groups', - iterator: 'group', - editTitle: '{{ inventory.name }}', - well: true, - wellOverride: true, - index: false, - hover: true, - multiSelect: true, - trackBy: 'group.id', - basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/groups/', - - fields: { - failed_hosts: { - label: '', - nosort: true, - mode: 'all', - iconOnly: true, - awToolTip: "{{ group.hosts_status_tip }}", - dataPlacement: "top", - icon: "{{ 'fa icon-job-' + group.hosts_status_class }}", - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - label: i18n._('Groups'), - key: true, - uiSref: "inventories.edit.groups.edit({group_id:group.id})", - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6', - class: 'InventoryManage-breakWord', - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - launch: { - mode: 'all', - ngDisabled: '!groupsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: i18n._("Select an inventory source by clicking the check box beside it. The inventory source can be a single group or a selection of multiple groups."), - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('RUN COMMANDS'), - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - ngShow: 'canAdhoc' - // TODO: set up a tip watcher and change text based on when - // things are selected/not selected. This is started and - // commented out in the inventory controller within the watchers. - // awToolTip: "{{ adhocButtonTipContents }}", - // dataTipWatch: "adhocButtonTipContents" - }, - create: { - mode: 'all', - ngClick: "createGroup()", - awToolTip: i18n._("Create a new group"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', - - edit: { - //label: 'Edit', - mode: 'all', - ngClick: "editGroup(group.id)", - awToolTip: i18n._('Edit group'), - dataPlacement: "top", - ngShow: "group.summary_fields.user_capabilities.edit" - }, - view: { - //label: 'Edit', - mode: 'all', - ngClick: "editGroup(group.id)", - awToolTip: i18n._('View group'), - dataPlacement: "top", - ngShow: "!group.summary_fields.user_capabilities.edit" - }, - "delete": { - //label: 'Delete', - mode: 'all', - ngClick: "deleteGroup(group)", - awToolTip: i18n._('Delete group'), - dataPlacement: "top", - ngShow: "group.summary_fields.user_capabilities.delete" - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js deleted file mode 100644 index 120d09567b05..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js +++ /dev/null @@ -1,205 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'GroupList', 'InventoryUpdate', - 'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', - 'InventoryHostsStrings', '$transitions', - function($scope, $rootScope, $state, $stateParams, GroupList, InventoryUpdate, - GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd, - InventoryHostsStrings, $transitions){ - - let list = GroupList; - - init(); - - function init(){ - $scope.inventory_id = $stateParams.inventory_id; - $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = canAdd; - - $scope.strings = { - deleteModal: {} - }; - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - if($state.current.name === "inventories.edit.groups") { - $scope.rowBeingEdited = $state.params.group_id; - $scope.listBeingEdited = "groups"; - } - - $scope.inventory_id = $stateParams.inventory_id; - - $scope.$watchCollection(list.name, function(){ - _.forEach($scope[list.name], processRow); - }); - - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - if(!$scope.groupsSelected) { - $scope.groupsSelected = []; - } - $scope.groupsSelected.push(item); - } else { - _.remove($scope.groupsSelected, { id: item.id }); - if($scope.groupsSelected.length === 0) { - $scope.groupsSelected = null; - } - } - }); - - } - - function processRow(group){ - if (group === undefined || group === null) { - group = {}; - } - - angular.forEach($scope.groupsSelected, function(selectedGroup){ - if(selectedGroup.id === group.id) { - group.isSelected = true; - } - }); - - let hosts_status; - - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory_id, - group_id: group.id - }); - _.assign(group, - {hosts_status_tip: hosts_status.tooltip}, - {hosts_status_class: hosts_status.class}); - } - - $scope.createGroup = function(){ - $state.go('inventories.edit.groups.add'); - }; - $scope.editGroup = function(id){ - $state.go('inventories.edit.groups.edit', {group_id: id}); - }; - $scope.goToGroupGroups = function(id){ - $state.go('inventories.edit.groups.edit.nested_groups', {group_id: id}); - }; - $scope.deleteGroup = function(group){ - $scope.toDelete = {}; - $scope.strings.deleteModal = {}; - angular.extend($scope.toDelete, group); - if($scope.toDelete.total_groups === 0 && $scope.toDelete.total_hosts === 0) { - // This group doesn't have any child groups or hosts - the user is just trying to delete - // the group - $scope.deleteOption = "delete"; - } - else { - $scope.strings.deleteModal.group = InventoryHostsStrings.get('deletegroup.GROUP', $scope.toDelete.total_groups); - $scope.strings.deleteModal.host = InventoryHostsStrings.get('deletegroup.HOST', $scope.toDelete.total_hosts); - - if($scope.toDelete.total_groups === 0 || $scope.toDelete.total_hosts === 0) { - if($scope.toDelete.total_groups === 0) { - $scope.strings.deleteModal.deleteGroupsHosts = InventoryHostsStrings.get('deletegroup.DELETE_HOST', $scope.toDelete.total_hosts); - $scope.strings.deleteModal.promoteGroupsHosts = InventoryHostsStrings.get('deletegroup.PROMOTE_HOST', $scope.toDelete.total_hosts); - } - else if($scope.toDelete.total_hosts === 0) { - $scope.strings.deleteModal.deleteGroupsHosts = InventoryHostsStrings.get('deletegroup.DELETE_GROUP', $scope.toDelete.total_groups); - $scope.strings.deleteModal.promoteGroupsHosts = InventoryHostsStrings.get('deletegroup.PROMOTE_GROUP', $scope.toDelete.total_groups); - } - } - else { - $scope.strings.deleteModal.deleteGroupsHosts = InventoryHostsStrings.get('deletegroup.DELETE_GROUPS_AND_HOSTS', {groups: $scope.toDelete.total_groups, hosts: $scope.toDelete.total_hosts}); - $scope.strings.deleteModal.promoteGroupsHosts = InventoryHostsStrings.get('deletegroup.PROMOTE_GROUPS_AND_HOSTS', {groups: $scope.toDelete.total_groups, hosts: $scope.toDelete.total_hosts}); - } - } - - $('#group-delete-modal').modal('show'); - }; - $scope.confirmDelete = function(){ - let reloadListStateParams = null; - - if($scope.groups.length === 1 && $state.params.group_search && !_.isEmpty($state.params.group_search.page) && $state.params.group_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.group_search.page = (parseInt(reloadListStateParams.group_search.page)-1).toString(); - } - - switch($scope.deleteOption){ - case 'promote': - GroupsService.promote($scope.toDelete.id, $stateParams.inventory_id) - .then(() => { - if (parseInt($state.params.group_id) === $scope.toDelete.id) { - $state.go("^", reloadListStateParams, {reload: true}); - } else { - $state.go($state.current, reloadListStateParams, {reload: true}); - } - setTimeout(function(){ - $('#group-delete-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }, 1000); - }); - break; - default: - GroupsService.delete($scope.toDelete.id).then(() => { - if (parseInt($state.params.group_id) === $scope.toDelete.id) { - $state.go("^", reloadListStateParams, {reload: true}); - } else { - $state.go($state.current, reloadListStateParams, {reload: true}); - } - setTimeout(function(){ - $('#group-delete-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }, 1000); - }); - } - }; - $scope.updateGroup = function(group) { - GroupsService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({ - scope: $scope, - group_id: group.id, - url: res.data.results[0].related.update, - group_name: group.name, - group_source: res.data.results[0].source - })); - }; - - $scope.cancelUpdate = function (id) { - CancelSourceUpdate({ scope: $scope, id: id }); - }; - - var cleanUpStateChangeListener = $transitions.onSuccess({}, function(trans) { - if (trans.to().name === "inventories.edit.groups.edit") { - $scope.rowBeingEdited = trans.params('to').group_id; - $scope.listBeingEdited = "groups"; - } - else { - delete $scope.rowBeingEdited; - delete $scope.listBeingEdited; - } - }); - - // Remove the listener when the scope is destroyed to avoid a memory leak - $scope.$on('$destroy', function() { - cleanUpStateChangeListener(); - }); - - $scope.setAdhocPattern = function(){ - var pattern = _($scope.groupsSelected) - .map(function(item){ - return item.name; - }).value().join(':'); - - $state.go('inventories.edit.adhoc', {pattern: pattern}); - }; - - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html deleted file mode 100644 index 23579b228595..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html +++ /dev/null @@ -1,57 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js deleted file mode 100644 index 39dac7cca98c..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js +++ /dev/null @@ -1,72 +0,0 @@ -import { N_ } from '../../../../../i18n'; -import {templateUrl} from '../../../../../shared/template-url/template-url.factory'; - -export default { - name: "inventories.edit.groups", - url: "/groups?{group_search:queryset}", - resolve: { - Dataset: ['GroupList', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - }, - params: { - group_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: "" - } - }, - ncyBreadcrumb: { - parent: "inventories.edit", - label: N_("GROUPS") - }, - views: { - 'related': { - templateProvider: function(GroupList, generateList, $templateRequest, $stateParams, GetBasePath) { - let list = _.cloneDeep(GroupList); - if($stateParams && $stateParams.group) { - list.basePath = GetBasePath('groups') + _.last($stateParams.group) + '/children'; - } - else { - //reaches here if the user is on the root level group - list.basePath = GetBasePath('inventory') + $stateParams.inventory_id + '/root_groups'; - } - - let html = generateList.build({ - list: list, - mode: 'edit' - }); - // Include the custom group delete modal template - return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/list/groups-list')).then((template) => { - return html.concat(template); - }); - }, - controller: 'GroupsListController' - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/main.js deleted file mode 100644 index 6c030c986904..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './groups-list.controller'; - -export default - angular.module('groupsList', []) - .controller('GroupsListController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/main.js deleted file mode 100644 index 4edf6ada5d7c..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/main.js +++ /dev/null @@ -1,26 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import groupList from './list/main'; -import groupAdd from './add/main'; -import groupEdit from './edit/main'; -import groupFormDefinition from './groups.form'; -import groupListDefinition from './groups.list'; -import GetHostsStatusMsg from './factories/get-hosts-status-msg.factory'; -import nestedGroups from './related/nested-groups/main'; -import nestedHosts from './related/nested-hosts/main'; - -export default - angular.module('group', [ - groupList.name, - groupAdd.name, - groupEdit.name, - nestedGroups.name, - nestedHosts.name - ]) - .factory('GroupForm', groupFormDefinition) - .factory('GroupList', groupListDefinition) - .factory('GetHostsStatusMsg', GetHostsStatusMsg); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.controller.js deleted file mode 100644 index 25633199bd0f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.controller.js +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'NestedGroupForm', - 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService', - 'GetChoices', 'GetBasePath', 'CreateSelect2', - 'rbacUiControlService', 'ToJSON', 'canAdd', - function($state, $stateParams, $scope, NestedGroupForm, ParseTypeChange, - GenerateForm, inventoryData, GroupsService, GetChoices, - GetBasePath, CreateSelect2, rbacUiControlService, - ToJSON, canAdd) { - - let form = NestedGroupForm; - init(); - - function init() { - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - $scope.canAdd = canAdd; - $scope.parseType = 'yaml'; - $scope.envParseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - field_id: 'nested_group_nested_group_variables', - variable: 'nested_group_variables', - }); - } - - $scope.formCancel = function() { - $state.go('^'); - }; - - $scope.formSave = function() { - var json_data; - json_data = ToJSON($scope.parseType, $scope.nested_group_variables, true); - - var group = { - variables: json_data, - name: $scope.name, - description: $scope.description, - inventory: inventoryData.id - }; - - GroupsService.post(group).then(res => { - if ($stateParams.group_id && _.has(res, 'data')) { - return GroupsService.associateGroup(res.data, $stateParams.group_id) - .then(() => $state.go('^', null, { reload: true })); - } else if(_.has(res, 'data.id')){ - $state.go('^.edit', { group_id: res.data.id }, { reload: true }); - } - }); - - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js deleted file mode 100644 index 2aba06a2904c..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js +++ /dev/null @@ -1,33 +0,0 @@ -import { N_ } from '../../../../../../i18n'; - -export default { - name: "inventories.edit.groups.edit.nested_groups.add", - url: "/add", - ncyBreadcrumb: { - parent: "inventories.edit.groups.edit.nested_groups", - label: N_("CREATE GROUP") - }, - views: { - 'nestedGroupForm@inventories': { - templateProvider: function(GenerateForm, NestedGroupForm) { - let form = NestedGroupForm; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: 'NestedGroupsAddController' - } - }, - resolve: { - canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js deleted file mode 100644 index 6f8f86e860cc..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - name: 'inventories.edit.groups.edit.nested_groups.associate', - squashSearchUrl: true, - url: '/associate', - ncyBreadcrumb:{ - skip:true - }, - views: { - 'modal@inventories.edit.groups.edit': { - templateProvider: function() { - return ``; - }, - controller: function($scope, $q, GroupsService, $state){ - $scope.associateGroups = function(selectedItems){ - var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateGroup({id: selectedItem.id}, $state.params.group_id)) ) - .then( () =>{ - deferred.resolve(); - }, (error) => { - deferred.reject(error); - }); - }; - } - } - }, - onExit: function($state) { - if ($state.transition) { - $('#associate-groups-modal').modal('hide'); - $('body').removeClass('modal-open'); - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html deleted file mode 100644 index 4b1db398831e..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html +++ /dev/null @@ -1,35 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js deleted file mode 100644 index 88d8eb04ed25..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js +++ /dev/null @@ -1,162 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'NestedGroupListDefinition', 'InventoryUpdate', - 'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', 'groupData', 'ProcessErrors', - '$transitions', - function($scope, $rootScope, $state, $stateParams, NestedGroupListDefinition, InventoryUpdate, - GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd, groupData, ProcessErrors, - $transitions){ - - let list = NestedGroupListDefinition; - - init(); - - function init(){ - $scope.inventory_id = $stateParams.inventory_id; - $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = canAdd; - $scope.disassociateFrom = groupData; - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - if($state.current.name === "inventories.edit.groups.edit.nested_groups.edit") { - $scope.rowBeingEdited = $state.params.group_id; - $scope.listBeingEdited = "groups"; - } - - $scope.inventory_id = $stateParams.inventory_id; - - $scope.$watchCollection(list.name, function(){ - _.forEach($scope[list.name], processRow); - }); - - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - if(!$scope.groupsSelected) { - $scope.groupsSelected = []; - } - $scope.groupsSelected.push(item); - } else { - _.remove($scope.groupsSelected, { id: item.id }); - if($scope.groupsSelected.length === 0) { - $scope.groupsSelected = null; - } - } - }); - - } - - function processRow(group){ - if (group === undefined || group === null) { - group = {}; - } - - angular.forEach($scope.groupsSelected, function(selectedGroup){ - if(selectedGroup.id === group.id) { - group.isSelected = true; - } - }); - - let hosts_status; - - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory_id, - group_id: group.id - }); - _.assign(group, - {hosts_status_tip: hosts_status.tooltip}, - {hosts_status_class: hosts_status.class}); - } - - $scope.disassociateGroup = function(group){ - $scope.toDisassociate = {}; - angular.extend($scope.toDisassociate, group); - $('#group-disassociate-modal').modal('show'); - }; - - $scope.confirmDisassociate = function(){ - - // Bind an even listener for the modal closing. Trying to $state.go() before the modal closes - // will mean that these two things are running async and the modal may not finish closing before - // the state finishes transitioning. - $('#group-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () { - // Remove the event handler so that we don't end up with multiple bindings - $('#group-disassociate-modal').off('hidden.bs.modal'); - - let reloadListStateParams = null; - - if($scope.nested_groups.length === 1 && $state.params.nested_group_search && !_.isEmpty($state.params.nested_group_search.page) && $state.params.nested_group_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.nested_group_search.page = (parseInt(reloadListStateParams.nested_group_search.page)-1).toString(); - } - - // Reload the inventory manage page and show that the group has been removed - $state.go('.', reloadListStateParams, {reload: true}); - }); - - let closeModal = function(){ - $('#group-disassociate-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }; - - GroupsService.disassociateGroup($scope.toDisassociate.id, $scope.disassociateFrom.id) - .then(() => { - closeModal(); - }).catch((error) => { - closeModal(); - ProcessErrors(null, error.data, error.status, null, { - hdr: 'Error!', - msg: 'Failed to disassociate group from parent group: POST returned status' + - error.status - }); - }); - }; - - $scope.editGroup = function(id){ - $state.go('inventories.edit.groups.edit', {group_id: id}); - }; - - $scope.goToGroupGroups = function(id){ - $state.go('inventories.edit.groups.edit.nested_groups', {group_id: id}); - }; - - var cleanUpStateChangeListener = $transitions.onSuccess({}, function(trans) { - if (trans.to().name === "inventories.edit.groups.edit.nested_groups.edit") { - $scope.rowBeingEdited = trans.params('to').group_id; - $scope.listBeingEdited = "groups"; - } - else { - delete $scope.rowBeingEdited; - delete $scope.listBeingEdited; - } - }); - - // Remove the listener when the scope is destroyed to avoid a memory leak - $scope.$on('$destroy', function() { - cleanUpStateChangeListener(); - }); - - $scope.setAdhocPattern = function(){ - var pattern = _($scope.groupsSelected) - .map(function(item){ - return item.name; - }).value().join(':'); - - $state.go('inventories.edit.adhoc', {pattern: pattern}); - }; - - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js deleted file mode 100644 index adc2cab8aba0..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js +++ /dev/null @@ -1,94 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Groups - * @description This form is for adding/editing a Group on the inventory page -*/ - -export default ['i18n', -function(i18n){ - return { - addTitle: i18n._('CREATE GROUP'), - editTitle: '{{ name }}', - showTitle: true, - name: 'nested_group', - iterator: "nested_group", - basePath: 'groups', - parent: 'inventories.edit.groups.edit.nested_groups', - // the parent node this generated state definition tree expects to attach to - stateTree: 'inventories', - // form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab - // this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit - activeEditState: 'inventories.edit.groups.edit.nested_groups.edit', - detailsClick: "$state.go('inventories.edit.groups.edit.nested_groups.edit')", - well: false, - tabs: true, - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - tab: 'properties' - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', - tab: 'properties' - }, - nested_group_variables: { - realName: 'variables', - label: i18n._('Variables'), - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - dataTitle: i18n._('Group Variables'), - dataPlacement: 'right', - parseTypeName: 'parseType', - awPopOver: "

Variables defined here apply to all child groups and hosts.

" + - "

Enter variables using either JSON or YAML syntax. Use the " + - "radio button to toggle between the two.

" + - "JSON:
\n" + - "
{
  \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

View JSON examples at www.json.org

' + - '

View YAML examples at docs.ansible.com

', - dataContainer: 'body', - tab: 'properties' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - related: { - nested_groups: { - name: 'related_groups', - ngClick: "$state.go('inventories.edit.groups.edit.related_groups')", - title: i18n._('Groups'), - iterator: 'related_group' - }, - - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js deleted file mode 100644 index 38730de2700e..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js +++ /dev/null @@ -1,117 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'nested_groups', - iterator: 'nested_group', - editTitle: '{{ inventory.name }}', - well: true, - wellOverride: true, - index: false, - hover: true, - multiSelect: true, - trackBy: 'nested_group.id', - basePath: 'api/v2/groups/{{$stateParams.group_id}}/children/', - - fields: { - failed_hosts: { - label: '', - nosort: true, - mode: 'all', - iconOnly: true, - awToolTip: "{{ nested_group.hosts_status_tip }}", - dataPlacement: "top", - icon: "{{ 'fa icon-job-' + nested_group.hosts_status_class }}", - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - label: i18n._('Groups'), - key: true, - uiSref: "inventories.edit.groups.edit({group_id:nested_group.id})", - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6', - class: 'InventoryManage-breakWord', - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - launch: { - mode: 'all', - ngDisabled: '!groupsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: i18n._("Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups."), - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('RUN COMMANDS'), - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - ngShow: 'canAdhoc' - // TODO: set up a tip watcher and change text based on when - // things are selected/not selected. This is started and - // commented out in the inventory controller within the watchers. - // awToolTip: "{{ adhocButtonTipContents }}", - // dataTipWatch: "adhocButtonTipContents" - }, - add: { - mode: 'all', - type: 'buttonDropdown', - awToolTip: i18n._("Add a group"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - options: [ - { - optionContent: i18n._('Existing Group'), - optionSref: '.associate', - ngShow: 'canAdd' - }, - { - optionContent: i18n._('New Group'), - optionSref: '.add', - ngShow: 'canAdd' - } - ], - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', - - edit: { - mode: 'all', - ngClick: "editGroup(nested_group.id)", - awToolTip: i18n._('Edit group'), - dataPlacement: "top", - ngShow: "nested_group.summary_fields.user_capabilities.edit" - }, - view: { - mode: 'all', - ngClick: "editGroup(nested_group.id)", - awToolTip: i18n._('View group'), - dataPlacement: "top", - ngShow: "!nested_group.summary_fields.user_capabilities.edit" - }, - "delete": { - mode: 'all', - ngClick: "disassociateGroup(nested_group)", - awToolTip: i18n._('Disassociate group'), - iconClass: 'fa fa-times', - dataPlacement: "top", - ngShow: "nested_group.summary_fields.user_capabilities.delete" - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js deleted file mode 100644 index 66495716aca7..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js +++ /dev/null @@ -1,80 +0,0 @@ -import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; -import { N_ } from '../../../../../../i18n'; - -export default { - name: 'inventories.edit.groups.edit.nested_groups', - url: "/nested_groups?{nested_group_search:queryset}", - params: { - nested_group_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: "" - } - }, - ncyBreadcrumb: { - parent: "inventories.edit.groups.edit", - label: N_("ASSOCIATED GROUPS") - }, - views: { - // 'related@inventories.edit.groups.edit': { - 'related': { - templateProvider: function(NestedGroupListDefinition, generateList, $templateRequest) { - let list = _.cloneDeep(NestedGroupListDefinition); - - let html = generateList.build({ - list: list, - mode: 'edit' - }); - - return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate')).then((template) => { - return html.concat(template); - }); - }, - controller: 'NestedGroupsListController' - } - }, - resolve: { - Dataset: ['NestedGroupListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - if($stateParams.group_id){ - path = GetBasePath('groups') + $stateParams.group_id + '/children'; - } - else if($stateParams.host_id){ - path = GetBasePath('hosts') + $stateParams.host_id + '/all_groups'; - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - host: ['$stateParams', 'HostsService', function($stateParams, HostsService) { - if($stateParams.host_id){ - return HostsService.get({ id: $stateParams.host_id }).then(function(res) { - return res.data.results[0]; - }); - } - }], - inventoryData: ['InventoriesService', '$stateParams', 'host', function(InventoriesService, $stateParams, host) { - var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id; - return InventoriesService.getInventory(id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/main.js deleted file mode 100644 index 445854d12095..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/main.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import nestedGroupListDefinition from './group-nested-groups.list'; -import controller from './group-nested-groups-list.controller'; -import addController from './group-nested-groups-add.controller'; -import NestedGroupForm from './group-nested-groups.form'; - -export default - angular.module('nestedGroups', []) - .factory('NestedGroupForm', NestedGroupForm) - .factory('NestedGroupListDefinition', nestedGroupListDefinition) - .controller('NestedGroupsListController', controller) - .controller('NestedGroupsAddController', addController); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.controller.js deleted file mode 100644 index 4cb3e840bb4a..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.controller.js +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition', 'ParseTypeChange', - 'GenerateForm', 'HostsService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd', 'GroupsService', - function($state, $stateParams, $scope, RelatedHostsFormDefinition, ParseTypeChange, - GenerateForm, HostsService, rbacUiControlService, GetBasePath, ToJSON, canAdd, GroupsService) { - - init(); - - function init() { - $scope.canAdd = canAdd; - $scope.parseType = 'yaml'; - $scope.host = { enabled: true }; - // apply form definition's default field values - GenerateForm.applyDefaults(RelatedHostsFormDefinition, $scope); - - ParseTypeChange({ - scope: $scope, - field_id: 'host_host_variables', - variable: 'host_variables', - parse_variable: 'parseType' - }); - } - $scope.formCancel = function() { - $state.go('^'); - }; - $scope.toggleHostEnabled = function() { - if ($scope.host.has_inventory_sources){ - return; - } - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.formSave = function(){ - var json_data = ToJSON($scope.parseType, $scope.host_variables, true), - params = { - variables: json_data,// $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables, - name: $scope.name, - description: $scope.description, - enabled: $scope.host.enabled, - inventory: $stateParams.inventory_id - }; - HostsService.post(params).then(function(res) { - return GroupsService.associateHost(res.data, $stateParams.group_id) - .then(() => $state.go('^', null, { reload: true })); - }); - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js deleted file mode 100644 index 438aa4a5f2d5..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js +++ /dev/null @@ -1,33 +0,0 @@ -import { N_ } from '../../../../../../i18n'; - -export default { - name: "inventories.edit.groups.edit.nested_hosts.add", - url: "/add", - ncyBreadcrumb: { - parent: "inventories.edit.groups.edit.nested_hosts", - label: N_("CREATE HOST") - }, - views: { - 'hostForm@inventories': { - templateProvider: function(GenerateForm, RelatedHostsFormDefinition, NestedHostsFormDefinition, $stateParams) { - let form = ($stateParams.group_id) ? NestedHostsFormDefinition : RelatedHostsFormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: 'NestedHostsAddController' - } - }, - resolve: { - canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/hosts") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js deleted file mode 100644 index 1d1ad65388b6..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - name: 'inventories.edit.groups.edit.nested_hosts.associate', - squashSearchUrl: true, - url: '/associate', - ncyBreadcrumb:{ - skip:true - }, - views: { - 'modal@inventories.edit.groups.edit': { - templateProvider: function() { - return ``; - }, - controller: function($scope, $q, GroupsService, $state){ - $scope.associateHosts = function(selectedItems){ - var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: selectedItem.id}, $state.params.group_id)) ) - .then( () =>{ - deferred.resolve(); - }, (error) => { - deferred.reject(error); - }); - }; - } - } - }, - onExit: function($state) { - if ($state.transition) { - $('#associate-groups-modal').modal('hide'); - $('body').removeClass('modal-open'); - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html deleted file mode 100644 index cf22da701eb6..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html +++ /dev/null @@ -1,35 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-list.controller.js deleted file mode 100644 index a288cb05c65f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-list.controller.js +++ /dev/null @@ -1,180 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePath', - 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostsService', 'SetStatus', 'canAdd', 'GroupsService', 'ProcessErrors', 'groupData', 'inventoryData', 'InventoryHostsStrings', - '$transitions', - function($scope, NestedHostsListDefinition, $rootScope, GetBasePath, - rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostsService, SetStatus, canAdd, GroupsService, ProcessErrors, groupData, inventoryData, InventoryHostsStrings, - $transitions) { - - let list = NestedHostsListDefinition; - - init(); - - function init(){ - $scope.canAdd = canAdd; - $scope.enableSmartInventoryButton = false; - $scope.disassociateFrom = groupData; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.inventory_obj = inventoryData; - - $rootScope.flashMessage = null; - - $scope.$watchCollection(list.name, function() { - $scope[list.name] = _.map($scope.nested_hosts, function(value) { - angular.forEach(value.summary_fields.groups.results, function(directParentGroup) { - if(directParentGroup.id === parseInt($state.params.group_id)) { - value.can_disassociate = true; - } - }); - angular.forEach($scope.hostsSelected, function(selectedHost){ - if(selectedHost.id === value.id) { - value.isSelected = true; - } - }); - return value; - }); - setJobStatus(); - }); - - $transitions.onSuccess({}, function(trans) { - if(trans.params('to') && trans.params('to').host_search) { - let hasMoreThanDefaultKeys = false; - angular.forEach(trans.params('to').host_search, function(value, key) { - if(key !== 'order_by' && key !== 'page_size' && key !== 'page') { - hasMoreThanDefaultKeys = true; - } - }); - $scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false; - $scope.smartInventoryButtonTooltip = hasMoreThanDefaultKeys ? InventoryHostsStrings.get('smartinventorybutton.ENABLED_INSTRUCTIONS') : InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - else { - $scope.enableSmartInventoryButton = false; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - }); - - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - if(!$scope.hostsSelected) { - $scope.hostsSelected = []; - } - $scope.hostsSelected.push(item); - } else { - _.remove($scope.hostsSelected, { id: item.id }); - if($scope.hostsSelected.length === 0) { - $scope.hostsSelected = null; - } - } - - $scope.systemTrackingDisabled = ($scope.hostsSelected && $scope.hostsSelected.length > 2) ? true : false; - }); - - } - - function setJobStatus(){ - _.forEach($scope.nested_hosts, function(value) { - SetStatus({ - scope: $scope, - host: value - }); - }); - } - - $scope.associateHost = function(){ - $state.go('inventories.edit.groups.edit.nested_hosts.associate'); - }; - $scope.editHost = function(id){ - $state.go('inventories.edit.hosts.edit', {host_id: id}); - }; - $scope.disassociateHost = function(host){ - $scope.toDisassociate = {}; - angular.extend($scope.toDisassociate, host); - $('#host-disassociate-modal').modal('show'); - }; - - $scope.confirmDisassociate = function(){ - - // Bind an even listener for the modal closing. Trying to $state.go() before the modal closes - // will mean that these two things are running async and the modal may not finish closing before - // the state finishes transitioning. - $('#host-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () { - // Remove the event handler so that we don't end up with multiple bindings - $('#host-disassociate-modal').off('hidden.bs.modal'); - - let reloadListStateParams = null; - - if($scope.nested_hosts.length === 1 && $state.params.nested_host_search && !_.isEmpty($state.params.nested_host_search.page) && $state.params.nested_host_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.nested_host_search.page = (parseInt(reloadListStateParams.nested_host_search.page)-1).toString(); - } - - // Reload the inventory manage page and show that the group has been removed - $state.go('.', reloadListStateParams, {reload: true}); - }); - - let closeModal = function(){ - $('#host-disassociate-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }; - - GroupsService.disassociateHost($scope.toDisassociate.id, $scope.disassociateFrom.id) - .then(() => { - closeModal(); - }).catch((error) => { - closeModal(); - ProcessErrors(null, error.data, error.status, null, { - hdr: 'Error!', - msg: 'Failed to disassociate host from group: POST returned status' + - error.status - }); - }); - }; - - $scope.toggleHost = function(event, host) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - - host.enabled = !host.enabled; - - HostsService.put(host).then(function(){ - $state.go($state.current, null, {reload: true}); - }); - }; - - $scope.systemTracking = function(){ - var hostIds = _.map($scope.hostsSelected, (host) => host.id); - $state.go('systemTracking', { - inventoryId: $state.params.inventory_id, - hosts: $scope.hostsSelected, - hostIds: hostIds - }); - }; - - $scope.setAdhocPattern = function(){ - var pattern = _($scope.hostsSelected) - .map(function(item){ - return item.name; - }).value().join(':'); - - $state.go('inventories.edit.adhoc', {pattern: pattern}); - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js deleted file mode 100644 index df84c40e335d..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js +++ /dev/null @@ -1,119 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Hosts - * @description This form is for adding/editing a host on the inventory page -*/ - -export default ['i18n', -function(i18n) { - return { - - addTitle: i18n._('CREATE HOST'), - editTitle: '{{ host.name }}', - name: 'host', - basePath: 'hosts', - well: false, - formLabelSize: 'col-lg-3', - formFieldSize: 'col-lg-9', - iterator: 'host', - activeEditState: 'inventories.edit.groups.edit.nested_hosts.edit', - stateTree: 'inventories.edit.groups.edit.nested_hosts', - headerFields:{ - enabled: { - class: 'Form-header-field', - ngClick: 'toggleHostEnabled(host)', - type: 'toggle', - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataTitle: i18n._('Host Enabled'), - ngDisabled: 'host.has_inventory_sources' - } - }, - fields: { - name: { - label: i18n._('Host Name'), - type: 'text', - required: true, - awPopOver: "

" + - i18n._("Provide a host name, ip address, or ip address:port. Examples include:") + - "

" + - "
myserver.domain.com
" + - "127.0.0.1
" + - "10.1.0.140:25
" + - "server.example.com:25" + - "
", - dataTitle: i18n._('Host Name'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)' - }, - description: { - label: i18n._('Description'), - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)', - type: 'text' - }, - host_variables: { - label: i18n._('Variables'), - type: 'textarea', - rows: 6, - class: 'Form-formGroup--fullWidth', - "default": "---", - awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Host Variables'), - dataPlacement: 'right', - dataContainer: 'body' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - ansible_facts: { - name: 'ansible_facts', - awToolTip: i18n._('Please save before viewing facts.'), - dataPlacement: 'top', - title: i18n._('Facts'), - skipGenerator: true - }, - nested_groups: { - name: 'nested_groups', - awToolTip: i18n._('Please save before defining groups.'), - dataPlacement: 'top', - ngClick: "$state.go('inventories.edit.groups.edit.nested_hosts.edit.nested_groups')", - title: i18n._('Groups'), - iterator: 'nested_group' - } - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js deleted file mode 100644 index a6af0d8c71cb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js +++ /dev/null @@ -1,138 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - name: 'nested_hosts', - iterator: 'nested_host', - editTitle: '{{ nested_host.name }}', // i don't think this is correct - // showTitle: false, - well: true, - wellOverride: true, - index: false, - hover: true, - // hasChildren: true, - multiSelect: true, - trackBy: 'nested_host.id', - basePath: 'api/v2/groups/{{$stateParams.group_id}}/all_hosts/', - - fields: { - toggleHost: { - ngDisabled: '!nested_host.summary_fields.user_capabilities.edit || nested_host.has_inventory_sources', - label: '', - columnClass: 'List-staticColumn--toggle', - type: "toggle", - ngClick: "toggleHost($event, nested_host)", - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataPlacement: "right", - nosort: true, - }, - active_failures: { - label: '', - iconOnly: true, - nosort: true, - // do not remove this ng-click directive - // the list generator case to handle fields without ng-click - // cannot handle the aw-* directives - ngClick: 'noop()', - awPopOver: "{{ nested_host.job_status_html }}", - dataTitle: "{{ nested_host.job_status_title }}", - awToolTip: "{{ nested_host.badgeToolTip }}", - dataPlacement: 'top', - icon: "{{ 'fa icon-job-' + nested_host.active_failures }}", - id: 'active-failures-action', - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - key: true, - label: i18n._('Hosts'), - uiSref: "inventories.edit.hosts.edit({host_id: nested_host.id})", - ngClass: "{ 'host-disabled-label': !nested_host.enabled }", - columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', - dataHostId: "{{ nested_host.id }}", - dataType: "nested_host", - class: 'InventoryManage-breakWord' - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', - edit: { - ngClick: "editHost(nested_host.id)", - icon: 'icon-edit', - awToolTip: i18n._('Edit host'), - dataPlacement: 'top', - ngShow: 'nested_host.summary_fields.user_capabilities.edit' - }, - view: { - ngClick: "editHost(nested_host.id)", - awToolTip: i18n._('View host'), - dataPlacement: 'top', - ngShow: '!nested_host.summary_fields.user_capabilities.edit' - }, - "delete": { - //label: 'Delete', - ngClick: "disassociateHost(nested_host)", - iconClass: 'fa fa-times', - awToolTip: i18n._('Disassociate host'), - dataPlacement: 'top', - ngShow: 'nested_host.summary_fields.user_capabilities.delete' - } - }, - - actions: { - launch: { - mode: 'all', - ngDisabled: '!hostsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: i18n._("Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups."), - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('RUN COMMANDS'), - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - // TODO: we don't always want to show this - ngShow: 'inventory_obj.summary_fields.user_capabilities.adhoc' - }, - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - add: { - mode: 'all', - type: 'buttonDropdown', - awToolTip: i18n._("Add a host"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - options: [ - { - optionContent: i18n._('Existing Host'), - optionSref: '.associate', - ngShow: 'canAdd' - }, - { - optionContent: i18n._('New Host'), - optionSref: '.add', - ngShow: 'canAdd' - } - ], - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js deleted file mode 100644 index 456da422d936..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js +++ /dev/null @@ -1,66 +0,0 @@ -import { N_ } from '../../../../../../i18n'; -import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; - -export default { - name: "inventories.edit.groups.edit.nested_hosts", - url: "/nested_hosts?{nested_host_search:queryset}", - params: { - nested_host_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: "" - } - }, - ncyBreadcrumb: { - parent: "inventories.edit.groups.edit", - label: N_("ASSOCIATED HOSTS") - }, - views: { - // 'related@inventories.edit.groups.edit': { - 'related': { - templateProvider: function(NestedHostsListDefinition, generateList, $templateRequest) { - let list = _.cloneDeep(NestedHostsListDefinition); - - let html = generateList.build({ - list: list, - mode: 'edit' - }); - return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate')).then((template) => { - return html.concat(template); - }); - }, - controller: 'NestedHostsListController' - } - }, - resolve: { - Dataset: ['NestedHostsListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - path = `api/v2/groups/${$stateParams.group_id}/all_hosts`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', function(rbacUiControlService) { - return rbacUiControlService.canAdd('hosts') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/main.js deleted file mode 100644 index 6905795f3d8a..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/main.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import nestedHostsListDefinition from './group-nested-hosts.list'; -import nestedHostsFormDefinition from './group-nested-hosts.form'; -import controller from './group-nested-hosts-list.controller'; -import addController from './group-nested-hosts-add.controller'; - -export default - angular.module('nestedHosts', []) - .factory('NestedHostsListDefinition', nestedHostsListDefinition) - .factory('NestedHostsFormDefinition', nestedHostsFormDefinition) - .controller('NestedHostsAddController', addController) - .controller('NestedHostsListController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.controller.js deleted file mode 100644 index 207bdf4f8f17..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.controller.js +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition', 'ParseTypeChange', - 'GenerateForm', 'HostsService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd', - function($state, $stateParams, $scope, RelatedHostsFormDefinition, ParseTypeChange, - GenerateForm, HostsService, rbacUiControlService, GetBasePath, ToJSON, canAdd) { - - init(); - - function init() { - $scope.canAdd = canAdd; - $scope.parseType = 'yaml'; - $scope.host = { enabled: true }; - // apply form definition's default field values - GenerateForm.applyDefaults(RelatedHostsFormDefinition, $scope); - - ParseTypeChange({ - scope: $scope, - field_id: 'host_host_variables', - variable: 'host_variables', - parse_variable: 'parseType' - }); - } - $scope.formCancel = function() { - $state.go('^'); - }; - $scope.toggleHostEnabled = function() { - if ($scope.host.has_inventory_sources){ - return; - } - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.formSave = function(){ - var json_data = ToJSON($scope.parseType, $scope.host_variables, true), - params = { - variables: json_data,// $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables, - name: $scope.name, - description: $scope.description, - enabled: $scope.host.enabled, - inventory: $stateParams.inventory_id - }; - HostsService.post(params).then(function(res) { - $state.go('^.edit', { host_id: res.data.id }, { reload: true }); - }) - .catch(function(){}); - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js deleted file mode 100644 index 7621eeb045c4..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js +++ /dev/null @@ -1,22 +0,0 @@ -import { N_ } from '../../../../../i18n'; - -export default { - name: "inventories.edit.hosts.add", - url: "/add", - ncyBreadcrumb: { - parent: "inventories.edit.hosts", - label: N_("CREATE HOST") - }, - views: { - 'hostForm@inventories': { - templateProvider: function(GenerateForm, RelatedHostsFormDefinition) { - let form = RelatedHostsFormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: 'RelatedHostAddController' - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/main.js deleted file mode 100644 index 7a55327c9f5b..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './host-add.controller'; - -export default -angular.module('relatedHostsAdd', []) - .controller('RelatedHostAddController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js deleted file mode 100644 index 52661b4129a8..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostsService', 'host', '$rootScope', - function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostsService, host, $rootScope){ - $scope.isSmartInvHost = $state.includes('inventories.editSmartInventory.hosts.edit'); - $scope.parseType = 'yaml'; - $scope.formCancel = function(){ - $state.go('^', null, {reload: true}); - }; - $scope.toggleHostEnabled = function(){ - if ($scope.host.has_inventory_sources){ - return; - } - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.toggleEnabled = function(){ - $scope.host.enabled = !$scope.host.enabled; - }; - $scope.formSave = function(){ - var host = { - id: $scope.host.id, - variables: $scope.host_variables === '---' || $scope.host_variables === '{}' ? null : $scope.host_variables, - name: $scope.name, - description: $scope.description, - enabled: $scope.host.enabled - }; - HostsService.put(host).then(function(){ - $state.go('.', null, {reload: true}); - }); - - }; - var init = function(){ - $scope.host = host; - $scope.name = host.name; - $rootScope.breadcrumb.host_name = host.name; - $scope.description = host.description; - $scope.host_variables = getVars(host.variables); - ParseTypeChange({ - scope: $scope, - field_id: 'host_host_variables', - variable: 'host_variables', - }); - }; - - // Adding this function b/c sometimes extra vars are returned to the - // UI as a string (ex: "foo: bar"), and other times as a - // json-object-string (ex: "{"foo": "bar"}"). CodeMirror wouldn't know - // how to prettify the latter. The latter occurs when host vars were - // system generated and not user-input (such as adding a cloud host); - function getVars(str){ - - // Quick function to test if the host vars are a json-object-string, - // by testing if they can be converted to a JSON object w/o error. - function IsJsonString(str) { - try { - JSON.parse(str); - } catch (e) { - return false; - } - return true; - } - - if(str === ''){ - return '---'; - } - else if(IsJsonString(str)){ - str = JSON.parse(str); - return jsyaml.safeDump(str); - } - else if(!IsJsonString(str)){ - return str; - } - } - - init(); - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/main.js deleted file mode 100644 index 9536f686dc51..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/main.js +++ /dev/null @@ -1,10 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import controller from './host-edit.controller'; - -export default -angular.module('relatedHostEdit', []) - .controller('RelatedHostEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/smart-host-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/smart-host-edit.route.js deleted file mode 100644 index 033e6054cae9..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/smart-host-edit.route.js +++ /dev/null @@ -1,29 +0,0 @@ -export default { - name: "inventories.editSmartInventory.hosts.edit", - url: "/edit/:host_id", - ncyBreadcrumb: { - parent: "inventories.editSmartInventory.hosts", - label: "{{breadcrumb.host_name}}" - }, - views: { - 'hostForm@inventories': { - templateProvider: function(GenerateForm, RelatedHostsFormDefinition) { - let form = _.cloneDeep(RelatedHostsFormDefinition); - form.stateTree = 'inventories.editSmartInventory.hosts'; - delete form.related; - return GenerateForm.buildHTML(form, { - mode: 'edit', - related: false - }); - }, - controller: 'RelatedHostEditController' - } - }, - resolve: { - host: ['$stateParams', 'InventoriesService', function($stateParams, InventoriesService) { - return InventoriesService.getHost($stateParams.smartinventory_id, $stateParams.host_id).then(function(res) { - return res.data.results[0]; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/standard-host-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/standard-host-edit.route.js deleted file mode 100644 index 432037658ff4..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/standard-host-edit.route.js +++ /dev/null @@ -1,25 +0,0 @@ -export default { - name: "inventories.edit.hosts.edit", - url: "/edit/:host_id", - ncyBreadcrumb: { - parent: "inventories.edit.hosts", - label: "{{breadcrumb.host_name}}" - }, - views: { - 'hostForm@inventories': { - templateProvider: function(GenerateForm, RelatedHostsFormDefinition) { - let form = RelatedHostsFormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'edit', - related: false - }); - }, - controller: 'RelatedHostEditController' - } - }, - resolve: { - host: ['$stateParams', 'HostsService', function($stateParams, HostsService) { - return HostsService.get({ id: $stateParams.host_id }).then((response) => response.data.results[0]); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js deleted file mode 100644 index d1f32f366acb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js +++ /dev/null @@ -1,178 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import HostsService from './../hosts/host.service'; -export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath', - 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostsService', 'SetStatus', 'canAdd', 'i18n', 'InventoryHostsStrings', '$transitions', - function($scope, ListDefinition, $rootScope, GetBasePath, - rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostsService, SetStatus, canAdd, i18n, InventoryHostsStrings, $transitions) { - - let list = ListDefinition; - - init(); - - function init(){ - $scope.canAdd = canAdd; - $scope.enableSmartInventoryButton = false; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $rootScope.flashMessage = null; - - $scope.$watchCollection(list.name, function() { - $scope[list.name] = _.map($scope.hosts, function(value) { - value.inventory_name = value.summary_fields.inventory.name; - value.inventory_id = value.summary_fields.inventory.id; - angular.forEach($scope.hostsSelected, function(selectedHost){ - if(selectedHost.id === value.id) { - value.isSelected = true; - } - }); - return value; - }); - setJobStatus(); - }); - - $transitions.onSuccess({}, function(trans) { - if(trans.params('to') && trans.params('to').host_search) { - let hasMoreThanDefaultKeys = false; - angular.forEach(trans.params('to').host_search, function(value, key) { - if(key !== 'order_by' && key !== 'page_size' && key !== 'page') { - hasMoreThanDefaultKeys = true; - } - }); - $scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false; - $scope.smartInventoryButtonTooltip = hasMoreThanDefaultKeys ? InventoryHostsStrings.get('smartinventorybutton.ENABLED_INSTRUCTIONS') : InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - else { - $scope.enableSmartInventoryButton = false; - $scope.smartInventoryButtonTooltip = InventoryHostsStrings.get('smartinventorybutton.DISABLED_INSTRUCTIONS'); - } - }); - - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - if(!$scope.hostsSelected) { - $scope.hostsSelected = []; - } - $scope.hostsSelected.push(item); - } else { - _.remove($scope.hostsSelected, { id: item.id }); - if($scope.hostsSelected.length === 0) { - $scope.hostsSelected = null; - } - } - - $scope.systemTrackingDisabled = ($scope.hostsSelected && $scope.hostsSelected.length > 2) ? true : false; - }); - - } - - function setJobStatus(){ - _.forEach($scope.hosts, function(value) { - SetStatus({ - scope: $scope, - host: value - }); - }); - } - - $scope.createHost = function(){ - $state.go('inventories.edit.hosts.add'); - }; - $scope.editHost = function(host){ - if($state.includes('inventories.edit.hosts')) { - $state.go('inventories.edit.hosts.edit', {host_id: host.id}); - } - else if($state.includes('inventories.editSmartInventory.hosts')) { - $state.go('inventories.editSmartInventory.hosts.edit', {host_id: host.id}); - } - }; - $scope.goToInsights = function(host){ - $state.go('inventories.edit.hosts.edit.insights', {inventory_id: host.inventory_id, host_id:host.id}); - }; - $scope.deleteHost = function(id, name){ - var body = '
' + i18n._('Are you sure you want to permanently delete the host below from the inventory?') + '
' + $filter('sanitize')(name) + '
'; - var action = function(){ - delete $rootScope.promptActionBtnClass; - Wait('start'); - HostsService.delete(id).then(() => { - $('#prompt-modal').modal('hide'); - - let reloadListStateParams = null; - - if($scope.hosts.length === 1 && $state.params.host_search && !_.isEmpty($state.params.host_search.page) && $state.params.host_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.host_search.page = (parseInt(reloadListStateParams.host_search.page)-1).toString(); - } - - if (parseInt($state.params.host_id) === id) { - $state.go('^', reloadListStateParams, {reload: true}); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - Wait('stop'); - }); - }; - // Prompt depends on having $rootScope.promptActionBtnClass available... - Prompt({ - hdr: 'Delete Host', - body: body, - action: action, - actionText: 'DELETE', - }); - $rootScope.promptActionBtnClass = 'Modal-errorButton'; - }; - - $scope.toggleHost = function(event, host) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - - host.enabled = !host.enabled; - - HostsService.put(host).then(function(){ - $state.go($state.current, null, {reload: true}); - }); - }; - - $scope.smartInventory = function() { - $state.go('inventories.addSmartInventory'); - }; - - $scope.systemTracking = function(){ - var hostIds = _.map($scope.hostsSelected, (host) => host.id); - $state.go('systemTracking', { - inventoryId: $state.params.inventory_id ? $state.params.inventory_id : $state.params.smartinventory_id, - hosts: $scope.hostsSelected, - hostIds: hostIds - }); - }; - - $scope.setAdhocPattern = function(){ - var pattern = _($scope.hostsSelected) - .map(function(item){ - return item.name; - }).value().join(':'); - - if($state.includes('inventories.edit')) { - $state.go('inventories.edit.adhoc', {pattern: pattern}); - } - else if($state.includes('inventories.editSmartInventory')) { - $state.go('inventories.editSmartInventory.adhoc', {pattern: pattern}); - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/main.js deleted file mode 100644 index 6cb8d2dda557..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/list/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import RelatedHostListController from './host-list.controller'; - -export default -angular.module('relatedHostList', []) - .controller('RelatedHostListController', RelatedHostListController); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/main.js deleted file mode 100644 index 08b0cdc5b6ea..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/main.js +++ /dev/null @@ -1,24 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import relatedHostAdd from './add/main'; - import relatedHostEdit from './edit/main'; - import relatedHostList from './list/main'; - import relatedHostsListDefinition from './related-host.list'; - import relatedHostsFormDefinition from './related-host.form'; - import relatedGroupsLabels from './related-groups-labels/main'; - import nestedGroups from './related/nested-groups/main'; - -export default -angular.module('relatedHost', [ - relatedHostAdd.name, - relatedHostEdit.name, - relatedHostList.name, - relatedGroupsLabels.name, - nestedGroups.name - ]) - .factory('RelatedHostsFormDefinition', relatedHostsFormDefinition) - .factory('RelatedHostsListDefinition', relatedHostsListDefinition); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/main.js deleted file mode 100644 index a3be739b8aa7..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import relatedGroupsabelsList from './relatedGroupsLabelsList.directive'; - -export default - angular.module('relatedGroupsLabels', []) - .directive('relatedGroupsLabelsList', relatedGroupsabelsList); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.block.less b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.block.less deleted file mode 100644 index 7261b6f7622f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.block.less +++ /dev/null @@ -1,3 +0,0 @@ -.RelatedGroupsLabelsCell{ - width:100%; -} diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js deleted file mode 100644 index d5a7672c63cb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js +++ /dev/null @@ -1,104 +0,0 @@ -/* jshint unused: vars */ -export default - [ 'templateUrl', - 'Wait', - 'Rest', - 'GetBasePath', - 'ProcessErrors', - 'Prompt', - '$q', - '$filter', - '$state', - 'i18n', - function(templateUrl, Wait, Rest, GetBasePath, ProcessErrors, Prompt, $q, $filter, $state, i18n) { - return { - restrict: 'E', - scope: false, - templateUrl: templateUrl('inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList'), - link: function(scope, element, attrs) { - scope.showDelete = attrs.showDelete === 'true'; - scope.seeMoreInactive = true; - - var getNext = function(data, arr, resolve) { - Rest.setUrl(data.next); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, arr.concat(data.results), resolve); - } else { - resolve.resolve(arr.concat(data.results)); - } - }); - }; - - scope.seeMore = function () { - var seeMoreResolve = $q.defer(); - Rest.setUrl(`${scope[scope.$parent.list.iterator].related.groups}?order_by=id`); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, data.results, seeMoreResolve); - } else { - seeMoreResolve.resolve(data.results); - } - }); - - seeMoreResolve.promise.then(function (groups) { - scope.related_groups = groups; - scope.seeMoreInactive = false; - }); - }; - - scope.seeLess = function() { - // Trim the groups array back down to 5 items - scope.related_groups = scope.related_groups.slice(0, 5); - // Re-set the seeMoreInteractive flag so that the "See More" will be displayed - scope.seeMoreInactive = true; - }; - - scope.deleteLabel = function(host, group) { - var action = function () { - $('#prompt-modal').modal('hide'); - scope.seeMoreInactive = true; - Wait('start'); - let url = `${GetBasePath('groups')}${group.id}/hosts`; - if(url) { - Rest.setUrl(url); - Rest.post({"disassociate": true, "id": host.id}) - .then(() => { - Wait('stop'); - $state.go('.', null, {reload: true}); - }) - .catch(({data, status}) => { - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Could not disassociate host from group. Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - } - }; - - Prompt({ - hdr: 'Remove host from ' + group.name , - body: '
' + i18n._('Confirm the removal of the') + ' ' + $filter('sanitize')(host.name) + ' ' + i18n._('from the') + ' ' + $filter('sanitize')(group.name) + ' ' + i18n._('group') + '.
', - action: action, - actionText: 'REMOVE' - }); - }; - - scope.$watchCollection(scope.$parent.list.iterator, function() { - // To keep the array of groups fresh, we need to set up a watcher - otherwise, the - // array will get set initially and then never be updated as groups are removed - if (scope[scope.$parent.list.iterator].summary_fields.groups){ - scope.related_groups = scope[scope.$parent.list.iterator].summary_fields.groups.results; - scope.count = scope[scope.$parent.list.iterator].summary_fields.groups.count; - } - else{ - scope.related_groups = null; - scope.count = null; - } - }); - - } - }; - } - ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html deleted file mode 100644 index 8b40988fdd94..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
- {{ related_group.name }} -
-
- -
-
-
View More
-
View Less
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js deleted file mode 100644 index 2ee6de78a2a8..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Hosts - * @description This form is for adding/editing a host on the inventory page -*/ - -export default ['i18n', -function(i18n) { - return { - - addTitle: i18n._('CREATE HOST'), - editTitle: '{{ host.name }}', - name: 'host', - basePath: 'hosts', - well: false, - formLabelSize: 'col-lg-3', - formFieldSize: 'col-lg-9', - iterator: 'host', - detailsClick: "$state.go('inventories.edit.hosts.edit', null, {reload:true})", - stateTree: 'inventories.edit.hosts', - headerFields:{ - enabled: { - class: 'Form-header-field', - ngClick: 'toggleHostEnabled(host)', - type: 'toggle', - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataTitle: i18n._('Host Enabled'), - ngDisabled: '!host.summary_fields.user_capabilities.edit || host.has_inventory_sources || isSmartInvHost' - } - }, - fields: { - name: { - label: i18n._('Host Name'), - type: 'text', - required: true, - awPopOver: "

" + - i18n._("Provide a host name, ip address, or ip address:port. Examples include:") + - "

" + - "
myserver.domain.com
" + - "127.0.0.1
" + - "10.1.0.140:25
" + - "server.example.com:25" + - "
", - dataTitle: i18n._('Host Name'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd) || isSmartInvHost' - }, - description: { - label: i18n._('Description'), - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd) || isSmartInvHost', - type: 'text' - }, - host_variables: { - label: i18n._('Variables'), - type: 'textarea', - rows: 6, - class: 'Form-formGroup--fullWidth', - "default": "---", - awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Host Variables'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd) || isSmartInvHost' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd) && !isSmartInvHost' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd) || isSmartInvHost' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(host.summary_fields.user_capabilities.edit || canAdd) && !isSmartInvHost' - } - }, - - related: { - ansible_facts: { - name: 'ansible_facts', - awToolTip: i18n._('Please save before viewing facts.'), - dataPlacement: 'top', - title: i18n._('Facts'), - skipGenerator: true - }, - nested_groups: { - name: 'nested_groups', - awToolTip: i18n._('Please save before defining groups.'), - dataPlacement: 'top', - ngClick: "$state.go('inventories.edit.hosts.edit.nested_groups')", - title: i18n._('Groups'), - iterator: 'nested_group' - }, - insights: { - name: 'insights', - awToolTip: i18n._('Please save before viewing Insights.'), - dataPlacement: 'top', - title: i18n._('Insights'), - skipGenerator: true, - ngIf: "host.insights_system_id!==null && host.summary_fields.inventory.hasOwnProperty('insights_credential_id')" - } - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.list.js deleted file mode 100644 index 5482faeb49e7..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.list.js +++ /dev/null @@ -1,131 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - name: 'hosts', - iterator: 'host', - editTitle: '{{ selected_group }}', - showTitle: false, - well: true, - wellOverride: true, - index: false, - hover: true, - multiSelect: true, - trackBy: 'host.id', - basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/hosts/', - - fields: { - toggleHost: { - ngDisabled: '!host.summary_fields.user_capabilities.edit || host.has_inventory_sources', - label: '', - columnClass: 'List-staticColumn--toggle', - type: "toggle", - ngClick: "toggleHost($event, host)", - awToolTip: "

" + - i18n._("Indicates if a host is available and should be included in running jobs.") + - "

" + - i18n._("For hosts that are part of an external" + - " inventory, this flag cannot be changed. It will be" + - " set by the inventory sync process.") + - "

", - dataPlacement: "right", - nosort: true, - }, - active_failures: { - label: '', - iconOnly: true, - nosort: true, - // do not remove this ng-click directive - // the list generator case to handle fields without ng-click - // cannot handle the aw-* directives - ngClick: 'noop()', - awPopOver: "{{ host.job_status_html }}", - dataTitle: "{{ host.job_status_title }}", - awToolTip: "{{ host.badgeToolTip }}", - dataPlacement: 'top', - icon: "{{ 'fa icon-job-' + host.active_failures }}", - id: 'active-failures-action', - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - key: true, - label: i18n._('Hosts'), - uiSref: ".edit({inventory_id: host.inventory_id,host_id: host.id})", - ngClass: "{ 'host-disabled-label': !host.enabled }", - columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', - dataHostId: "{{ host.id }}", - dataType: "host", - class: 'InventoryManage-breakWord' - }, - groups: { - label: i18n._("Related Groups"), - type: 'related_groups', - nosort: true, - showDelete: true, - columnClass: 'RelatedGroupsLabelsCell List-tableCell col-lg-2 col-md-3 hidden-sm hidden-xs' - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', - edit: { - ngClick: "editHost(host)", - icon: 'icon-edit', - awToolTip: i18n._('Edit host'), - dataPlacement: 'top', - ngShow: 'host.summary_fields.user_capabilities.edit' - }, - insights: { - ngClick: "goToInsights(host)", - icon: 'fa-info', - awToolTip: i18n._('View Insights Data'), - dataPlacement: 'top', - ngShow: 'host.insights_system_id && host.summary_fields.inventory.hasOwnProperty("insights_credential_id")', - ngClass: "{'List-actionButton--selected': $stateParams['host_id'] == host.id && $state.is('inventories.edit.hosts.edit.insights')}" - }, - view: { - ngClick: "editHost(host)", - awToolTip: i18n._('View host'), - dataPlacement: 'top', - ngShow: '!host.summary_fields.user_capabilities.edit' - }, - "delete": { - ngClick: "deleteHost(host.id, host.name)", - icon: 'icon-trash', - awToolTip: i18n._('Delete host'), - dataPlacement: 'top', - ngShow: 'host.summary_fields.user_capabilities.delete' - } - }, - - actions: { - launch: { - mode: 'all', - ngDisabled: '!hostsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: i18n._("Select an inventory source by clicking the check box beside it. The inventory source can be a single host or a selection of multiple hosts."), - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('RUN COMMANDS'), - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - // TODO: we don't always want to show this - ngShow: 'inventory_obj.summary_fields.user_capabilities.adhoc' - }, - create: { - mode: 'all', - ngClick: "createHost()", - awToolTip: i18n._("Create a new host"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.route.js deleted file mode 100644 index 0c8f6cb23a89..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.route.js +++ /dev/null @@ -1,83 +0,0 @@ -import { N_ } from '../../../../i18n'; - -export default { - name: "inventories.edit.hosts", - url: "/hosts?{host_search:queryset}", - params: { - host_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash:"" - } - }, - ncyBreadcrumb: { - parent: "inventories.edit", - label: N_("HOSTS") - }, - views: { - 'related': { - templateProvider: function(ListDefinition, generateList, $stateParams, GetBasePath) { - let list = _.cloneDeep(ListDefinition); - if($stateParams && $stateParams.group) { - list.basePath = GetBasePath('groups') + _.last($stateParams.group) + '/all_hosts'; - } - else { - //reaches here if the user is on the root level group - list.basePath = GetBasePath('inventory') + $stateParams.inventory_id + '/hosts'; - } - let html = generateList.build({ - list: list, - mode: 'edit' - }); - return html; - }, - controller: 'RelatedHostListController' - } - }, - resolve: { - ListDefinition: ['RelatedHostsListDefinition', '$stateParams', 'GetBasePath', (RelatedHostsListDefinition, $stateParams, GetBasePath) => { - let list = _.cloneDeep(RelatedHostsListDefinition); - list.basePath = GetBasePath('inventory') + $stateParams.inventory_id + '/hosts'; - return list; - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - hostsUrl: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return $stateParams.group && $stateParams.group.length > 0 ? - // nested context - provide all hosts managed by nodes - InventoriesService.childHostsUrl(_.last($stateParams.group)) : - // root context - provide all hosts in an inventory - InventoriesService.rootHostsUrl($stateParams.inventory_id); - }], - hostsDataset: ['ListDefinition', 'QuerySet', '$stateParams', 'hostsUrl', (list, qs, $stateParams, hostsUrl) => { - let path = hostsUrl; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - }], - inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', function(rbacUiControlService) { - return rbacUiControlService.canAdd('hosts') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js deleted file mode 100644 index c710a7675485..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - name: 'inventories.edit.hosts.edit.nested_groups.associate', - squashSearchUrl: true, - url: '/associate', - ncyBreadcrumb:{ - skip:true - }, - views: { - 'modal@inventories.edit.hosts.edit': { - templateProvider: function() { - return ``; - }, - controller: function($scope, $q, GroupsService, $state){ - $scope.associateGroups = function(selectedItems){ - var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) ) - .then( () =>{ - deferred.resolve(); - }, (error) => { - deferred.reject(error); - }); - }; - } - } - }, - onExit: function($state) { - if ($state.transition) { - $('#associate-groups-modal').modal('hide'); - $('body').removeClass('modal-open'); - } - }, -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html deleted file mode 100644 index 5f68d4dc51db..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-list.controller.js deleted file mode 100644 index 72a841dc7627..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-list.controller.js +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'HostNestedGroupListDefinition', 'InventoryUpdate', - 'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', 'ProcessErrors', 'host', - function($scope, $rootScope, $state, $stateParams, HostNestedGroupListDefinition, InventoryUpdate, - GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd, ProcessErrors, host){ - - let list = HostNestedGroupListDefinition; - - init(); - - function init(){ - $scope.toDisassociate = host; - $scope.inventory_id = $stateParams.inventory_id; - $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = canAdd; - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watchCollection(list.name, function(){ - _.forEach($scope[list.name], buildStatusIndicators); - }); - - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - if(!$scope.groupsSelected) { - $scope.groupsSelected = []; - } - $scope.groupsSelected.push(item); - } else { - _.remove($scope.groupsSelected, { id: item.id }); - if($scope.groupsSelected.length === 0) { - $scope.groupsSelected = null; - } - } - }); - - } - - function buildStatusIndicators(group){ - if (group === undefined || group === null) { - group = {}; - } - - let hosts_status; - - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory_id, - group_id: group.id - }); - _.assign(group, - {hosts_status_tip: hosts_status.tooltip}, - {hosts_status_class: hosts_status.class}); - } - - $scope.associateGroup = function() { - $state.go('.associate'); - }; - - $scope.disassociateGroup = function(group){ - $scope.disassociateFrom = group; - $('#group-disassociate-modal').modal('show'); - }; - - $scope.confirmDisassociate = function(){ - - // Bind an even listener for the modal closing. Trying to $state.go() before the modal closes - // will mean that these two things are running async and the modal may not finish closing before - // the state finishes transitioning. - $('#group-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () { - // Remove the event handler so that we don't end up with multiple bindings - $('#group-disassociate-modal').off('hidden.bs.modal'); - - let reloadListStateParams = null; - - if($scope.nested_groups.length === 1 && $state.params.nested_group_search && !_.isEmpty($state.params.nested_group_search.page) && $state.params.nested_group_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.nested_group_search.page = (parseInt(reloadListStateParams.nested_group_search.page)-1).toString(); - } - - // Reload the inventory manage page and show that the group has been removed - $state.go('.', reloadListStateParams, {reload: true}); - }); - - let closeModal = function(){ - $('#group-disassociate-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }; - - GroupsService.disassociateHost($scope.toDisassociate.id, $scope.disassociateFrom.id) - .then(() => { - closeModal(); - }).catch((error) => { - closeModal(); - ProcessErrors(null, error.data, error.status, null, { - hdr: 'Error!', - msg: 'Failed to disassociate group from parent group: POST returned status' + - error.status - }); - }); - }; - - $scope.editGroup = function(id){ - $state.go('inventories.edit.groups.edit', {group_id: id}); - }; - - $scope.goToGroupGroups = function(id){ - $state.go('inventories.edit.groups.edit.nested_groups', {group_id: id}); - }; - - $scope.setAdhocPattern = function(){ - var pattern = _($scope.groupsSelected) - .map(function(item){ - return item.name; - }).value().join(':'); - - $state.go('^.^.^.adhoc', {pattern: pattern}); - }; - - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js deleted file mode 100644 index e544040e5ba7..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js +++ /dev/null @@ -1,105 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'nested_groups', - iterator: 'nested_group', - editTitle: '{{ inventory.name }}', - well: true, - wellOverride: true, - index: false, - hover: true, - multiSelect: true, - trackBy: 'nested_group.id', - basePath: 'api/v2/hosts/{{$stateParams.host_id}}/all_groups/', - - fields: { - failed_hosts: { - label: '', - nosort: true, - mode: 'all', - iconOnly: true, - awToolTip: "{{ nested_group.hosts_status_tip }}", - dataPlacement: "top", - icon: "{{ 'fa icon-job-' + nested_group.hosts_status_class }}", - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - label: i18n._('Groups'), - key: true, - ngClick: "goToGroupGroups(nested_group.id)", - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6', - class: 'InventoryManage-breakWord', - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - launch: { - mode: 'all', - ngDisabled: '!groupsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: i18n._("Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups."), - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('RUN COMMANDS'), - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - ngShow: 'canAdhoc' - // TODO: set up a tip watcher and change text based on when - // things are selected/not selected. This is started and - // commented out in the inventory controller within the watchers. - // awToolTip: "{{ adhocButtonTipContents }}", - // dataTipWatch: "adhocButtonTipContents" - }, - associate: { - mode: 'all', - ngClick: 'associateGroup()', - awToolTip: i18n._("Associate an existing group"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', - - edit: { - mode: 'all', - ngClick: "editGroup(nested_group.id)", - awToolTip: i18n._('Edit group'), - dataPlacement: "top", - ngShow: "nested_group.summary_fields.user_capabilities.edit" - }, - view: { - mode: 'all', - ngClick: "editGroup(nested_group.id)", - awToolTip: i18n._('View group'), - dataPlacement: "top", - ngShow: "!nested_group.summary_fields.user_capabilities.edit" - }, - "delete": { - mode: 'all', - ngClick: "disassociateGroup(nested_group)", - awToolTip: i18n._('Disassociate group'), - iconClass: 'fa fa-times', - dataPlacement: "top", - ngShow: "nested_group.summary_fields.user_capabilities.delete" - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js deleted file mode 100644 index 7f3a82a4930c..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js +++ /dev/null @@ -1,78 +0,0 @@ -import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; -import { N_ } from '../../../../../../i18n'; - -export default { - name: 'inventories.edit.hosts.edit.nested_groups', - url: "/nested_groups?{nested_group_search:queryset}", - params: { - nested_group_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: "" - } - }, - ncyBreadcrumb: { - parent: "inventories.edit.hosts.edit", - label: N_("ASSOCIATED GROUPS") - }, - views: { - // 'related@inventories.edit.groups.edit': { - 'related': { - templateProvider: function(HostNestedGroupListDefinition, generateList, $templateRequest) { - let list = _.cloneDeep(HostNestedGroupListDefinition); - - let html = generateList.build({ - list: list, - mode: 'edit' - }); - - return $templateRequest(templateUrl('inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate')).then((template) => { - return html.concat(template); - }); - }, - controller: 'HostNestedGroupsListController' - } - }, - resolve: { - Dataset: ['HostNestedGroupListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - if($stateParams.group_id){ - path = GetBasePath('groups') + $stateParams.group_id + '/children'; - } - else if($stateParams.host_id){ - path = GetBasePath('hosts') + $stateParams.host_id + '/all_groups'; - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - host: ['$stateParams', 'HostsService', function($stateParams, HostsService) { - if($stateParams.host_id){ - return HostsService.get({ id: $stateParams.host_id }).then((res) => res.data.results[0]); - } - }], - inventoryData: ['InventoriesService', '$stateParams', 'host', function(InventoriesService, $stateParams, host) { - var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id; - return InventoriesService.getInventory(id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/main.js deleted file mode 100644 index d2ec22fe62c8..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import HostNestedGroupListDefinition from './host-nested-groups.list'; -import HostNestedGroupsListController from './host-nested-groups-list.controller'; - -export default - angular.module('hostNestedGroups', []) - .factory('HostNestedGroupListDefinition', HostNestedGroupListDefinition) - .controller('HostNestedGroupsListController', HostNestedGroupsListController); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/main.js deleted file mode 100644 index 04cfc8ba9ad3..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './sources-add.controller'; - -export default -angular.module('sourcesAdd', []) - .controller('SourcesAddController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js deleted file mode 100644 index 4415dc386dfc..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js +++ /dev/null @@ -1,321 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', - 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService', - 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', - 'rbacUiControlService', 'ToJSON', 'SourcesService', 'Empty', - 'Wait', 'Rest', 'Alert', 'ProcessErrors', 'inventorySourcesOptions', - '$rootScope', 'i18n', 'InventorySourceModel', 'InventoryHostsStrings', - function($state, $stateParams, $scope, SourcesFormDefinition, ParseTypeChange, - GenerateForm, inventoryData, GroupsService, GetChoices, - GetBasePath, CreateSelect2, GetSourceTypeOptions, rbacUiControlService, - ToJSON, SourcesService, Empty, Wait, Rest, Alert, ProcessErrors, - inventorySourcesOptions,$rootScope, i18n, InventorySource, InventoryHostsStrings) { - - let form = SourcesFormDefinition; - $scope.mode = 'add'; - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope, true); - $scope.canAdd = inventorySourcesOptions.actions.POST; - $scope.envParseType = 'yaml'; - - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'rax_regions', - choice_name: 'rax_region_choices', - options: inventorySourcesOptions - }); - - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'ec2_regions', - choice_name: 'ec2_region_choices', - options: inventorySourcesOptions - }); - - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'gce_regions', - choice_name: 'gce_region_choices', - options: inventorySourcesOptions - }); - - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'azure_regions', - choice_name: 'azure_rm_region_choices', - options: inventorySourcesOptions - }); - - // Load options for group_by - GetChoices({ - scope: $scope, - field: 'group_by', - variable: 'ec2_group_by', - choice_name: 'ec2_group_by_choices', - options: inventorySourcesOptions - }); - - initRegionSelect(); - - GetChoices({ - scope: $scope, - field: 'verbosity', - variable: 'verbosity_options', - options: inventorySourcesOptions - }); - - CreateSelect2({ - element: '#inventory_source_verbosity', - multiple: false - }); - - $scope.verbosity = $scope.verbosity_options[1]; - - GetSourceTypeOptions({ - scope: $scope, - variable: 'source_type_options' - }); - - const inventorySource = new InventorySource(); - - var getInventoryFiles = function (project) { - var url; - - if (!Empty(project)) { - url = GetBasePath('projects') + project + '/inventories/'; - Wait('start'); - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - $scope.inventory_files = data; - $scope.inventory_files.push("/ (project root)"); - CreateSelect2({ - element:'#inventory-file-select', - addNew: true, - multiple: false, - scope: $scope, - options: 'inventory_files', - model: 'inventory_file' - }); - Wait('stop'); - }) - .catch(() => { - Alert('Cannot get inventory files', 'Unable to retrieve the list of inventory files for this project.', 'alert-info'); - Wait('stop'); - }); - } - }; - - // Register a watcher on project_name - if ($scope.getInventoryFilesUnregister) { - $scope.getInventoryFilesUnregister(); - } - $scope.getInventoryFilesUnregister = $scope.$watch('project', function (newValue, oldValue) { - if (newValue !== oldValue) { - getInventoryFiles(newValue); - } - }); - - $scope.lookupCredential = function(){ - if($scope.source.value !== "scm" && $scope.source.value !== "custom") { - let kind = ($scope.source.value === "ec2") ? "aws" : $scope.source.value; - $state.go('.credential', { - credential_search: { - kind: kind, - page_size: '5', - page: '1' - } - }); - } - else { - $state.go('.credential', { - credential_search: { - credential_type__kind: "cloud", - page_size: '5', - page: '1' - } - }); - } - }; - - $scope.lookupProject = function(){ - $state.go('.project', { - project_search: { - page_size: '5', - page: '1' - } - }); - }; - - $scope.sourceChange = function(source) { - source = (source && source.value) ? source.value : ''; - if ($scope.source.value === "scm" && $scope.source.value === "custom") { - $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network'; - } - else{ - $scope.credentialBasePath = (source === 'ec2') ? GetBasePath('credentials') + '?kind=aws' : GetBasePath('credentials') + (source === '' ? '' : '?kind=' + (source)); - } - if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm' || source === 'cloudforms' || source === "satellite6") { - $scope.envParseType = 'yaml'; - - var varName; - if (source === 'scm') { - varName = 'custom_variables'; - } else { - varName = source + '_variables'; - } - - $scope[varName] = $scope[varName] === (null || undefined) ? '---' : $scope[varName]; - ParseTypeChange({ - scope: $scope, - field_id: varName, - variable: varName, - parse_variable: 'envParseType' - }); - } - - if (source === 'scm') { - $scope.projectBasePath = GetBasePath('projects') + '?not__status=never updated'; - $scope.overwrite_vars = true; - $scope.inventory_source_form.inventory_file.$setPristine(); - } else { - $scope.overwrite_vars = false; - } - - // reset fields - $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; - // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint - $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions']; - $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false; - $scope.source_regions = null; - $scope.credential = null; - $scope.credential_name = null; - $scope.group_by = null; - $scope.group_by_choices = []; - initRegionSelect(); - }; - // region / source options callback - - $scope.$on('sourceTypeOptionsReady', function() { - CreateSelect2({ - element: '#inventory_source_source', - multiple: false - }); - }); - - function initRegionSelect(){ - CreateSelect2({ - element: '#inventory_source_source_regions', - multiple: true - }); - - let add_new = false; - if( _.get($scope, 'source') === 'ec2' || _.get($scope.source, 'value') === 'ec2') { - $scope.group_by_choices = $scope.ec2_group_by; - $scope.groupByPopOver = "

" + i18n._("Select which groups to create automatically. ") + - $rootScope.BRAND_NAME + i18n._(" will create group names similar to the following examples based on the options selected:") + "

    " + - "
  • " + i18n._("Availability Zone:") + "zones » us-east-1b
  • " + - "
  • " + i18n._("Image ID:") + "images » ami-b007ab1e
  • " + - "
  • " + i18n._("Instance ID:") + "instances » i-ca11ab1e
  • " + - "
  • " + i18n._("Instance Type:") + "types » type_m1_medium
  • " + - "
  • " + i18n._("Key Name:") + "keys » key_testing
  • " + - "
  • " + i18n._("Region:") + "regions » us-east-1
  • " + - "
  • " + i18n._("Security Group:") + "security_groups » security_group_default
  • " + - "
  • " + i18n._("Tags:") + "tags » tag_Name » tag_Name_host1
  • " + - "
  • " + i18n._("VPC ID:") + "vpcs » vpc-5ca1ab1e
  • " + - "
  • " + i18n._("Tag None:") + "tags » tag_none
  • " + - "

" + i18n._("If blank, all groups above are created except") + "" + i18n._("Instance ID") + ".

"; - - $scope.instanceFilterPopOver = "

" + i18n._("Provide a comma-separated list of filter expressions. ") + - i18n._("Hosts are imported to ") + $rootScope.BRAND_NAME + i18n._(" when ") + "" + i18n._("ANY") + "" + i18n._(" of the filters match.") + "

" + - i18n._("Limit to hosts having a tag:") + "
\n" + - "
tag-key=TowerManaged
\n" + - i18n._("Limit to hosts using either key pair:") + "
\n" + - "
key-name=staging, key-name=production
\n" + - i18n._("Limit to hosts where the Name tag begins with ") + "" + i18n._("test") + ":
\n" + - "
tag:Name=test*
\n" + - "

" + i18n._("View the ") + "" + i18n._("Describe Instances documentation") + " " + - i18n._("for a complete list of supported filters.") + "

"; - } - if( _.get($scope, 'source') === 'vmware' || _.get($scope.source, 'value') === 'vmware') { - add_new = true; - $scope.group_by_choices = []; - $scope.group_by = $scope.group_by_choices; - $scope.groupByPopOver = i18n._("Specify which groups to create automatically. Group names will be created similar to the options selected. If blank, all groups above are created. Refer to Ansible Tower documentation for more detail."); - $scope.instanceFilterPopOver = i18n._("Provide a comma-separated list of filter expressions. Hosts are imported when all of the filters match. Refer to Ansible Tower documentation for more detail."); - } - if( _.get($scope, 'source') === 'tower' || _.get($scope.source, 'value') === 'tower') { - $scope.instanceFilterPopOver = i18n._("Provide the named URL encoded name or id of the remote Tower inventory to be imported."); - } - CreateSelect2({ - element: '#inventory_source_group_by', - multiple: true, - addNew: add_new - }); - } - - $scope.formCancel = function() { - $state.go('^'); - }; - - $scope.formSave = function() { - var params; - - params = { - name: $scope.name, - description: $scope.description, - inventory: inventoryData.id, - instance_filters: $scope.instance_filters, - source_script: $scope.inventory_script, - credential: $scope.credential, - overwrite: $scope.overwrite, - overwrite_vars: $scope.overwrite_vars, - update_on_launch: $scope.update_on_launch, - verbosity: $scope.verbosity.value, - update_cache_timeout: $scope.update_cache_timeout || 0, - // comma-delimited strings - group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by), - source_regions: _.map($scope.source_regions, 'value').join(',') - }; - - if ($scope.source) { - let source_vars = $scope.source.value === 'scm' ? $scope.custom_variables : $scope[$scope.source.value + '_variables']; - params.source_vars = source_vars === '---' || source_vars === '{}' ? null : source_vars; - params.source = $scope.source.value; - if ($scope.source.value === 'scm') { - params.update_on_project_update = $scope.update_on_project_update; - params.source_project = $scope.project; - - if ($scope.inventory_file === '/ (project root)') { - params.source_path = ""; - } else { - params.source_path = $scope.inventory_file; - } - } - } else { - params.source = null; - } - - inventorySource.request('post', { - data: params - }).then((response) => { - let inventory_source_id = response.data.id; - $state.go('^.edit', {inventory_source_id: inventory_source_id}, {reload: true}); - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: InventoryHostsStrings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js deleted file mode 100644 index 897a8446ba3e..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js +++ /dev/null @@ -1,30 +0,0 @@ -import { N_ } from '../../../../../i18n'; - -export default { - name: "inventories.edit.inventory_sources.add", - url: "/add", - ncyBreadcrumb: { - parent: "inventories.edit.inventory_sources", - label: N_("CREATE INVENTORY SOURCE") - }, - views: { - 'sourcesForm@inventories': { - templateProvider: function(GenerateForm, SourcesFormDefinition) { - let form = SourcesFormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: 'SourcesAddController' - } - }, - resolve: { - inventorySourcesOptions: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.inventorySourcesOptions($stateParams.inventory_id) - .then(function(res) { - return res.data; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/main.js deleted file mode 100644 index 8c68bc554407..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './sources-edit.controller'; - -export default -angular.module('sourcesEdit', []) - .controller('SourcesEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js deleted file mode 100644 index eb3c083cd472..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js +++ /dev/null @@ -1,417 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$state', '$stateParams', '$scope', 'ParseVariableString', - 'rbacUiControlService', 'ToJSON', 'ParseTypeChange', 'GroupsService', - 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', - 'SourcesService', 'inventoryData', 'inventorySourcesOptions', 'Empty', - 'Wait', 'Rest', 'Alert', '$rootScope', 'i18n', 'InventoryHostsStrings', - 'ProcessErrors', 'inventorySource', - function($state, $stateParams, $scope, ParseVariableString, - rbacUiControlService, ToJSON,ParseTypeChange, GroupsService, - GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, - SourcesService, inventoryData, inventorySourcesOptions, Empty, - Wait, Rest, Alert, $rootScope, i18n, InventoryHostsStrings, - ProcessErrors, inventorySource) { - - const inventorySourceData = inventorySource.get(); - - $scope.projectBasePath = GetBasePath('projects') + '?not__status=never updated'; - $scope.canAdd = inventorySourcesOptions.actions.POST; - // instantiate expected $scope values from inventorySourceData - _.assign($scope, - {credential: inventorySourceData.credential}, - {overwrite: inventorySourceData.overwrite}, - {overwrite_vars: inventorySourceData.overwrite_vars}, - {update_on_launch: inventorySourceData.update_on_launch}, - {update_cache_timeout: inventorySourceData.update_cache_timeout}, - {instance_filters: inventorySourceData.instance_filters}, - {inventory_script: inventorySourceData.source_script}, - {verbosity: inventorySourceData.verbosity}); - - $scope.inventory_source_obj = inventorySourceData; - $scope.breadcrumb.inventory_source_name = inventorySourceData.name; - if (inventorySourceData.credential) { - $scope.credential_name = inventorySourceData.summary_fields.credential.name; - } - - if(inventorySourceData.source === 'scm') { - $scope.project = inventorySourceData.source_project; - $scope.project_name = inventorySourceData.summary_fields.source_project.name; - updateSCMProject(); - } - - // display custom inventory_script name - if (inventorySourceData.source === 'custom' && inventorySourceData.summary_fields.source_script) { - $scope.inventory_script_name = inventorySourceData.summary_fields.source_script.name; - } - $scope = angular.extend($scope, inventorySourceData); - - $scope.$watch('summary_fields.user_capabilities.edit', function(val) { - $scope.canAdd = val; - }); - - $scope.$on('sourceTypeOptionsReady', function() { - $scope.source = _.find($scope.source_type_options, { value: inventorySourceData.source }); - var source = $scope.source && $scope.source.value ? $scope.source.value : null; - $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false; - CreateSelect2({ - element: '#inventory_source_source', - multiple: false - }); - - if (source === 'ec2' || source === 'custom' || - source === 'vmware' || source === 'openstack' || - source === 'scm' || source === 'cloudforms' || - source === 'satellite6') { - - var varName; - if (source === 'scm') { - varName = 'custom_variables'; - } else { - varName = source + '_variables'; - } - - $scope[varName] = ParseVariableString(inventorySourceData - .source_vars); - - ParseTypeChange({ - scope: $scope, - field_id: varName, - variable: varName, - parse_variable: 'envParseType', - }); - } - }); - - $scope.envParseType = 'yaml'; - - GetSourceTypeOptions({ - scope: $scope, - variable: 'source_type_options' - }); - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'rax_regions', - choice_name: 'rax_region_choices', - options: inventorySourcesOptions - }); - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'ec2_regions', - choice_name: 'ec2_region_choices', - options: inventorySourcesOptions - }); - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'gce_regions', - choice_name: 'gce_region_choices', - options: inventorySourcesOptions - }); - GetChoices({ - scope: $scope, - field: 'source_regions', - variable: 'azure_regions', - choice_name: 'azure_rm_region_choices', - options: inventorySourcesOptions - }); - GetChoices({ - scope: $scope, - field: 'group_by', - variable: 'ec2_group_by', - choice_name: 'ec2_group_by_choices', - options: inventorySourcesOptions - }); - - var source = $scope.source === 'azure_rm' ? 'azure' : $scope.source; - var regions = inventorySourceData.source_regions.split(','); - // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint - $scope.source_region_choices = $scope[source + '_regions']; - - // the API stores azure regions as all-lowercase strings - but the azure regions received from OPTIONS are Snake_Cased - if (source === 'azure') { - $scope.source_regions = _.map(regions, (region) => _.find($scope[source + '_regions'], (o) => o.value.toLowerCase() === region)); - } - // all other regions are 1-1 - else { - $scope.source_regions = _.map(regions, (region) => _.find($scope[source + '_regions'], (o) => o.value === region)); - } - initRegionSelect(); - - GetChoices({ - scope: $scope, - field: 'verbosity', - variable: 'verbosity_options', - options: inventorySourcesOptions - }); - - var i; - for (i = 0; i < $scope.verbosity_options.length; i++) { - if ($scope.verbosity_options[i].value === $scope.verbosity) { - $scope.verbosity = $scope.verbosity_options[i]; - } - } - - initVerbositySelect(); - - $scope.$watch('verbosity', initVerbositySelect); - - // Register a watcher on project_name - if ($scope.getInventoryFilesUnregister) { - $scope.getInventoryFilesUnregister(); - } - $scope.getInventoryFilesUnregister = $scope.$watch('project', function (newValue, oldValue) { - if (newValue !== oldValue) { - updateSCMProject(); - } - }); - - function initVerbositySelect(){ - CreateSelect2({ - element: '#inventory_source_verbosity', - multiple: false - }); - } - - function sync_inventory_file_select2() { - CreateSelect2({ - element:'#inventory-file-select', - addNew: true, - multiple: false, - scope: $scope, - options: 'inventory_files', - model: 'inventory_file' - }); - - // TODO: figure out why the inventory file model is being set to - // dirty - } - - function updateSCMProject() { - var url; - - if (!Empty($scope.project)) { - url = GetBasePath('projects') + $scope.project + '/inventories/'; - Wait('start'); - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - $scope.inventory_files = data; - $scope.inventory_files.push("/ (project root)"); - - if (inventorySourceData.source_path !== "") { - $scope.inventory_file = inventorySourceData.source_path; - if ($scope.inventory_files.indexOf($scope.inventory_file) < 0) { - $scope.inventory_files.push($scope.inventory_file); - } - } else { - $scope.inventory_file = "/ (project root)"; - } - sync_inventory_file_select2(); - Wait('stop'); - }) - .catch(() => { - Alert('Cannot get inventory files', 'Unable to retrieve the list of inventory files for this project.', 'alert-info'); - Wait('stop'); - }); - } - } - - function initRegionSelect() { - CreateSelect2({ - element: '#inventory_source_source_regions', - multiple: true - }); - - let add_new = false; - if( _.get($scope, 'source') === 'ec2' || _.get($scope.source, 'value') === 'ec2') { - $scope.group_by_choices = $scope.ec2_group_by; - let group_by = inventorySourceData.group_by.split(','); - $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, { value: item })); - - $scope.groupByPopOver = "

" + i18n._("Select which groups to create automatically. ") + - $rootScope.BRAND_NAME + i18n._(" will create group names similar to the following examples based on the options selected:") + "

    " + - "
  • " + i18n._("Availability Zone:") + "zones » us-east-1b
  • " + - "
  • " + i18n._("Image ID:") + "images » ami-b007ab1e
  • " + - "
  • " + i18n._("Instance ID:") + "instances » i-ca11ab1e
  • " + - "
  • " + i18n._("Instance Type:") + "types » type_m1_medium
  • " + - "
  • " + i18n._("Key Name:") + "keys » key_testing
  • " + - "
  • " + i18n._("Region:") + "regions » us-east-1
  • " + - "
  • " + i18n._("Security Group:") + "security_groups » security_group_default
  • " + - "
  • " + i18n._("Tags:") + "tags » tag_Name » tag_Name_host1
  • " + - "
  • " + i18n._("VPC ID:") + "vpcs » vpc-5ca1ab1e
  • " + - "
  • " + i18n._("Tag None:") + "tags » tag_none
  • " + - "

" + i18n._("If blank, all groups above are created except") + "" + i18n._("Instance ID") + ".

"; - - - $scope.instanceFilterPopOver = "

" + i18n._("Provide a comma-separated list of filter expressions. ") + - i18n._("Hosts are imported to ") + $rootScope.BRAND_NAME + i18n._(" when ") + "" + i18n._("ANY") + "" + i18n._(" of the filters match.") + "

" + - i18n._("Limit to hosts having a tag:") + "
\n" + - "
tag-key=TowerManaged
\n" + - i18n._("Limit to hosts using either key pair:") + "
\n" + - "
key-name=staging, key-name=production
\n" + - i18n._("Limit to hosts where the Name tag begins with ") + "" + i18n._("test") + ":
\n" + - "
tag:Name=test*
\n" + - "

" + i18n._("View the ") + "" + i18n._("Describe Instances documentation") + " " + - i18n._("for a complete list of supported filters.") + "

"; - - } - if( _.get($scope, 'source') === 'vmware' || _.get($scope.source, 'value') === 'vmware') { - add_new = true; - $scope.group_by_choices = (inventorySourceData.group_by) ? inventorySourceData.group_by.split(',') - .map((i) => ({name: i, label: i, value: i})) : []; - $scope.group_by = $scope.group_by_choices; - $scope.groupByPopOver = i18n._(`Specify which groups to create automatically. Group names will be created similar to the options selected. If blank, all groups above are created. Refer to Ansible Tower documentation for more detail.`); - $scope.instanceFilterPopOver = i18n._(`Provide a comma-separated list of filter expressions. Hosts are imported when all of the filters match. Refer to Ansible Tower documentation for more detail.`); - } - if( _.get($scope, 'source') === 'tower' || _.get($scope.source, 'value') === 'tower') { - $scope.instanceFilterPopOver = i18n._(`Provide the named URL encoded name or id of the remote Tower inventory to be imported.`); - } - CreateSelect2({ - element: '#inventory_source_group_by', - multiple: true, - addNew: add_new - }); - } - - $scope.lookupProject = function(){ - $state.go('.project', { - project_search: { - page_size: '5', - page: '1' - } - }); - }; - - $scope.lookupCredential = function(){ - if($scope.source.value !== "scm" && $scope.source.value !== "custom") { - let kind = ($scope.source.value === "ec2") ? "aws" : $scope.source.value; - $state.go('.credential', { - credential_search: { - kind: kind, - page_size: '5', - page: '1' - } - }); - } - else { - $state.go('.credential', { - credential_search: { - credential_type__kind: "cloud", - page_size: '5', - page: '1' - } - }); - } - }; - - $scope.formCancel = function() { - $state.go('^'); - }; - $scope.formSave = function() { - var params; - - params = { - id: inventorySourceData.id, - name: $scope.name, - description: $scope.description, - inventory: inventoryData.id, - instance_filters: $scope.instance_filters, - source_script: $scope.inventory_script, - credential: $scope.credential, - overwrite: $scope.overwrite, - overwrite_vars: $scope.overwrite_vars, - update_on_launch: $scope.update_on_launch, - update_cache_timeout: $scope.update_cache_timeout || 0, - verbosity: $scope.verbosity.value, - // comma-delimited strings - group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by), - source_regions: _.map($scope.source_regions, 'value').join(',') - }; - - if ($scope.source) { - let source_vars = $scope.source.value === 'scm' ? $scope.custom_variables : $scope[$scope.source.value + '_variables']; - params.source_vars = source_vars === '---' || source_vars === '{}' ? null : source_vars; - params.source = $scope.source.value; - if ($scope.source.value === 'scm') { - params.update_on_project_update = $scope.update_on_project_update; - params.source_project = $scope.project; - - if ($scope.inventory_file === '/ (project root)') { - params.source_path = ""; - } else { - params.source_path = $scope.inventory_file; - } - } - } else { - params.source = null; - } - - inventorySource.request('put', { - data: params - }).then(() => { - $state.go('.', null, { reload: true }); - }).catch(({ data, status, config }) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: InventoryHostsStrings.get('error.CALL', { path: `${config.url}`, status }) - }); - }); - }; - - $scope.sourceChange = function(source) { - source = (source && source.value) ? source.value : ''; - if ($scope.source.value === "scm" && $scope.source.value === "custom") { - $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network'; - } - else{ - $scope.credentialBasePath = (source === 'ec2') ? GetBasePath('credentials') + '?kind=aws' : GetBasePath('credentials') + (source === '' ? '' : '?kind=' + (source)); - } - if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm' || source === 'cloudforms' || source === "satellite6") { - $scope.envParseType = 'yaml'; - - var varName; - if (source === 'scm') { - varName = 'custom_variables'; - } else { - varName = source + '_variables'; - } - - $scope[varName] = $scope[varName] === (null || undefined) ? '---' : $scope[varName]; - ParseTypeChange({ - scope: $scope, - field_id: varName, - variable: varName, - parse_variable: 'envParseType' - }); - } - - if (source === 'scm') { - $scope.overwrite_vars = true; - $scope.inventory_source_form.inventory_file.$setPristine(); - } else { - $scope.overwrite_vars = false; - } - - // reset fields - $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; - // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint - $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions']; - $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false; - $scope.source_regions = null; - $scope.credential = null; - $scope.credential_name = null; - $scope.group_by = null; - $scope.group_by_choices = []; - - initRegionSelect(); - - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js deleted file mode 100644 index dbc233735746..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js +++ /dev/null @@ -1,29 +0,0 @@ -export default { - name: "inventories.edit.inventory_sources.edit", - url: "/edit/:inventory_source_id", - ncyBreadcrumb: { - parent: "inventories.edit.inventory_sources", - label: '{{breadcrumb.inventory_source_name}}' - }, - views: { - 'groupForm@inventories': { - templateProvider: function(GenerateForm, SourcesFormDefinition) { - let form = SourcesFormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'edit', - related: false - }); - }, - controller: 'SourcesEditController' - } - }, - resolve: { - inventorySource: ['InventorySourceModel', '$stateParams', (InventorySource, $stateParams) => { - return new InventorySource('get', $stateParams.inventory_source_id); - }], - inventorySourcesOptions: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.inventorySourcesOptions($stateParams.inventory_id) - .then((response) => response.data); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js deleted file mode 100644 index b739f2287d77..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js +++ /dev/null @@ -1,89 +0,0 @@ -import { N_ } from '../../../../../i18n'; - -export default { - searchPrefix: 'notification', - name: "inventories.edit.inventory_sources.edit.notifications", - url: `/notifications`, - ncyBreadcrumb: { - parent: "inventories.edit.inventory_sources.edit", - label: N_("NOTIFICATIONS") - }, - params: { - [ 'notification_search']: { - value: { order_by: 'name' } - } - }, - views: { - 'related': { - templateProvider: function(FormDefinition, GenerateForm, $stateParams, SourcesFormDefinition) { - var form, html; - if($stateParams && $stateParams.inventory_source_id){ - form = SourcesFormDefinition; - } - else { - form = typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition; - } - html = GenerateForm.buildCollection({ - mode: 'edit', - related: `notifications`, - form: form - }); - return html; - }, - controller: ['$scope', 'NotificationsList', 'Dataset', 'ToggleNotification', 'NotificationsListInit', 'GetBasePath', '$stateParams', - function($scope, list, Dataset, ToggleNotification, NotificationsListInit, GetBasePath, $stateParams) { - var params = $stateParams, - id = params.inventory_source_id, - url = GetBasePath('inventory_sources'); - - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - - NotificationsListInit({ - scope: $scope, - url: url, - id: id - }); - - $scope.$watch(`${list.iterator}_dataset`, function() { - // The list data has changed and we need to update which notifications are on/off - $scope.$emit('relatednotifications'); - }); - } - - $scope.toggleNotification = function(event, notifier_id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } - catch(e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: url + id, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - - init(); - - } - ] - } - }, - resolve: { - Dataset: ['NotificationsList', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - let path = GetBasePath(list.basePath); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/cancel-source-update.factory.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/cancel-source-update.factory.js deleted file mode 100644 index 394d0d54129e..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/cancel-source-update.factory.js +++ /dev/null @@ -1,63 +0,0 @@ -export default - function CancelSourceUpdate(Empty, Rest, ProcessErrors, Alert, Wait, Find) { - return function(params) { - var scope = params.scope, - id = params.id, - inventory_source = params.inventory_source; - - // Cancel the update process - if (Empty(inventory_source)) { - inventory_source = Find({ list: scope.inventory_sources, key: 'id', val: id }); - scope.selected_inventory_source_id = inventory_source.id; - } - - if (inventory_source && (inventory_source.status === 'running' || inventory_source.status === 'pending')) { - // We found the inventory_source, and there is a running update - Wait('start'); - Rest.setUrl(inventory_source.url); - Rest.get() - .then(({data}) => { - // Check that we have access to cancelling an update - var url = (data.related.current_update) ? data.related.current_update : data.related.last_update; - url += 'cancel/'; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - if (data.can_cancel) { - // Cancel the update process - Rest.setUrl(url); - Rest.post() - .then(() => { - Wait('stop'); - //Alert('Inventory Sync Cancelled', 'Request to cancel the sync process was submitted to the task manger. ' + - // 'Click the button to monitor the status.', 'alert-info'); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. POST status: ' + status - }); - }); - } - else { - Wait('stop'); - } - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + inventory_source.url + ' failed. GET status: ' + status - }); - }); - } - }; - } - -CancelSourceUpdate.$inject = - [ 'Empty', 'Rest', 'ProcessErrors', - 'Alert', 'Wait', 'Find' - ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-source-type-options.factory.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-source-type-options.factory.js deleted file mode 100644 index 33e9b83ca746..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-source-type-options.factory.js +++ /dev/null @@ -1,37 +0,0 @@ -export default - function GetSourceTypeOptions(Rest, ProcessErrors, GetBasePath) { - return function(params) { - var scope = params.scope, - variable = params.variable; - - if (scope[variable] === undefined) { - scope[variable] = []; - Rest.setUrl(GetBasePath('inventory_sources')); - Rest.options() - .then(({data}) => { - var i, choices = data.actions.GET.source.choices; - for (i = 0; i < choices.length; i++) { - if (choices[i][0] !== 'file' && choices[i][0] !== "") { - scope[variable].push({ - label: choices[i][1], - value: choices[i][0] - }); - } - } - scope.cloudCredentialRequired = false; - scope.$emit('sourceTypeOptionsReady'); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve options for inventory_sources.source. OPTIONS status: ' + status - }); - }); - } - }; - } - -GetSourceTypeOptions.$inject = - [ 'Rest', - 'ProcessErrors', - 'GetBasePath' - ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js deleted file mode 100644 index 772af4c68b39..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js +++ /dev/null @@ -1,61 +0,0 @@ -export default - function GetSyncStatusMsg(i18n) { - return function(params) { - var status = params.status, - launch_class = '', - launch_tip = i18n._('Start sync process'), - schedule_tip = i18n._('Schedule inventory syncs'), - stat, stat_class, status_tip; - - stat = status; - stat_class = stat; - - switch (status) { - case 'never updated': - stat = 'never'; - stat_class = 'na'; - status_tip = i18n._('Sync not performed. Click') + ' ' + i18n._('to start it now.'); - break; - case 'none': - case 'ok': - case '': - launch_class = 'btn-disabled'; - stat = 'n/a'; - stat_class = 'na'; - status_tip = i18n._('Cloud source not configured. Click') + ' ' + i18n._('to update.'); - launch_tip = i18n._('Cloud source not configured.'); - break; - case 'canceled': - status_tip = i18n._('Sync canceled. Click to view log.'); - break; - case 'failed': - status_tip = i18n._('Sync failed. Click to view log.'); - break; - case 'successful': - status_tip = i18n._('Sync completed. Click to view log.'); - break; - case 'pending': - status_tip = i18n._('Sync pending.'); - launch_class = "btn-disabled"; - launch_tip = "Sync pending"; - break; - case 'updating': - case 'running': - launch_class = "btn-disabled"; - launch_tip = i18n._("Sync running"); - status_tip = i18n._("Sync running. Click to view log."); - break; - } - - return { - "class": stat_class, - "tooltip": status_tip, - "status": stat, - "launch_class": launch_class, - "launch_tip": launch_tip, - "schedule_tip": schedule_tip - }; - }; - } - -GetSyncStatusMsg.$inject = ['i18n']; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/view-update-status.factory.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/view-update-status.factory.js deleted file mode 100644 index 5b928e5cf590..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/factories/view-update-status.factory.js +++ /dev/null @@ -1,35 +0,0 @@ -export default - function ViewUpdateStatus($state, Rest, ProcessErrors, Alert, Wait, Empty, Find) { - return function(params) { - var scope = params.scope, - inventory_source_id = params.inventory_source_id, - inventory_source = Find({ list: scope.inventory_sources, key: 'id', val: inventory_source_id }); - - if (inventory_source) { - if (Empty(inventory_source.status) || inventory_source.status === "never updated") { - Alert('No Status Available', '
An inventory sync has not been performed for the selected group. Start the process by ' + - 'clicking the button.
', 'alert-info', null, null, null, null, true); - } else { - Wait('start'); - Rest.setUrl(inventory_source.url); - Rest.get() - .then(({data}) => { - // Get the ID from the correct summary field - var update_id = (data.summary_fields.current_update) ? data.summary_fields.current_update.id : data.summary_fields.last_update.id; - - $state.go('output', { id: update_id, type: 'inventory' }); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve inventory source: ' + inventory_source.url + - ' GET returned status: ' + status }); - }); - } - } - }; - } - -ViewUpdateStatus.$inject = - [ '$state', 'Rest', 'ProcessErrors', - 'Alert', 'Wait', 'Empty', 'Find' - ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/main.js deleted file mode 100644 index 2c7c3b62f848..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './sources-list.controller'; - -export default - angular.module('sourcesList', []) - .controller('SourcesListController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js deleted file mode 100644 index 0b3877437802..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js +++ /dev/null @@ -1,17 +0,0 @@ -import { N_ } from '../../../../../../i18n'; -import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; - -export default { - name: 'inventories.edit.inventory_sources.edit.schedules.add', - url: '/add', - ncyBreadcrumb: { - parent: 'inventories.edit.inventory_sources.edit.schedules', - label: N_("CREATE SCHEDULE") - }, - views: { - 'scheduler@inventories': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm") - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js deleted file mode 100644 index 2c956fd6cd26..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js +++ /dev/null @@ -1,18 +0,0 @@ -import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; -import editScheduleResolve from '../../../../../../scheduler/editSchedule.resolve'; - -export default { - name: 'inventories.edit.inventory_sources.edit.schedules.edit', - url: '/:schedule_id', - ncyBreadcrumb: { - parent: 'inventories.edit.inventory_sources.edit.schedules', - label: "{{breadcrumb.schedule_name}}" - }, - views: { - 'scheduler@inventories': { - templateUrl: templateUrl("scheduler/schedulerForm"), - controller: 'schedulerEditController', - } - }, - resolve: editScheduleResolve() -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js deleted file mode 100644 index aebe56b62492..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js +++ /dev/null @@ -1,54 +0,0 @@ -import { N_ } from '../../../../../../i18n'; - -export default { - searchPrefix: 'schedule', - name: 'inventories.edit.inventory_sources.edit.schedules', - url: '/schedules', - ncyBreadcrumb: { - parent: 'inventories.edit.inventory_sources.edit', - label: N_('SCHEDULES') - }, - views: { - 'related': { - templateProvider: function(SchedulesList, generateList){ - SchedulesList.title = false; - let html = generateList.build({ - list: SchedulesList, - mode: 'edit' - }); - return html; - }, - controller: 'schedulerListController' - } - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', 'inventorySource', - function(list, qs, $stateParams, GetBasePath, inventorySource) { - let path = `${inventorySource.get().related.schedules}`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['inventorySource', function(inventorySource) { - return inventorySource.get(); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'inventorySource', - (SchedulesList, inventorySource) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = `${inventorySource.get().related.schedules}`; - return list; - } - ] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js deleted file mode 100644 index 6b2d43ee555f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js +++ /dev/null @@ -1,236 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'SourcesListDefinition', - 'InventoryUpdate', 'CancelSourceUpdate', - 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath', - 'GetSyncStatusMsg', 'Dataset', 'Find', 'QuerySet', - 'inventoryData', '$filter', 'Prompt', 'Wait', 'SourcesService', 'inventorySourceOptions', - 'canAdd', 'hasSyncableSources', 'i18n', 'InventoryHostsStrings', 'InventorySourceModel', 'ProcessErrors', - function($scope, $rootScope, $state, $stateParams, SourcesListDefinition, - InventoryUpdate, CancelSourceUpdate, - ViewUpdateStatus, rbacUiControlService, GetBasePath, GetSyncStatusMsg, - Dataset, Find, qs, inventoryData, $filter, Prompt, - Wait, SourcesService, inventorySourceOptions, canAdd, hasSyncableSources, i18n, - InventoryHostsStrings, InventorySource, ProcessErrors){ - - let inventorySource = new InventorySource(); - - let list = SourcesListDefinition; - var inventory_source; - - init(); - - function init(){ - $scope.inventory_id = $stateParams.inventory_id; - $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = canAdd; - $scope.showSyncAll = hasSyncableSources; - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.inventory_id = $stateParams.inventory_id; - _.forEach($scope[list.name], buildStatusIndicators); - optionsRequestDataProcessing(); - - $scope.$on(`ws-jobs`, function(e, data){ - inventory_source = Find({ list: $scope.inventory_sources, key: 'id', val: data.inventory_source_id }); - - if (inventory_source === undefined || inventory_source === null) { - inventory_source = {}; - } - - if(data.status === 'failed' || data.status === 'successful'){ - let path = GetBasePath('inventory') + $stateParams.inventory_id + '/inventory_sources'; - - qs.search(path, $state.params[`${list.iterator}_search`]) - .then((searchResponse)=> { - $scope[`${list.iterator}_dataset`] = searchResponse.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - _.forEach($scope[list.name], buildStatusIndicators); - optionsRequestDataProcessing(); - }); - } else { - var status = GetSyncStatusMsg({ - status: data.status - }); - inventory_source.status = data.status; - inventory_source.status_class = status.class; - inventory_source.status_tooltip = status.tooltip; - inventory_source.launch_tooltip = status.launch_tip; - inventory_source.launch_class = status.launch_class; - } - }); - - $scope.$watchCollection(`${$scope.list.name}`, function() { - _.forEach($scope[list.name], buildStatusIndicators); - optionsRequestDataProcessing(); - }); - } - - function optionsRequestDataProcessing(){ - if ($scope[list.name] !== undefined) { - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - - // Set the item source label - if (list.fields.source && inventorySourceOptions && inventorySourceOptions.hasOwnProperty('source')) { - inventorySourceOptions.source.choices.forEach(function(choice) { - if (choice[0] === item.source) { - itm.source_label = choice[1]; - } - }); - } - }); - } - } - - function buildStatusIndicators(inventory_source){ - if (inventory_source === undefined || inventory_source === null) { - inventory_source = {}; - } - - let inventory_source_status; - - inventory_source_status = GetSyncStatusMsg({ - status: inventory_source.status, - has_inventory_sources: inventory_source.has_inventory_sources, - source: ( (inventory_source) ? inventory_source.source : null ) - }); - _.assign(inventory_source, - {status_class: inventory_source_status.class}, - {status_tooltip: inventory_source_status.tooltip}, - {launch_tooltip: inventory_source_status.launch_tip}, - {launch_class: inventory_source_status.launch_class}, - {group_schedule_tooltip: inventory_source_status.schedule_tip}, - {source: inventory_source ? inventory_source.source : null}, - {status: inventory_source ? inventory_source.status : null}); - } - - $scope.createSource = function(){ - $state.go('inventories.edit.inventory_sources.add'); - }; - $scope.editSource = function(id){ - $state.go('inventories.edit.inventory_sources.edit', {inventory_source_id: id}); - }; - $scope.deleteSource = function(inventory_source){ - var action = function(){ - $rootScope.promptActionBtnClass = "Modal-errorButton--sourcesDelete"; - Wait('start'); - let hostDelete = SourcesService.deleteHosts(inventory_source.id).catch(({data, status}) => { - $('#prompt-modal').modal('hide'); - Wait('stop'); - ProcessErrors($scope, data, status, null, - { - hdr: i18n._('Error!'), - msg: i18n._('There was an error deleting inventory source hosts. Returned status: ') + - status - }); - }); - let groupDelete = SourcesService.deleteGroups(inventory_source.id).catch(({data, status}) => { - $('#prompt-modal').modal('hide'); - Wait('stop'); - ProcessErrors($scope, data, status, null, - { - hdr: i18n._('Error!'), - msg: i18n._('There was an error deleting inventory source groups. Returned status: ') + - status - }); - }); - Promise.all([hostDelete, groupDelete]).then(() => { - SourcesService.delete(inventory_source.id).then(() => { - $('#prompt-modal').modal('hide'); - delete $rootScope.promptActionBtnClass; - let reloadListStateParams = null; - - if($scope.inventory_sources.length === 1 && $state.params.inventory_source_search && !_.isEmpty($state.params.inventory_source_search.page) && $state.params.inventory_source_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.inventory_source_search.page = (parseInt(reloadListStateParams.inventory_source_search.page)-1).toString(); - } - if (parseInt($state.params.inventory_source_id) === inventory_source.id) { - $state.go('^', reloadListStateParams, {reload: true}); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - Wait('stop'); - }) - .catch(({data, status}) => { - $('#prompt-modal').modal('hide'); - Wait('stop'); - ProcessErrors($scope, data, status, null, - { - hdr: i18n._('Error!'), - msg: i18n._('There was an error deleting inventory source. Returned status: ') + - status - }); - }); - }); - }; - - inventorySource.getDependentResourceCounts(inventory_source.id) - .then((counts) => { - const invalidateRelatedLines = []; - let deleteModalBody = `
${InventoryHostsStrings.get('deleteResource.CONFIRM', 'inventory source')}
`; - - counts.forEach(countObj => { - if(countObj.count && countObj.count > 0) { - invalidateRelatedLines.push(`
${countObj.label}${countObj.count}
`); - } - }); - - if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { - deleteModalBody = `
${InventoryHostsStrings.get('deleteResource.USED_BY', 'inventory source')} ${InventoryHostsStrings.get('deleteResource.CONFIRM', 'inventory source')}
`; - invalidateRelatedLines.forEach(invalidateRelatedLine => { - deleteModalBody += invalidateRelatedLine; - }); - } - - Prompt({ - hdr: i18n._('Delete Source'), - resourceName: $filter('sanitize')(inventory_source.name), - body: deleteModalBody, - action: action, - actionText: 'DELETE' - }); - $rootScope.promptActionBtnClass = 'Modal-errorButton'; - }); - - }; - - $scope.updateSource = function(inventory_source) { - InventoryUpdate({ - scope: $scope, - url: inventory_source.related.update - }); - }; - - $scope.cancelUpdate = function (id) { - CancelSourceUpdate({ scope: $scope, id: id }); - }; - $scope.viewUpdateStatus = function (id) { - ViewUpdateStatus({ - scope: $scope, - inventory_source_id: id - }); - }; - $scope.scheduleSource = function(id) { - // Add this inv source's id to the array of inv source id's so that it gets - // added to the breadcrumb trail - $state.go('inventories.edit.inventory_sources.edit.schedules',{inventory_source_id: id}); - }; - - $scope.syncAllSources = function() { - InventoryUpdate({ - scope: $scope, - url: inventoryData.related.update_inventory_sources, - updateAllSources: true - }); - }; - - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html deleted file mode 100644 index 7a6ef41a07b8..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html +++ /dev/null @@ -1,79 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js deleted file mode 100644 index c9d988258127..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js +++ /dev/null @@ -1,89 +0,0 @@ -import { N_ } from '../../../../../i18n'; - -export default { - name: "inventories.edit.inventory_sources", - url: "/inventory_sources?{inventory_source_search:queryset}", - params: { - inventory_source_search: { - value: { - page_size: "20", - order_by: "name", - not__source: "" - }, - dynamic: true, - squash: "" - } - }, - data: { - socket: { - groups: { - jobs: ["status_changed"] - } - } - }, - ncyBreadcrumb: { - parent: "inventories.edit", - label: N_("SOURCES") - }, - views: { - 'related': { - templateProvider: function(SourcesListDefinition, generateList) { - let list = _.cloneDeep(SourcesListDefinition); - let html = generateList.build({ - list: list, - mode: 'edit' - }); - return html; - }, - controller: 'SourcesListController' - } - }, - resolve: { - inventorySourceOptions: ['SourcesService', (SourcesService) => { - return SourcesService.options().then(response => response.data.actions.GET); - }], - Dataset: ['SourcesListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data); - }], - canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { - return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - }], - hasSyncableSources: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.updateInventorySourcesGet($stateParams.inventory_id) - .then(function(res) { - let canUpdateFound = false; - if(res.data && res.data.length > 0) { - res.data.forEach(function(source) { - if(source.can_update) { - canUpdateFound = true; - } - }); - } - - return canUpdateFound; - }) - .catch(function() { - return false; - }); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-credential.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-credential.route.js deleted file mode 100644 index b80e65c1c9ea..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-credential.route.js +++ /dev/null @@ -1,52 +0,0 @@ -export default { - params: { - credential_search: { - value: { - page_size:"5", - order_by:"name", - role_level:"use_role", - kind: null, - credential_type__kind: null - }, - dynamic:true, - squash:"" - } - }, - data: { - basePath:"credentials", - formChildState:true - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'modal': { - templateProvider: function(ListDefinition, generateList) { - let list_html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - return `${list_html}`; - - } - } - }, - resolve: { - ListDefinition: ['CredentialList', function(list) { - return list; - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - return qs.search(GetBasePath('credentials'), $stateParams[`${list.iterator}_search`]); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-inventory-script.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-inventory-script.route.js deleted file mode 100644 index c2a9ab71b940..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-inventory-script.route.js +++ /dev/null @@ -1,65 +0,0 @@ -export default { - params: { - inventory_script_search: { - value: { - page_size: "5", - order_by: "name", - role_level: "admin_role", - }, - dynamic: true, - squash: "" - } - }, - data: { - basePath: "inventory_scripts", - formChildState: true - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'modal': { - templateProvider: function(ListDefinition, generateList) { - let list_html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - return `${list_html}`; - - } - } - }, - resolve: { - ListDefinition: ['InventoryScriptsList', function(list) { - return list; - }], - OrganizationId: ['ListDefinition', 'InventoriesService', '$stateParams', '$rootScope', - function(list, InventoriesService, $stateParams, $rootScope){ - if($rootScope.$$childTail && - $rootScope.$$childTail.$resolve && - $rootScope.$$childTail.$resolve.hasOwnProperty('inventoryData')){ - return $rootScope.$$childTail.$resolve.inventoryData.summary_fields.organization.id; - } - else { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data.summary_fields.organization.id); - } - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', '$state', 'OrganizationId', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope, $state, OrganizationId) => { - - $stateParams[`${list.iterator}_search`].role_level = "admin_role"; - $stateParams[`${list.iterator}_search`].organization = OrganizationId; - - return qs.search(GetBasePath('inventory_scripts'), $stateParams[`${list.iterator}_search`]); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-project.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-project.route.js deleted file mode 100644 index 53869691a73f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/lookup/sources-lookup-project.route.js +++ /dev/null @@ -1,51 +0,0 @@ -export default { - params: { - project_search: { - value: { - page_size:"5", - order_by:"name", - not__status:"never updated", - role_level:"use_role", - }, - dynamic:true, - squash:"" - } - }, - data: { - basePath:"projects", - formChildState:true - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'modal': { - templateProvider: function(ListDefinition, generateList) { - let list_html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - return `${list_html}`; - - } - } - }, - resolve: { - ListDefinition: ['ProjectList', function(list) { - return list; - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - return qs.search(GetBasePath('projects'), $stateParams[`${list.iterator}_search`]); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/main.js deleted file mode 100644 index 51eafc26c66f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/main.js +++ /dev/null @@ -1,30 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import sourcesList from './list/main'; -import sourcesAdd from './add/main'; -import sourcesEdit from './edit/main'; -import sourcesFormDefinition from './sources.form'; -import sourcesListDefinition from './sources.list'; -import service from './sources.service'; -import GetSyncStatusMsg from './factories/get-sync-status-msg.factory'; -import ViewUpdateStatus from './factories/view-update-status.factory'; -import CancelSourceUpdate from './factories/cancel-source-update.factory'; -import GetSourceTypeOptions from './factories/get-source-type-options.factory'; - -export default - angular.module('sources', [ - sourcesList.name, - sourcesAdd.name, - sourcesEdit.name - ]) - .factory('SourcesFormDefinition', sourcesFormDefinition) - .factory('SourcesListDefinition', sourcesListDefinition) - .factory('GetSyncStatusMsg', GetSyncStatusMsg) - .factory('ViewUpdateStatus', ViewUpdateStatus) - .factory('CancelSourceUpdate', CancelSourceUpdate) - .factory('GetSourceTypeOptions', GetSourceTypeOptions) - .service('SourcesService', service); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js deleted file mode 100644 index 89299827b9bb..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js +++ /dev/null @@ -1,424 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Groups - * @description This form is for adding/editing a Group on the inventory page -*/ - -export default ['NotificationsList', 'i18n', function(NotificationsList, i18n){ - - var notifications_object = { - name: 'notifications', - index: false, - basePath: "notifications", - include: "NotificationsList", - title: i18n._('Notifications'), - iterator: 'notification', - ngIf: "!(inventory_source_obj.source === undefined || inventory_source_obj.source === '')", - generateList: true, - ngClick: "$state.go('inventories.edit.inventory_sources.edit.notifications')" - // search: { - // "or__job__inventory": '' - // } - }; - let clone = _.clone(NotificationsList); - notifications_object = angular.extend(clone, notifications_object); -return { - addTitle: i18n._('CREATE SOURCE'), - editTitle: '{{ name }}', - showTitle: true, - name: 'inventory_source', - basePath: 'inventory_sources', - parent: 'inventories.edit.sources', - // the parent node this generated state definition tree expects to attach to - stateTree: 'inventories', - tabs: true, - // form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab - // this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit - activeEditState: 'inventories.edit.inventory_sources.edit', - detailsClick: "$state.go('inventories.edit.inventory_sources.edit')", - well: false, - subFormTitles: { - sourceSubForm: i18n._('Source Details'), - }, - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - tab: 'properties' - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - tab: 'properties' - }, - source: { - label: i18n._('Source'), - type: 'select', - required: true, - ngOptions: 'source.label for source in source_type_options track by source.value', - ngChange: 'sourceChange(source)', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - ngModel: 'source', - hasSubForm: true - }, - credential: { - label: i18n._('Credential'), - type: 'lookup', - list: 'CredentialList', - basePath: 'credentials', - ngShow: "source && source.value !== ''", - sourceModel: 'credential', - sourceField: 'name', - ngClick: 'lookupCredential()', - awRequiredWhen: { - reqExpression: "cloudCredentialRequired", - init: "false" - }, - subForm: 'sourceSubForm', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - watchBasePath: "credentialBasePath" - }, - project: { - // initializes a default value for this search param - // search params with default values set will not generate user-interactable search tags - label: i18n._('Project'), - type: 'lookup', - list: 'ProjectList', - basePath: 'projects', - ngShow: "source && source.value === 'scm'", - sourceModel: 'project', - sourceField: 'name', - ngClick: 'lookupProject()', - awRequiredWhen: { - reqExpression: "source && source.value === 'scm'", - init: "false" - }, - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - watchBasePath: "projectBasePath", - subForm: 'sourceSubForm' - }, - inventory_file: { - label: i18n._('Inventory File'), - type:'select', - defaultText: i18n._('Choose an inventory file'), - ngOptions: 'file for file in inventory_files track by file', - ngShow: "source && source.value === 'scm'", - ngDisabled: "!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd) || disableInventoryFileBecausePermissionDenied", - id: 'inventory-file-select', - awRequiredWhen: { - reqExpression: "source && source.value === 'scm'", - init: "true" - }, - column: 1, - awPopOver: "

" + i18n._("Select the inventory file to be synced by this source. " + - "You can select from the dropdown or enter a file within the input.") + "

", - dataTitle: i18n._('Inventory File'), - dataPlacement: 'right', - dataContainer: "body", - includeInventoryFileNotFoundError: true, - subForm: 'sourceSubForm' - }, - source_regions: { - label: i18n._('Regions'), - type: 'select', - ngOptions: 'source.label for source in source_region_choices track by source.value', - multiSelect: true, - ngShow: "source && (source.value == 'rax' || source.value == 'ec2' || source.value == 'gce' || source.value == 'azure_rm')", - dataTitle: i18n._('Source Regions'), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, or choose") + - "" + i18n._("All") + " " + i18n._("to include all regions. Only Hosts associated with the selected regions will be updated.") + "

", - dataContainer: 'body', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - instance_filters: { - label: i18n._("Instance Filters"), - type: 'text', - ngShow: "source && (source.value == 'ec2' || source.value == 'vmware' || source.value == 'tower')", - dataTitle: i18n._('Instance Filters'), - dataPlacement: 'right', - awPopOverWatch: 'instanceFilterPopOver', - awPopOver: '{{ instanceFilterPopOver }}', - dataContainer: 'body', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - group_by: { - label: i18n._('Only Group By'), - type: 'select', - ngShow: "source && (source.value == 'ec2' || source.value == 'vmware')", - ngOptions: 'source.label for source in group_by_choices track by source.value', - multiSelect: true, - dataTitle: i18n._("Only Group By"), - dataPlacement: 'right', - awPopOverWatch: 'groupByPopOver', - awPopOver: '{{ groupByPopOver }}', - dataContainer: 'body', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - inventory_script: { - label : i18n._("Custom Inventory Script"), - type: 'lookup', - basePath: 'inventory_scripts', - list: 'InventoryScriptsList', - ngShow: "source && source.value === 'custom'", - sourceModel: 'inventory_script', - sourceField: 'name', - awRequiredWhen: { - reqExpression: "source && source.value === 'custom'", - init: "false" - }, - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - custom_variables: { - id: 'custom_variables', - label: i18n._('Environment Variables'), //"{{vars_label}}" , - ngShow: "source && source.value=='custom' || source.value === 'scm'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Environment Variables"), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Provide environment variables to pass to the custom inventory script.") + "

" + - "

" + i18n._("Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - i18n._("JSON:") + "
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - i18n._("YAML:") + "
\n" + - "
---
somevar: somevalue
password: magic
\n" + - "

" + i18n._("View JSON examples at ") + 'www.json.org

' + - "

" + i18n._("View YAML examples at ") + 'docs.ansible.com

', - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - ec2_variables: { - id: 'ec2_variables', - label: i18n._('Source Variables'), //"{{vars_label}}" , - ngShow: "source && source.value == 'ec2'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Source Variables"), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables ") + - "" + - i18n._("view ec2.ini in the Ansible github repo.") + "

" + - "

" + i18n._("Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - i18n._("JSON:") + "
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - i18n._("YAML:") + "
\n" + - "
---
somevar: somevalue
password: magic
\n" + - "

" + i18n._("View JSON examples at ") + 'www.json.org

' + - "

" + i18n._("View YAML examples at ") + 'docs.ansible.com

', - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - vmware_variables: { - id: 'vmware_variables', - label: i18n._('Source Variables'), //"{{vars_label}}" , - ngShow: "source && source.value == 'vmware'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Source Variables"), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Override variables found in vmware.ini and used by the inventory update script. For a detailed description of these variables ") + - "" + - i18n._("view vmware_inventory.ini in the Ansible github repo.") + "

" + - "

" + i18n._("Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - i18n._("JSON:") + "
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - i18n._("YAML:") + "
\n" + - "
---
somevar: somevalue
password: magic
\n" + - "

" + i18n._("View JSON examples at ") + 'www.json.org

' + - "

" + i18n._("View YAML examples at ") + 'docs.ansible.com

', - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - openstack_variables: { - id: 'openstack_variables', - label: i18n._('Source Variables'), //"{{vars_label}}" , - ngShow: "source && source.value == 'openstack'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Source Variables"), - dataPlacement: 'right', - awPopOver: i18n._(`Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration - - view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.`), - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - cloudforms_variables: { - id: 'cloudforms_variables', - label: i18n._('Source Variables'), - ngShow: "source && source.value == 'cloudforms'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Source Variables"), - dataPlacement: 'right', - awPopOver: i18n._(`Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration - - view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.`), - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - satellite6_variables: { - id: 'satellite6_variables', - label: i18n._('Source Variables'), - ngShow: "source && source.value == 'satellite6'", - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - 'default': '---', - parseTypeName: 'envParseType', - dataTitle: i18n._("Source Variables"), - dataPlacement: 'right', - awPopOver: i18n._(`Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration - - view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.`), - dataContainer: 'body', - subForm: 'sourceSubForm' - }, - verbosity: { - label: i18n._('Verbosity'), - type: 'select', - ngOptions: 'v.label for v in verbosity_options track by v.value', - ngShow: "source && (source.value !== '' && source.value !== null)", - disableChooseOption: true, - column: 1, - awPopOver: "

" + i18n._("Control the level of output ansible will produce for inventory source update jobs.") + "

", - dataTitle: i18n._('Verbosity'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - checkbox_group: { - label: i18n._('Update Options'), - type: 'checkbox_group', - ngShow: "source && (source.value !== '' && source.value !== null)", - class: 'Form-checkbox--stacked', - subForm: 'sourceSubForm', - fields: [{ - name: 'overwrite', - label: i18n._('Overwrite'), - type: 'checkbox', - ngShow: "source.value !== '' && source.value !== null", - awPopOver: "

" + i18n._("If checked, any hosts and groups that were previously present on the external source but are now removed will be removed from the Tower inventory. Hosts and groups that were not managed by the inventory source will be promoted to the next manually created group or if there is no manually created group to promote them into, they will be left in the \"all\" default group for the inventory.") + '

' + - i18n._("When not checked, local child hosts and groups not found on the external source will remain untouched by the inventory update process.") + "

", - dataTitle: i18n._('Overwrite'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options', - ngDisabled: "(!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd))" - }, { - name: 'overwrite_vars', - label: i18n._('Overwrite Variables'), - type: 'checkbox', - ngShow: "source.value !== '' && source.value !== null", - awPopOver: "

" + i18n._("If checked, all variables for child groups and hosts will be removed and replaced by those found on the external source.") + '

' + - i18n._("When not checked, a merge will be performed, combining local variables with those found on the external source.") + "

", - dataTitle: i18n._('Overwrite Variables'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options', - ngDisabled: "(!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd) || source.value === 'scm')" - }, { - name: 'update_on_launch', - label: i18n._('Update on Launch'), - type: 'checkbox', - ngShow: "source.value !== '' && source.value !== null", - awPopOver: "

" + i18n._("Each time a job runs using this inventory, " + - "refresh the inventory from the selected source before executing job tasks.") + "

", - dataTitle: i18n._('Update on Launch'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' - }, { - name: 'update_on_project_update', - label: i18n._('Update on Project Change'), - type: 'checkbox', - ngShow: "source.value === 'scm'", - awPopOver: "

" + i18n._("After every project update where the SCM revision changes, " + - "refresh the inventory from the selected source before executing job tasks. " + - "This is intended for static content, like the Ansible inventory .ini file format.") + "

", - dataTitle: i18n._('Update on Project Update'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' - }] - }, - update_cache_timeout: { - label: i18n._("Cache Timeout") + " " + i18n._("(seconds)") + "", - id: 'source-cache-timeout', - type: 'number', - ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)', - integer: true, - min: 0, - ngShow: "source && source.value !== '' && update_on_launch", - spinner: true, - "default": 0, - awPopOver: "

" + i18n._("Time in seconds to consider an inventory sync to be current. " + - "During job runs and callbacks the task system will evaluate the timestamp of the latest sync. " + - "If it is older than Cache Timeout, it is not considered current, and a new inventory sync will be performed.") + "

", - dataTitle: i18n._('Cache Timeout'), - dataPlacement: 'right', - dataContainer: "body", - subForm: 'sourceSubForm' - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - notifications: notifications_object, - schedules: { - title: i18n._('Schedules'), - skipGenerator: true, - ngClick: "$state.go('inventories.edit.inventory_sources.edit.schedules')" - } - } - -}; - -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.list.js deleted file mode 100644 index 8fdf58bec251..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.list.js +++ /dev/null @@ -1,131 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['i18n', function(i18n) { - return { - name: 'inventory_sources', - iterator: 'inventory_source', - editTitle: '{{ inventory_source.name }}', - well: true, - wellOverride: true, - index: false, - hover: true, - trackBy: 'inventory_source.id', - basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/inventory_sources/', - - fields: { - sync_status: { - label: '', - nosort: true, - mode: 'all', - iconOnly: true, - ngClick: 'viewUpdateStatus(inventory_source.id)', - awToolTip: "{{ inventory_source.status_tooltip }}", - dataTipWatch: "inventory_source.status_tooltip", - icon: "{{ 'fa icon-cloud-' + inventory_source.status_class }}", - ngClass: "inventory_source.status_class", - dataPlacement: "top", - columnClass: 'status-column List-staticColumn--smallStatus' - }, - name: { - label: i18n._('Sources'), - key: true, - uiSref: "inventories.edit.inventory_sources.edit({inventory_source_id:inventory_source.id})", - columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', - class: 'InventoryManage-breakWord', - }, - source: { - label: i18n._('Type'), - ngBind: 'inventory_source.source_label', - columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4' - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshGroups()", - ngShow: "socketStatus == 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - sync_all: { - mode: 'all', - awToolTip: i18n._("Sync all inventory sources"), - ngClick: "syncAllSources()", - ngShow: "showSyncAll", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('SYNC ALL'), - dataPlacement: "top" - }, - create: { - mode: 'all', - ngClick: "createSource()", - awToolTip: i18n._("Create a new source"), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd', - dataPlacement: "top", - } - }, - - fieldActions: { - - columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4 text-right', - - edit: { - mode: 'all', - ngClick: "editSource(inventory_source.id)", - awToolTip: i18n._('Edit source'), - dataPlacement: "top", - ngShow: "inventory_source.summary_fields.user_capabilities.edit" - }, - source_update: { - mode: 'all', - ngClick: 'updateSource(inventory_source)', - awToolTip: "{{ inventory_source.launch_tooltip }}", - dataTipWatch: "inventory_source.launch_tooltip", - ngShow: "(inventory_source.status !== 'running' && inventory_source.status " + - "!== 'pending' && inventory_source.status !== 'updating') && inventory_source.summary_fields.user_capabilities.start", - ngClass: "inventory_source.launch_class", - dataPlacement: "top", - }, - cancel: { - mode: 'all', - ngClick: "cancelUpdate(inventory_source.id)", - awToolTip: i18n._("Cancel sync process"), - 'class': 'red-txt', - ngShow: "(inventory_source.status == 'running' || inventory_source.status == 'pending' " + - "|| inventory_source.status == 'updating') && inventory_source.summary_fields.user_capabilities.start", - dataPlacement: "top", - iconClass: "fa fa-minus-circle" - }, - schedule: { - mode: 'all', - ngClick: "scheduleSource(inventory_source.id)", - awToolTip: "{{ inventory_source.group_schedule_tooltip }}", - ngClass: "inventory_source.scm_type_class", - dataPlacement: 'top', - ngShow: "!(inventory_source.summary_fields.inventory_source.source === '') && inventory_source.summary_fields.user_capabilities.schedule" - }, - view: { - mode: 'all', - ngClick: "editSource(inventory_source.id)", - awToolTip: i18n._('View source'), - dataPlacement: "top", - ngShow: "!inventory_source.summary_fields.user_capabilities.edit" - }, - "delete": { - mode: 'all', - ngClick: "deleteSource(inventory_source)", - awToolTip: i18n._('Delete source'), - dataPlacement: "top", - ngShow: "inventory_source.summary_fields.user_capabilities.delete" - } - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js deleted file mode 100644 index ce65a7dae52f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js +++ /dev/null @@ -1,154 +0,0 @@ -export default -['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ - return { - stringifyParams: function(params){ - return _.reduce(params, (result, value, key) => { - return result + key + '=' + value + '&'; - }, ''); - }, - // cute abstractions via fn.bind() - url: function(){ - return ''; - }, - error: function(data) { - ProcessErrors($rootScope, data.data, data.status, null, { hdr: 'Error!', - msg: 'Call to ' + this.url + '. GET returned: ' + data.status }); - }, - success: function(data){ - return data; - }, - // HTTP methods - get: function(params){ - Wait('start'); - this.url = GetBasePath('inventory_sources') + '?' + this.stringifyParams(params); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - post: function(inventory_source){ - Wait('start'); - this.url = GetBasePath('inventory_sources'); - Rest.setUrl(this.url); - return Rest.post(inventory_source) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - put: function(inventory_source){ - Wait('start'); - this.url = GetBasePath('inventory_sources') + inventory_source.id; - Rest.setUrl(this.url); - return Rest.put(inventory_source) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - delete: function(id){ - Wait('start'); - this.url = GetBasePath('inventory_sources') + id; - Rest.setUrl(this.url); - return Rest.destroy() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - options: function(){ - this.url = GetBasePath('inventory_sources'); - Rest.setUrl(this.url); - return Rest.options() - .then(this.success.bind(this)) - .catch(this.error.bind(this)); - }, - getCredential: function(id){ - Wait('start'); - this.url = GetBasePath('credentials') + id; - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - getInventorySource: function(params){ - Wait('start'); - this.url = GetBasePath('inventory_sources') + '?' + this.stringifyParams(params); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - putInventorySource: function(params, url){ - Wait('start'); - this.url = url; - Rest.setUrl(this.url); - return Rest.put(params) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level - associateGroup: function(group, target){ - Wait('start'); - this.url = GetBasePath('groups') + target + '/children/'; - Rest.setUrl(this.url); - return Rest.post(group) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - disassociateGroup: function(group, parent){ - Wait('start'); - this.url = GetBasePath('groups') + parent + '/children/'; - Rest.setUrl(this.url); - return Rest.post({id: group, disassociate: 1}) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - promote: function(group, inventory){ - Wait('start'); - this.url = GetBasePath('inventory') + inventory + '/groups/'; - Rest.setUrl(this.url); - return Rest.post({id: group, disassociate: 1}) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - encodeGroupBy(source, group_by){ - source = source && source.value ? source.value : ''; - if(source === 'ec2'){ - return _.map(group_by, 'value').join(','); - } - - if(source === 'vmware'){ - group_by = _.map(group_by, (i) => {return i.value;}); - $("#inventory_source_group_by").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ - group_by.push(option.title); - }); - group_by = (Array.isArray(group_by)) ? _.uniq(group_by).join() : ""; - return group_by; - } - else { - return; - } - }, - deleteHosts(id) { - this.url = GetBasePath('inventory_sources') + id + '/hosts/'; - Rest.setUrl(this.url); - return Rest.destroy() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(); - }, - deleteGroups(id) { - this.url = GetBasePath('inventory_sources') + id + '/groups/'; - Rest.setUrl(this.url); - return Rest.destroy() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(); - } - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/main.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/main.js deleted file mode 100644 index 911492557f47..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './smart-inventory-add.controller'; - -export default -angular.module('smartInventoryAdd', []) - .controller('SmartInventoryAddController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js deleted file mode 100644 index 1f21e3844f03..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js +++ /dev/null @@ -1,102 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Inventories - * @description This controller's for the Inventory page - */ - -function SmartInventoryAdd($scope, $location, - GenerateForm, smartInventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, - GetBasePath, ParseTypeChange, Wait, ToJSON, - $state, canAdd, InstanceGroupsService) { - - $scope.canAdd = canAdd; - - // Inject dynamic view - var defaultUrl = GetBasePath('inventory'), - form = smartInventoryForm; - - init(); - - function init() { - $scope.canEditOrg = true; - form.formLabelSize = null; - form.formFieldSize = null; - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - $scope.parseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - variable: 'smartinventory_variables', - parse_variable: 'parseType', - field_id: 'smartinventory_smartinventory_variables' - }); - - $scope.smart_hosts = $state.params.hostfilter ? JSON.parse($state.params.hostfilter) : ''; - } - - // Save - $scope.formSave = function() { - Wait('start'); - try { - let fld, data = {}; - - for (fld in form.fields) { - data[fld] = $scope[fld]; - } - - data.variables = ToJSON($scope.parseType, $scope.smartinventory_variables, true); - - data.host_filter = decodeURIComponent($scope.smart_hosts.host_filter); - - data.kind = "smart"; - - Rest.setUrl(defaultUrl); - Rest.post(data) - .then(({data}) => { - const inventory_id = data.id, - instance_group_url = data.related.instance_groups; - - InstanceGroupsService.addInstanceGroups(instance_group_url, $scope.instance_groups) - .then(() => { - Wait('stop'); - $state.go('inventories.editSmartInventory', {smartinventory_id: inventory_id}, {reload: true}); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to post instance groups. POST returned ' + - 'status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new inventory. Post returned status: ' + status - }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error parsing inventory variables. Parser returned: " + err); - } - - }; - - $scope.formCancel = function() { - $state.go('inventories'); - }; -} - -export default ['$scope', '$location', - 'GenerateForm', 'smartInventoryForm', 'rbacUiControlService', 'Rest', 'Alert', - 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', - 'Wait', 'ToJSON', '$state', 'canAdd', 'InstanceGroupsService', SmartInventoryAdd -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/main.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/main.js deleted file mode 100644 index b5c59c9e6d82..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './smart-inventory-edit.controller'; - -export default -angular.module('smartInventoryEdit', []) - .controller('SmartInventoryEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js deleted file mode 100644 index 7af348d0d14a..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js +++ /dev/null @@ -1,110 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -function SmartInventoryEdit($scope, $location, - $stateParams, InventoryForm, Rest, ProcessErrors, - GetBasePath, ParseTypeChange, Wait, ToJSON, - ParseVariableString, $state, OrgAdminLookup, resourceData, - $rootScope, InstanceGroupsService, InstanceGroupsData) { - - // Inject dynamic view - var defaultUrl = GetBasePath('inventory'), - form = InventoryForm, - inventory_id = $stateParams.smartinventory_id, - inventoryData = resourceData.data, - instance_group_url = inventoryData.related.instance_groups; - init(); - - function init() { - form.formLabelSize = null; - form.formFieldSize = null; - $scope.inventory_id = inventory_id; - - $scope = angular.extend($scope, inventoryData); - - $scope.smartinventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables); - $scope.organization_name = inventoryData.summary_fields.organization.name; - $scope.instance_groups = InstanceGroupsData; - - $scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAdd = false; - } - }); - - $scope.parseType = 'yaml'; - - - ParseTypeChange({ - scope: $scope, - variable: 'smartinventory_variables', - parse_variable: 'parseType', - field_id: 'smartinventory_smartinventory_variables' - }); - - OrgAdminLookup.checkForAdminAccess({organization: inventoryData.organization}) - .then(function(canEditOrg){ - $scope.canEditOrg = canEditOrg; - }); - - $scope.inventory_obj = inventoryData; - $rootScope.breadcrumb.inventory_name = inventoryData.name; - - $scope.smart_hosts = { - host_filter: encodeURIComponent($scope.host_filter) - }; - } - - // Save - $scope.formSave = function() { - Wait('start'); - - let fld, data = {}; - - for (fld in form.fields) { - data[fld] = $scope[fld]; - } - - data.variables = ToJSON($scope.parseType, $scope.smartinventory_variables, true); - data.host_filter = decodeURIComponent($scope.smart_hosts.host_filter); - data.kind = "smart"; - - Rest.setUrl(defaultUrl + inventory_id + '/'); - Rest.put(data) - .then(() => { - InstanceGroupsService.editInstanceGroups(instance_group_url, $scope.instance_groups) - .then(() => { - Wait('stop'); - $state.go($state.current, {}, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update instance groups. POST returned status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update inventory. PUT returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('inventories'); - }; - -} - -export default [ '$scope', '$location', - '$stateParams', 'InventoryForm', 'Rest', - 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'Wait', - 'ToJSON', 'ParseVariableString', - '$state', 'OrgAdminLookup', 'resourceData', - '$rootScope', 'InstanceGroupsService', 'InstanceGroupsData', SmartInventoryEdit -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js deleted file mode 100644 index 0f8a57560f47..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js +++ /dev/null @@ -1,20 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import smartInventoryAdd from './add/main'; -import smartInventoryEdit from './edit/main'; -import smartInventoryForm from './smart-inventory.form'; -import smartInventoryHostFilter from './smart-inventory-host-filter/smart-inventory-host-filter.directive'; -import hostFilterModal from './smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive'; - -export default -angular.module('smartInventory', [ - smartInventoryAdd.name, - smartInventoryEdit.name - ]) - .factory('smartInventoryForm', smartInventoryForm) - .directive('smartInventoryHostFilter', smartInventoryHostFilter) - .directive('hostFilterModal', hostFilterModal); diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive.js deleted file mode 100644 index 4f6bc0c15d15..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive.js +++ /dev/null @@ -1,89 +0,0 @@ -export default ['templateUrl', function(templateUrl) { - return { - restrict: 'E', - scope: { - hostFilter: '=', - organization: '=' - }, - templateUrl: templateUrl('inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal'), - link: function(scope, element) { - - $('#host-filter-modal').on('hidden.bs.modal', function () { - $('#host-filter-modal').off('hidden.bs.modal'); - $(element).remove(); - }); - - scope.showModal = function() { - $('#host-filter-modal').modal('show'); - }; - - scope.destroyModal = function() { - $('#host-filter-modal').modal('hide'); - }; - - }, - controller: ['$scope', 'QuerySet', 'GetBasePath', 'HostsList', '$compile', 'generateList', function($scope, qs, GetBasePath, HostsList, $compile, GenerateList) { - - function init() { - - $scope.host_default_params = { - order_by: 'name', - page_size: 5, - inventory__organization: $scope.organization - }; - - $scope.host_queryset = _.merge({ - order_by: 'name', - page_size: 5, - inventory__organization: $scope.organization - }, $scope.hostFilter ? $scope.hostFilter : {}); - - // Fire off the initial search - qs.search(GetBasePath('hosts'), $scope.host_queryset) - .then(res => { - $scope.host_dataset = res.data; - $scope.hosts = $scope.host_dataset.results; - - let hostList = _.cloneDeep(HostsList); - delete hostList.fields.toggleHost; - delete hostList.fields.active_failures; - delete hostList.fields.name.ngClick; - hostList.fields.name.class += " HostFilterModal-tableRow"; - hostList.fields.name.noLink = true; - hostList.well = false; - delete hostList.fields.inventory.ngClick; - hostList.fields.inventory.ngBind = 'host.summary_fields.inventory.name'; - hostList.emptyListText = 'You must have access to at least one host in order to create a smart inventory host filter'; - let html = GenerateList.build({ - list: hostList, - input_type: 'host-filter-modal-body', - hideViewPerPage: true - }); - - $scope.list = hostList; - - $('#host-filter-modal-body').append($compile(html)($scope)); - - $scope.showModal(); - }); - } - - init(); - - $scope.cancelForm = function() { - $scope.destroyModal(); - }; - - $scope.saveForm = function() { - // Strip defaults out of the state params copy - angular.forEach(Object.keys($scope.host_default_params), function(value) { - delete $scope.host_queryset[value]; - }); - - $scope.hostFilter = angular.copy($scope.host_queryset); - - $scope.destroyModal(); - }; - }] - }; -}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html deleted file mode 100644 index e0b6d7fef230..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js deleted file mode 100644 index 1c28668debc2..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', 'QuerySet', 'InventoryHostsStrings', - function($scope, qs, InventoryHostsStrings) { - $scope.hostFilterTags = []; - - $scope.$watch('organization', function(){ - if($scope.hasEditPermissions) { - $scope.filterTooltip = $scope.organization ? InventoryHostsStrings.get('smartinventories.hostfilter.INSTRUCTIONS') : InventoryHostsStrings.get('smartinventories.hostfilter.MISSING_ORG'); - } - else { - $scope.filterTooltip = InventoryHostsStrings.get('smartinventories.hostfilter.MISSING_PERMISSIONS'); - } - }); - - $scope.$watch('hostFilter', function(){ - $scope.hostFilterTags = []; - - if($scope.hostFilter && $scope.hostFilter !== '') { - let hostFilterCopy = angular.copy($scope.hostFilter); - - let searchParam = hostFilterCopy.host_filter.split('%20and%20'); - delete hostFilterCopy.host_filter; - - $.each(searchParam, function(index, param) { - let paramParts = decodeURIComponent(param).split(/=(.+)/); - $scope.hostFilterTags.push(qs.decodeParam(paramParts[1], paramParts[0])); - }); - - $scope.hostFilterTags = $scope.hostFilterTags.concat(qs.stripDefaultParams(hostFilterCopy)); - } - }); - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.directive.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.directive.js deleted file mode 100644 index dd60d0e736a3..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.directive.js +++ /dev/null @@ -1,27 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import smartInventoryHostFilterController from './smart-inventory-host-filter.controller'; - -export default ['templateUrl', '$compile', - function(templateUrl, $compile) { - return { - scope: { - hostFilter: '=', - hasEditPermissions: '=', - organization: '=' - }, - restrict: 'E', - templateUrl: templateUrl('inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter'), - controller: smartInventoryHostFilterController, - link: function(scope) { - scope.openHostFilterModal = function() { - $('#content-container').append($compile('')(scope)); - }; - } - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html deleted file mode 100644 index 8e697dbe3742..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html +++ /dev/null @@ -1,13 +0,0 @@ -
- - - - - - {{tag}} - - -
- diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js deleted file mode 100644 index af5768aacc11..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js +++ /dev/null @@ -1,69 +0,0 @@ -import { N_ } from '../../../i18n'; - -export default { - name: "inventories.editSmartInventory.hosts", - url: "/hosts?{host_search:queryset}", - params: { - host_search: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash:"" - } - }, - ncyBreadcrumb: { - label: N_("HOSTS") - }, - views: { - 'related': { - templateProvider: function(ListDefinition, generateList) { - let list = _.cloneDeep(ListDefinition); - let html = generateList.build({ - list: list, - mode: 'edit' - }); - return html; - }, - controller: 'RelatedHostListController' - } - }, - resolve: { - ListDefinition: ['RelatedHostsListDefinition', '$stateParams', 'GetBasePath', (RelatedHostsListDefinition, $stateParams, GetBasePath) => { - let list = _.cloneDeep(RelatedHostsListDefinition); - list.basePath = GetBasePath('inventory') + $stateParams.smartinventory_id + '/hosts'; - delete list.actions.create; - delete list.fields.groups; - delete list.fieldActions.delete; - delete list.fieldActions.edit; - delete list.fieldActions.view.ngShow; - list.fields.toggleHost.ngDisabled = true; - list.fields.name.columnClass = 'col-lg-8 col-md-11 col-sm-8 col-xs-7'; - return list; - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - hostsUrl: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.rootHostsUrl($stateParams.smartinventory_id); - }], - hostsDataset: ['ListDefinition', 'QuerySet', '$stateParams', 'hostsUrl', (list, qs, $stateParams, hostsUrl) => { - let path = hostsUrl; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - }], - inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) { - return InventoriesService.getInventory($stateParams.smartinventory_id).then(res => res.data); - }] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js deleted file mode 100644 index 01a49b008b4e..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js +++ /dev/null @@ -1,162 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW SMART INVENTORY'), - editTitle: '{{ name }}', - name: 'smartinventory', - basePath: 'inventory', - breadcrumbName: i18n._('SMART INVENTORY'), - stateTree: 'inventories', - activeEditState: 'inventories.editSmartInventory', - detailsClick: "$state.go('inventories.editSmartInventory')", - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - required: true, - capitalize: false, - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - basePath: 'organizations', - list: 'OrganizationList', - sourceModel: 'organization', - sourceField: 'name', - required: true, - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', - awLookupWhen: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg' - }, - smart_hosts: { - label: i18n._('Smart Host Filter'), - type: 'custom', - control: '', - awPopOver: "

" + i18n._("Populate the hosts for this inventory by using a search filter.") + "

" + i18n._("Example: ansible_facts.ansible_distribution:\"RedHat\"") + "

" + i18n._("Refer to the Ansible Tower documentation for further syntax and examples.") + "

", - dataTitle: i18n._('Smart Host Filter'), - dataPlacement: 'right', - dataContainer: 'body', - required: true - }, - instance_groups: { - label: i18n._('Instance Groups'), - type: 'custom', - awPopOver: "

" + i18n._("Select the Instance Groups for this Inventory to run on.") + "

", - dataTitle: i18n._('Instance Groups'), - dataPlacement: 'right', - dataContainer: 'body', - control: '', - }, - smartinventory_variables: { - label: i18n._('Variables'), - type: 'textarea', - class: 'Form-formGroup--fullWidth', - rows: 6, - "default": "---", - awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Inventory Variables'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - related: { - permissions: { - name: 'permissions', - awToolTip: i18n._('Please save before assigning permissions.'), - dataPlacement: 'top', - basePath: 'api/v2/inventories/{{$stateParams.smartinventory_id}}/access_list/', - type: 'collection', - title: i18n._('Permissions'), - iterator: 'permission', - index: false, - open: false, - search: { - order_by: 'username' - }, - actions: { - add: { - label: i18n._('Add'), - ngClick: "$state.go('.add')", - awToolTip: i18n._('Add a permission'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - - } - }, - fields: { - username: { - key: true, - label: i18n._('User'), - linkBase: 'users', - class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' - }, - role: { - label: i18n._('Role'), - type: 'role', - nosort: true, - class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', - }, - team_roles: { - label: i18n._('Team Roles'), - type: 'team_roles', - nosort: true, - class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4', - } - }, - ngClick: "$state.go('inventories.editSmartInventory.permissions');" - }, - hosts: { - name: 'hosts', - awToolTip: i18n._('Please save before viewing hosts.'), - dataPlacement: 'top', - include: "RelatedHostsListDefinition", - title: i18n._('Hosts'), - iterator: 'host', - ngClick: "$state.go('inventories.editSmartInventory.hosts');", - skipGenerator: true - }, - completed_jobs: { - title: i18n._('Completed Jobs'), - skipGenerator: true, - ngClick: "$state.go('inventories.editSmartInventory.completed_jobs')" - } - } - - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/inventory-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/inventory-add.controller.js deleted file mode 100644 index 5d332b80f007..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/inventory-add.controller.js +++ /dev/null @@ -1,99 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Inventories - * @description This controller's for the Inventory page - */ - -function InventoriesAdd($scope, $location, - GenerateForm, InventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, - GetBasePath, ParseTypeChange, Wait, ToJSON, - $state, canAdd, CreateSelect2, InstanceGroupsService) { - - $scope.canAdd = canAdd; - - // Inject dynamic view - var defaultUrl = GetBasePath('inventory'), - form = InventoryForm; - - init(); - - function init() { - $scope.canEditOrg = true; - form.formLabelSize = null; - form.formFieldSize = null; - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - $scope.parseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - variable: 'inventory_variables', - parse_variable: 'parseType', - field_id: 'inventory_inventory_variables' - }); - } - - // Save - $scope.formSave = function() { - Wait('start'); - try { - var fld, data; - - data = {}; - for (fld in form.fields) { - if (form.fields[fld].realName) { - data[form.fields[fld].realName] = $scope[fld]; - } else { - data[fld] = $scope[fld]; - } - } - - Rest.setUrl(defaultUrl); - Rest.post(data) - .then(({data}) => { - const inventory_id = data.id, - instance_group_url = data.related.instance_groups; - - InstanceGroupsService.addInstanceGroups(instance_group_url, $scope.instance_groups) - .then(() => { - Wait('stop'); - $state.go('inventories.edit', {inventory_id: inventory_id}, {reload: true}); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to post instance groups. POST returned ' + - 'status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new inventory. Post returned status: ' + status - }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error parsing inventory variables. Parser returned: " + err); - } - - }; - - $scope.formCancel = function() { - $state.go('inventories'); - }; -} - -export default ['$scope', '$location', - 'GenerateForm', 'InventoryForm', 'rbacUiControlService', 'Rest', 'Alert', - 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', - 'Wait', 'ToJSON', '$state','canAdd', 'CreateSelect2', 'InstanceGroupsService', InventoriesAdd -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/main.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/main.js deleted file mode 100644 index 2e477aa96c1f..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './inventory-add.controller'; - -export default -angular.module('InventoryAdd', []) - .controller('InventoryAddController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js deleted file mode 100644 index 8f96ae9f6fd0..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js +++ /dev/null @@ -1,119 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Inventories - * @description This controller's for the Inventory page - */ - -function InventoriesEdit($scope, $location, - $stateParams, InventoryForm, Rest, ProcessErrors, - GetBasePath, ParseTypeChange, Wait, ToJSON, - ParseVariableString, $state, OrgAdminLookup, $rootScope, resourceData, - CreateSelect2, InstanceGroupsService, InstanceGroupsData, CanRemediate) { - - // Inject dynamic view - let defaultUrl = GetBasePath('inventory'), - form = InventoryForm, - fld, data, - inventoryData = resourceData.data, - instance_group_url = inventoryData.related.instance_groups; - - init(); - - function init() { - form.formLabelSize = null; - form.formFieldSize = null; - - $scope = angular.extend($scope, inventoryData); - - $scope.insights_credential_name = (inventoryData.summary_fields.insights_credential && inventoryData.summary_fields.insights_credential.name) ? inventoryData.summary_fields.insights_credential.name : null; - $scope.insights_credential = (inventoryData.summary_fields.insights_credential && inventoryData.summary_fields.insights_credential.id) ? inventoryData.summary_fields.insights_credential.id : null; - $scope.is_insights = (inventoryData.summary_fields.insights_credential && inventoryData.summary_fields.insights_credential.id) ? true : false; - $scope.organization_name = inventoryData.summary_fields.organization.name; - $scope.inventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables); - $scope.parseType = 'yaml'; - $scope.instance_groups = InstanceGroupsData; - $scope.canRemediate = CanRemediate; - - ParseTypeChange({ - scope: $scope, - variable: 'inventory_variables', - parse_variable: 'parseType', - field_id: 'inventory_inventory_variables' - }); - - OrgAdminLookup.checkForRoleLevelAdminAccess(inventoryData.organization, 'inventory_admin_role') - .then(function(canEditOrg){ - $scope.canEditOrg = canEditOrg; - }); - - $scope.inventory_obj = inventoryData; - $scope.inventory_name = inventoryData.name; - $rootScope.breadcrumb.inventory_name = inventoryData.name; - - $scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAdd = false; - } - }); - } - - // Save - $scope.formSave = function() { - Wait('start'); - - data = {}; - for (fld in form.fields) { - if (form.fields[fld].realName) { - data[form.fields[fld].realName] = $scope[fld]; - } else { - data[fld] = $scope[fld]; - } - } - - Rest.setUrl(defaultUrl + $stateParams.inventory_id + '/'); - Rest.put(data) - .then(() => { - InstanceGroupsService.editInstanceGroups(instance_group_url, $scope.instance_groups) - .then(() => { - Wait('stop'); - $state.go($state.current, {}, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update instance groups. POST returned status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update inventory. PUT returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('inventories'); - }; - - $scope.remediateInventory = function(inv_id, insights_credential){ - $state.go('templates.addJobTemplate', {inventory_id: inv_id, credential_id: insights_credential}); - }; - -} - -export default ['$scope', '$location', - '$stateParams', 'InventoryForm', 'Rest', - 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'Wait', - 'ToJSON', 'ParseVariableString', - '$state', 'OrgAdminLookup', '$rootScope', 'resourceData', 'CreateSelect2', - 'InstanceGroupsService', 'InstanceGroupsData', 'CanRemediate', - InventoriesEdit, -]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/main.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/main.js deleted file mode 100644 index 130a5e8b4b97..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './inventory-edit.controller'; - -export default - angular.module('InventoryEdit', []) - .controller('InventoryEditController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js deleted file mode 100644 index 1c9f1dd13d0a..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js +++ /dev/null @@ -1,185 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name forms.function:Inventories - * @description This form is for adding/editing an inventory - */ - -export default ['i18n', -function(i18n) { - return { - - addTitle: i18n._('NEW INVENTORY'), - editTitle: '{{ inventory_name }}', - name: 'inventory', - basePath: 'inventory', - // the top-most node of this generated state tree - stateTree: 'inventories', - tabs: true, - - fields: { - name: { - realName: 'name', - label: i18n._('Name'), - type: 'text', - required: true, - capitalize: false, - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - description: { - realName: 'description', - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - basePath: 'organizations', - list: 'OrganizationList', - sourceModel: 'organization', - sourceField: 'name', - required: true, - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', - awLookupWhen: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg' - }, - insights_credential: { - label: i18n._('Insights Credential'), - type: 'lookup', - list: 'CredentialList', - basePath: 'credentials', - sourceModel: 'insights_credential', - sourceField: 'name', - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', - }, - instance_groups: { - label: i18n._('Instance Groups'), - type: 'custom', - awPopOver: i18n._('Select the Instance Groups for this Inventory to run on. Refer to the Ansible Tower documentation for more detail.'), - dataTitle: i18n._('Instance Groups'), - dataPlacement: 'right', - dataContainer: 'body', - control: '', - }, - inventory_variables: { - realName: 'variables', - label: i18n._('Variables'), - type: 'textarea', - class: 'Form-formGroup--fullWidth', - rows: 6, - "default": "---", - awPopOver: i18n._('Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.'), - dataTitle: i18n._('Variables'), - dataPlacement: 'right', - dataContainer: 'body', - ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - related: { - permissions: { - name: 'permissions', - awToolTip: i18n._('Please save before assigning permissions.'), - dataPlacement: 'top', - basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/access_list/', - type: 'collection', - title: i18n._('Permissions'), - iterator: 'permission', - index: false, - open: false, - search: { - order_by: 'username' - }, - actions: { - add: { - label: i18n._('Add'), - ngClick: "$state.go('.add')", - awToolTip: i18n._('Add a permission'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' - - } - }, - fields: { - username: { - key: true, - label: i18n._('User'), - linkBase: 'users', - class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' - }, - role: { - label: i18n._('Role'), - type: 'role', - nosort: true, - class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', - }, - team_roles: { - label: i18n._('Team Roles'), - type: 'team_roles', - nosort: true, - class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4', - } - } - }, - groups: { - name: 'groups', - awToolTip: i18n._('Please save before creating groups.'), - dataPlacement: 'top', - include: "GroupList", - title: i18n._('Groups'), - iterator: 'group', - skipGenerator: true - }, - hosts: { - name: 'hosts', - awToolTip: i18n._('Please save before creating hosts.'), - dataPlacement: 'top', - include: "RelatedHostsListDefinition", - title: i18n._('Hosts'), - iterator: 'host', - skipGenerator: true - }, - inventory_sources: { - name: 'inventory_sources', - awToolTip: i18n._('Please save before defining inventory sources.'), - dataPlacement: 'top', - title: i18n._('Sources'), - iterator: 'inventory_source', - skipGenerator: true - }, - completed_jobs: { - title: i18n._('Completed Jobs'), - skipGenerator: true - } - }, - relatedButtons: { - remediate_inventory: { - ngClick: 'remediateInventory(id, insights_credential)', - ngShow: 'is_insights && mode !== "add" && canRemediate', - label: i18n._('Remediate Inventory'), - class: 'Form-primaryButton' - } - } - - };}]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/main.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/main.js deleted file mode 100644 index 1b2f8d8be51d..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/main.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import inventoryAdd from './add/main'; - import inventoryEdit from './edit/main'; - import InventoryForm from './inventory.form'; - -export default -angular.module('standardInventory', [ - inventoryAdd.name, - inventoryEdit.name - ]) - .factory('InventoryForm', InventoryForm); diff --git a/awx/ui/client/src/inventories-hosts/inventory-hosts.block.less b/awx/ui/client/src/inventories-hosts/inventory-hosts.block.less deleted file mode 100644 index e4663663fbf4..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventory-hosts.block.less +++ /dev/null @@ -1,10 +0,0 @@ -#hosts-panel { - .List-noItems { - margin-top: 0px; - } - .groupsList { - .List-noItems { - margin-top: 52px; - } - } -} \ No newline at end of file diff --git a/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js b/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js deleted file mode 100644 index 6c46f7c9d55b..000000000000 --- a/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js +++ /dev/null @@ -1,40 +0,0 @@ -function InventoryHostsStrings (BaseString) { - BaseString.call(this, 'inventory-hosts'); - - let t = this.t; - let ns = this['inventory-hosts']; - - ns.deletegroup = { - GROUP: count => t.p(count, 'group', 'groups'), - HOST: count => t.p(count, 'host', 'hosts'), - PROMOTE_GROUPS_AND_HOSTS: data => t.s('Promote {{ group }} and {{ host }}', { - group: this.get('deletegroup.GROUP', data.groups), - host: this.get('deletegroup.HOST', data.hosts) - }), - DELETE_GROUPS_AND_HOSTS: data => t.s('Delete {{ group }} and {{ host }}', { - group: this.get('deletegroup.GROUP', data.groups), - host: this.get('deletegroup.HOST', data.hosts) - }), - PROMOTE_GROUP: count => t.p(count, 'Promote group', 'Promote groups'), - DELETE_GROUP: count => t.p(count, 'Delete group', 'Delete groups'), - PROMOTE_HOST: count => t.p(count, 'Promote host', 'Promote hosts'), - DELETE_HOST: count => t.p(count, 'Delete host', 'Delete hosts'), - }; - - ns.smartinventories = { - hostfilter: { - MISSING_ORG: t.s('Please select an organization before editing the host filter.'), - INSTRUCTIONS: t.s('Please click the icon to edit the host filter.'), - MISSING_PERMISSIONS: t.s('You do not have sufficient permissions to edit the host filter.') - } - }; - - ns.smartinventorybutton = { - DISABLED_INSTRUCTIONS: "Please enter at least one search term to create a new Smart Inventory.", - ENABLED_INSTRUCTIONS: "Create a new Smart Inventory from search results." - }; -} - -InventoryHostsStrings.$inject = ['BaseStringService']; - -export default InventoryHostsStrings; diff --git a/awx/ui/client/src/inventories-hosts/main.js b/awx/ui/client/src/inventories-hosts/main.js deleted file mode 100644 index de837d2049af..000000000000 --- a/awx/ui/client/src/inventories-hosts/main.js +++ /dev/null @@ -1,18 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import hosts from './hosts/main'; - import inventories from './inventories/main'; - import shared from './shared/main'; - import InventoryHostsStrings from './inventory-hosts.strings'; - -export default -angular.module('inventories-hosts', [ - hosts.name, - inventories.name, - shared.name - ]) - .service('InventoryHostsStrings', InventoryHostsStrings); diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js deleted file mode 100644 index 2f99c6a07508..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -function AnsibleFacts($scope, Facts, ParseTypeChange, ParseVariableString) { - - function init() { - $scope.facts = ParseVariableString(Facts); - let rows = (_.isEmpty(Facts)) ? 6 : 20; - $("#host_facts").attr("rows", rows); - $scope.parseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - variable: 'facts', - parse_variable: 'parseType', - field_id: 'host_facts', - readOnly: true - }); - } - - init(); - -} - -export default ['$scope', 'Facts', 'ParseTypeChange', 'ParseVariableString', AnsibleFacts -]; diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html deleted file mode 100644 index 5cb0ac216282..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html +++ /dev/null @@ -1,10 +0,0 @@ - -
- -
- -
-
- diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js deleted file mode 100644 index 045fe535ddbc..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js +++ /dev/null @@ -1,27 +0,0 @@ -import {templateUrl} from '../../../shared/template-url/template-url.factory'; -import { N_ } from '../../../i18n'; - -export default { - url: '/ansible_facts', - ncyBreadcrumb: { - label: N_("FACTS") - }, - views: { - 'related': { - controller: 'AnsibleFactsController', - templateUrl: templateUrl('inventories-hosts/shared/ansible-facts/ansible-facts') - } - }, - resolve: { - Facts: ['$stateParams', 'GetBasePath', 'Rest', - function($stateParams, GetBasePath, Rest) { - let ansibleFactsUrl = GetBasePath('hosts') + $stateParams.host_id + '/ansible_facts'; - Rest.setUrl(ansibleFactsUrl); - return Rest.get() - .then(({data}) => { - return data; - }); - } - ] - } -}; diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/main.js b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/main.js deleted file mode 100644 index 506652953f9e..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './ansible-facts.controller'; - -export default -angular.module('AnsibleFacts', []) - .controller('AnsibleFactsController', controller); diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.block.less b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.block.less deleted file mode 100644 index 6aa733a6e28b..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.block.less +++ /dev/null @@ -1,12 +0,0 @@ -.AssociateGroups-modalBody { - padding-top: 0px; -} -.AssociateGroups-backDrop { - width: 100vw; - height: 100vh; - position: fixed; - top: 0; - left: 0; - opacity: 0; - transition: 0.5s opacity; -} diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js deleted file mode 100644 index bfc4cda17e6d..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['$scope', '$rootScope', 'ProcessErrors', 'GetBasePath', 'generateList', - '$state', 'Rest', '$q', 'Wait', '$window', 'QuerySet', 'GroupList', - function($scope, $rootScope, ProcessErrors, GetBasePath, generateList, - $state, Rest, $q, Wait, $window, qs, GroupList) { - $scope.$on("linkLists", function() { - - init(); - - function init(){ - $scope.associate_group_default_params = { - order_by: 'name', - page_size: 5 - }; - - $scope.associate_group_queryset = { - order_by: 'name', - page_size: 5 - }; - - if($state.params.group_id) { - $scope.associate_group_default_params.not__id = $state.params.group_id; - $scope.associate_group_queryset.not__id = $state.params.group_id; - } - - let list = _.cloneDeep(GroupList); - list.basePath = GetBasePath('inventory') + $state.params.inventory_id + '/groups'; - list.iterator = 'associate_group'; - list.name = 'associate_groups'; - list.multiSelect = true; - list.fields.name.ngClick = 'linkoutGroup(associate_group)'; - list.trackBy = 'associate_group.id'; - list.multiSelectPreview = { - selectedRows: 'selectedItems', - availableRows: 'associate_groups' - }; - delete list.actions; - delete list.fieldActions; - delete list.fields.failed_hosts; - list.well = false; - $scope.list = list; - - // Fire off the initial search - qs.search(list.basePath, $scope.associate_group_default_params) - .then(function(res) { - $scope.associate_group_dataset = res.data; - $scope.associate_groups = $scope.associate_group_dataset.results; - - let html = generateList.build({ - list: list, - mode: 'edit', - title: false, - hideViewPerPage: true - }); - - $scope.compileList(html); - - $scope.$watchCollection('associate_groups', function () { - if($scope.selectedItems) { - $scope.associate_groups.forEach(function(row, i) { - if ($scope.selectedItems.filter(function(e) { return e.id === row.id; }).length > 0) { - $scope.associate_groups[i].isSelected = true; - } - }); - } - }); - - }); - - $scope.selectedItems = []; - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - $scope.selectedItems.push(item); - } - else { - // _.remove() Returns the new array of removed elements. - // This will pull all the values out of the array that don't - // match the deselected item effectively removing it - $scope.selectedItems = _.remove($scope.selectedItems, function(selectedItem) { - return selectedItem.id !== item.id; - }); - } - }); - } - - $scope.linkGroups = function() { - $scope.saveFunction({selectedItems: $scope.selectedItems}) - .then(() =>{ - $scope.closeModal(); - }).catch(() => { - $scope.closeModal(); - }); - - }; - - $scope.linkoutGroup = function(group) { - $window.open('/#/inventories/inventory/' + group.inventory + '/groups/edit/' + group.id,'_blank'); - }; - }); - }]; diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.directive.js b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.directive.js deleted file mode 100644 index 7b0595352c59..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.directive.js +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import controller from './associate-groups.controller'; - -/* jshint unused: vars */ -export default ['templateUrl', 'Wait', '$compile', '$state', - function(templateUrl, Wait, $compile, $state) { - return { - restrict: 'E', - transclude: true, - scope: { - saveFunction: '&' - }, - controller: controller, - templateUrl: templateUrl('inventories-hosts/shared/associate-groups/associate-groups'), - link: function(scope, element, attrs, controller, transcludefn) { - - $("body").addClass("is-modalOpen"); - - //$("body").append(element); - - Wait('start'); - - scope.$broadcast("linkLists"); - - setTimeout(function() { - $('#associate-groups-modal').modal("show"); - }, 200); - - $('.modal[aria-hidden=false]').each(function () { - if ($(this).attr('id') !== 'associate-groups-modal') { - $(this).modal('hide'); - } - }); - - scope.closeModal = function() { - $("body").removeClass("is-modalOpen"); - $('#associate-groups-modal').on('hidden.bs.modal', - function () { - $('.AddUsers').remove(); - }); - $('#associate-groups-modal').modal('hide'); - - $state.go('^', null, {reload: true}); - }; - - scope.compileList = function(html) { - $('#associate-groups-list').append($compile(html)(scope)); - }; - - Wait('stop'); - - window.scrollTo(0,0); - } - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html deleted file mode 100644 index 2f8b4a674793..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.block.less b/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.block.less deleted file mode 100644 index 68ea70336999..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.block.less +++ /dev/null @@ -1,12 +0,0 @@ -.AssociateHosts-modalBody { - padding-top: 0px; -} -.AssociateHosts-backDrop { - width: 100vw; - height: 100vh; - position: fixed; - top: 0; - left: 0; - opacity: 0; - transition: 0.5s opacity; -} diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.controller.js b/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.controller.js deleted file mode 100644 index 9a3014afcf0d..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.controller.js +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['$scope', '$rootScope', 'ProcessErrors', 'GetBasePath', 'generateList', - '$state', 'Rest', '$q', 'Wait', '$window', 'QuerySet', 'RelatedHostsListDefinition', - function($scope, $rootScope, ProcessErrors, GetBasePath, generateList, - $state, Rest, $q, Wait, $window, qs, RelatedHostsListDefinition) { - $scope.$on("linkLists", function() { - - init(); - - function init(){ - $scope.associate_host_default_params = { - order_by: 'name', - page_size: 5 - }; - - $scope.associate_host_queryset = { - order_by: 'name', - page_size: 5 - }; - - let list = _.cloneDeep(RelatedHostsListDefinition); - list.basePath = GetBasePath('inventory') + $state.params.inventory_id + '/hosts'; - list.iterator = 'associate_host'; - list.name = 'associate_hosts'; - list.multiSelect = true; - list.fields.name.ngClick = 'linkoutHost(associate_host)'; - list.fields.name.ngClass = "{ 'host-disabled-label': !associate_host.enabled }"; - list.fields.name.dataHostId = "{{ associate_host.id }}"; - list.trackBy = 'associate_host.id'; - list.multiSelectPreview = { - selectedRows: 'selectedItems', - availableRows: 'associate_hosts' - }; - delete list.fields.toggleHost; - delete list.fields.active_failures; - delete list.fields.groups; - delete list.actions; - delete list.fieldActions; - list.well = false; - $scope.list = list; - - // Fire off the initial search - qs.search(list.basePath, $scope.associate_host_default_params) - .then(function(res) { - $scope.associate_host_dataset = res.data; - $scope.associate_hosts = $scope.associate_host_dataset.results; - - let html = generateList.build({ - list: list, - mode: 'edit', - title: false, - hideViewPerPage: true - }); - - $scope.compileList(html); - - $scope.$watchCollection('associate_hosts', function () { - if($scope.selectedItems) { - $scope.associate_hosts.forEach(function(row, i) { - if ($scope.selectedItems.filter(function(e) { return e.id === row.id; }).length > 0) { - $scope.associate_hosts[i].isSelected = true; - } - }); - } - }); - - }); - - $scope.selectedItems = []; - $scope.$on('selectedOrDeselected', function(e, value) { - let item = value.value; - - if (value.isSelected) { - $scope.selectedItems.push(item); - } - else { - // _.remove() Returns the new array of removed elements. - // This will pull all the values out of the array that don't - // match the deselected item effectively removing it - $scope.selectedItems = _.remove($scope.selectedItems, function(selectedItem) { - return selectedItem.id !== item.id; - }); - } - }); - } - - $scope.linkhosts = function() { - $scope.saveFunction({selectedItems: $scope.selectedItems}) - .then(() =>{ - $scope.closeModal(); - }).catch(() => { - $scope.closeModal(); - }); - - }; - - $scope.linkoutHost = function(host) { - $window.open('/#/inventories/inventory/' + host.inventory + '/hosts/edit/' + host.id,'_blank'); - }; - }); - }]; diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.directive.js b/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.directive.js deleted file mode 100644 index 8cfbdb10941b..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.directive.js +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import controller from './associate-hosts.controller'; - -/* jshint unused: vars */ -export default ['templateUrl', 'Wait', '$compile', '$state', - function(templateUrl, Wait, $compile, $state) { - return { - restrict: 'E', - transclude: true, - scope: { - saveFunction: '&' - }, - controller: controller, - templateUrl: templateUrl('inventories-hosts/shared/associate-hosts/associate-hosts'), - link: function(scope, element, attrs, controller, transcludefn) { - - $("body").addClass("is-modalOpen"); - - //$("body").append(element); - - Wait('start'); - - scope.$broadcast("linkLists"); - - setTimeout(function() { - $('#associate-hosts-modal').modal("show"); - }, 200); - - $('.modal[aria-hidden=false]').each(function () { - if ($(this).attr('id') !== 'associate-hosts-modal') { - $(this).modal('hide'); - } - }); - - scope.closeModal = function() { - $("body").removeClass("is-modalOpen"); - $('#associate-hosts-modal').on('hidden.bs.modal', - function () { - $('.AddUsers').remove(); - }); - $('#associate-hosts-modal').modal('hide'); - - $state.go('^', null, {reload: true}); - }; - - scope.compileList = function(html) { - $('#associate-hosts-list').append($compile(html)(scope)); - }; - - Wait('stop'); - - window.scrollTo(0,0); - } - }; - } -]; diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html b/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html deleted file mode 100644 index 64c24bf804ca..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/awx/ui/client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js b/awx/ui/client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js deleted file mode 100644 index a31b8f73fa43..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js +++ /dev/null @@ -1,16 +0,0 @@ -export default - function SetEnabledMsg(i18n) { - return function(host) { - if (host.has_inventory_sources) { - // Inventory sync managed, so not clickable - host.enabledToolTip = (host.enabled) ? i18n._('Host is available') : i18n._('Host is not available'); - } - else { - // Clickable - host.enabledToolTip = (host.enabled) ? i18n._('Host is available. Click to toggle.') : i18n._('Host is not available. Click to toggle.'); - } - }; - } - -SetEnabledMsg.$inject = - [ 'i18n', ]; diff --git a/awx/ui/client/src/inventories-hosts/shared/factories/set-status.factory.js b/awx/ui/client/src/inventories-hosts/shared/factories/set-status.factory.js deleted file mode 100644 index aea5b5671f9f..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/factories/set-status.factory.js +++ /dev/null @@ -1,103 +0,0 @@ -export default - function SetStatus($filter, SetEnabledMsg, Empty, i18n) { - return function(params) { - var scope = params.scope, - host = params.host, - i, html, title; - - function ellipsis(a) { - if (a.length > 25) { - return a.substr(0,25) + '...'; - } - return a; - } - - function noRecentJobs() { - title = i18n._('No job data'); - html = "

" + i18n._("No recent job data available for this host.") + "

\n"; - } - - function setMsg(host) { - var j, job, jobs; - - if (host.has_active_failures === true || (host.has_active_failures === false && host.last_job !== null)) { - if (host.has_active_failures === true) { - host.badgeToolTip = i18n._('Most recent job failed. Click to view jobs.'); - host.active_failures = 'error'; - } - else { - host.badgeToolTip = i18n._("Most recent job successful. Click to view jobs."); - host.active_failures = 'successful'; - } - if (host.summary_fields.recent_jobs.length > 0) { - // build html table of job status info - jobs = host.summary_fields.recent_jobs.sort( - function(a,b) { - // reverse numerical order - return -1 * (a - b); - }); - title = "Recent Jobs"; - html = "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - for (j=0; j < jobs.length; j++) { - job = jobs[j]; - html += "\n"; - - // SmartStatus-tooltips are named --success whereas icon-job uses successful - var iconStatus = (job.status === 'successful') ? 'success' : 'failed'; - - html += "\n"; - - html += "\n"; - - html += "\n"; - - html += "\n"; - } - html += "\n"; - html += "
" + i18n._("Status") + "" + i18n._("Finished") + "" + i18n._("Name") + "
" + ($filter('longDate')(job.finished)).replace(/ /,'
') + "
" + $filter('sanitize')(ellipsis(job.name)) + "
\n"; - } - else { - noRecentJobs(); - } - } - else if (host.has_active_failures === false && host.last_job === null) { - host.badgeToolTip = i18n._("No job data available."); - host.active_failures = 'none'; - noRecentJobs(); - } - host.job_status_html = html; - host.job_status_title = title; - } - - if (!Empty(host)) { - // update single host - setMsg(host); - SetEnabledMsg(host); - } - else { - // update all hosts - for (i=0; i < scope.hosts.length; i++) { - setMsg(scope.hosts[i]); - SetEnabledMsg(scope.hosts[i]); - } - } - }; - } - -SetStatus.$inject = - [ '$filter', - 'SetEnabledMsg', - 'Empty', - 'i18n' - ]; diff --git a/awx/ui/client/src/inventories-hosts/shared/groups.service.js b/awx/ui/client/src/inventories-hosts/shared/groups.service.js deleted file mode 100644 index 0c6e1f8bef3c..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/groups.service.js +++ /dev/null @@ -1,131 +0,0 @@ -export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ - return { - stringifyParams: function(params){ - return _.reduce(params, (result, value, key) => { - return result + key + '=' + value + '&'; - }, ''); - }, - // cute abstractions via fn.bind() - url: function(){ - return ''; - }, - error: function(data) { - ProcessErrors($rootScope, data.data, data.status, null, { hdr: 'Error!', - msg: 'Call to ' + this.url + '. GET returned: ' + data.status }); - }, - success: function(data){ - return data; - }, - // HTTP methods - get: function(params){ - Wait('start'); - this.url = GetBasePath('groups') + '?' + this.stringifyParams(params); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - post: function(group){ - Wait('start'); - this.url = GetBasePath('groups'); - Rest.setUrl(this.url); - return Rest.post(group) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - put: function(group){ - Wait('start'); - this.url = GetBasePath('groups') + group.id; - Rest.setUrl(this.url); - return Rest.put(group) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - delete: function(id){ - Wait('start'); - this.url = GetBasePath('groups') + id; - Rest.setUrl(this.url); - return Rest.destroy() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - getCredential: function(id){ - Wait('start'); - this.url = GetBasePath('credentials') + id; - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - getInventorySource: function(params){ - Wait('start'); - this.url = GetBasePath('inventory_sources') + '?' + this.stringifyParams(params); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - putInventorySource: function(params, url){ - Wait('start'); - this.url = url; - Rest.setUrl(this.url); - return Rest.put(params) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level - associateGroup: function(group, target){ - Wait('start'); - this.url = GetBasePath('groups') + target + '/children/'; - Rest.setUrl(this.url); - return Rest.post(group) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - disassociateGroup: function(group, parent){ - Wait('start'); - this.url = GetBasePath('groups') + parent + '/children/'; - Rest.setUrl(this.url); - return Rest.post({id: group, disassociate: 1}) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - associateHost: function(host, target){ - Wait('start'); - this.url = GetBasePath('groups') + target + '/hosts/'; - Rest.setUrl(this.url); - return Rest.post(host) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - disassociateHost: function(host, group){ - Wait('start'); - this.url = GetBasePath('groups') + group + '/hosts/'; - Rest.setUrl(this.url); - return Rest.post({id: host, disassociate: 1}) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - promote: function(group, inventory){ - Wait('start'); - this.url = GetBasePath('inventory') + inventory + '/groups/'; - Rest.setUrl(this.url); - return Rest.post({id: group, disassociate: 1}) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/shared/hosts.service.js b/awx/ui/client/src/inventories-hosts/shared/hosts.service.js deleted file mode 100644 index 86241468928e..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/hosts.service.js +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', - function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ - return { - stringifyParams: function(params){ - return _.reduce(params, (result, value, key) => { - return result + key + '=' + value + '&'; - }, ''); - }, - // cute abstractions via fn.bind() - url: function(){ - return ''; - }, - error: function(data, status) { - ProcessErrors($rootScope, data.data, status, null, { hdr: 'Error!', - msg: 'Call to ' + this.url + '. GET returned: ' + status }); - }, - success: function(data){ - return data; - }, - // HTTP methods - get: function(params){ - Wait('start'); - this.url = GetBasePath('hosts') + '?' + this.stringifyParams(params); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - post: function(host){ - Wait('start'); - this.url = GetBasePath('hosts'); - Rest.setUrl(this.url); - return Rest.post(host) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - put: function(host){ - Wait('start'); - this.url = GetBasePath('hosts') + host.id; - Rest.setUrl(this.url); - return Rest.put(host) - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - delete: function(id){ - Wait('start'); - this.url = GetBasePath('hosts') + id; - Rest.setUrl(this.url); - return Rest.destroy() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/shared/inventories.service.js b/awx/ui/client/src/inventories-hosts/shared/inventories.service.js deleted file mode 100644 index 3cd069c4c209..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/inventories.service.js +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', - function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ - return { - // cute abstractions via fn.bind() - url: function(){ - return ''; - }, - error: function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + this.url + '. GET returned: ' + status }); - }, - success: function(data){ - return data; - }, - // data getters - getInventory: function(id){ - Wait('start'); - this.url = GetBasePath('inventory') + id; - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - getBreadcrumbs: function(groups){ - Wait('start'); - this.url = GetBasePath('groups') + '?' + _.map(groups, function(item){ - return '&or__id=' + item; - }).join(''); - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)) - .finally(Wait('stop')); - }, - rootHostsUrl: function(id){ - var url = GetBasePath('inventory') + id + '/hosts'; - return url; - }, - childHostsUrl: function(id){ - var url = GetBasePath('groups') + id + '/all_hosts'; - return url; - }, - childGroupsUrl: function(id){ - var url = GetBasePath('groups') + id + '/children'; - return url; - }, - rootGroupsUrl: function(id){ - var url = GetBasePath('inventory') + id+ '/root_groups'; - return url; - }, - inventorySourcesOptions: function(inventoryId) { - this.url = GetBasePath('inventory') + inventoryId + '/inventory_sources'; - Rest.setUrl(this.url); - return Rest.options() - .then(this.success.bind(this)) - .catch(this.error.bind(this)); - }, - updateInventorySourcesGet: function(inventoryId) { - this.url = GetBasePath('inventory') + inventoryId + '/update_inventory_sources'; - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)); - }, - getHost: function(inventoryId, hostId) { - this.url = GetBasePath('inventory') + inventoryId + '/hosts?id=' + hostId; - Rest.setUrl(this.url); - return Rest.get() - .then(this.success.bind(this)) - .catch(this.error.bind(this)); - } - }; - }]; diff --git a/awx/ui/client/src/inventories-hosts/shared/main.js b/awx/ui/client/src/inventories-hosts/shared/main.js deleted file mode 100644 index 37075ddc524c..000000000000 --- a/awx/ui/client/src/inventories-hosts/shared/main.js +++ /dev/null @@ -1,26 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import SetStatus from './factories/set-status.factory'; -import SetEnabledMsg from './factories/set-enabled-msg.factory'; -import ansibleFacts from './ansible-facts/main'; -import InventoriesService from './inventories.service'; -import GroupsService from './groups.service'; -import HostsService from './hosts.service'; -import associateGroups from './associate-groups/associate-groups.directive'; -import associateHosts from './associate-hosts/associate-hosts.directive'; - -export default -angular.module('inventoriesHostsFactories', [ - ansibleFacts.name -]) - .factory('SetStatus', SetStatus) - .factory('SetEnabledMsg', SetEnabledMsg) - .service('HostsService', HostsService) - .service('InventoriesService', InventoriesService) - .service('GroupsService', GroupsService) - .directive('associateGroups', associateGroups) - .directive('associateHosts', associateHosts); diff --git a/awx/ui/client/src/inventory-scripts/add/add.controller.js b/awx/ui/client/src/inventory-scripts/add/add.controller.js deleted file mode 100644 index 60c6714d703e..000000000000 --- a/awx/ui/client/src/inventory-scripts/add/add.controller.js +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'Wait', - 'InventoryScriptsForm', 'ProcessErrors', 'GetBasePath', - 'GenerateForm', '$scope', '$state', 'Alert', - function(Rest, Wait, - InventoryScriptsForm, ProcessErrors, GetBasePath, - GenerateForm, $scope, $state, Alert - ) { - var form = InventoryScriptsForm, - url = GetBasePath('inventory_scripts'); - - init(); - - function init() { - Rest.setUrl(url); - Rest.options() - .then(({data}) => { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add an inventory script.', 'alert-info'); - } - }); - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - // @issue @jmitchell - this setting probably collides with new RBAC can* implementation? - $scope.canEdit = true; - } - - // Save - $scope.formSave = function() { - Wait('start'); - Rest.setUrl(url); - Rest.post({ - name: $scope.name, - description: $scope.description, - organization: $scope.organization, - script: $scope.script - }) - .then(() => { - $state.go('inventoryScripts', null, { reload: true }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new inventory script. POST returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('^'); - }; - } -]; diff --git a/awx/ui/client/src/inventory-scripts/add/main.js b/awx/ui/client/src/inventory-scripts/add/main.js deleted file mode 100644 index 11d9659f64d4..000000000000 --- a/awx/ui/client/src/inventory-scripts/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './add.controller'; - -export default - angular.module('inventoryScriptsAdd', []) - .controller('InventoryScriptsAddController', controller); diff --git a/awx/ui/client/src/inventory-scripts/edit/edit.controller.js b/awx/ui/client/src/inventory-scripts/edit/edit.controller.js deleted file mode 100644 index 5bd7ee8f19ac..000000000000 --- a/awx/ui/client/src/inventory-scripts/edit/edit.controller.js +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'Wait', - 'InventoryScriptsForm', 'ProcessErrors', 'GetBasePath', - 'GenerateForm', 'inventory_scriptData', - '$scope', '$state', - function( - Rest, Wait, InventoryScriptsForm, ProcessErrors, GetBasePath, - GenerateForm, inventory_scriptData, - $scope, $state - ) { - var generator = GenerateForm, - data = inventory_scriptData, - id = inventory_scriptData.id, - form = InventoryScriptsForm, - master = {}, - url = GetBasePath('inventory_scripts'); - - init(); - - function init() { - $scope.inventory_script = inventory_scriptData; - - $scope.$watch('inventory_script_obj.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAdd = false; - } - }); - - var fld; - for (fld in form.fields) { - if (data[fld]) { - $scope[fld] = data[fld]; - master[fld] = data[fld]; - } - - if (form.fields[fld].sourceModel && data.summary_fields && - data.summary_fields[form.fields[fld].sourceModel]) { - $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - } - } - - } - - $scope.formSave = function() { - generator.clearApiErrors($scope); - Wait('start'); - Rest.setUrl(url + id + '/'); - Rest.put({ - name: $scope.name, - description: $scope.description, - organization: $scope.organization, - script: $scope.script - }) - .then(() => { - $state.go('inventoryScripts', null, { reload: true }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new inventory script. PUT returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('inventoryScripts'); - }; - - } -]; diff --git a/awx/ui/client/src/inventory-scripts/edit/main.js b/awx/ui/client/src/inventory-scripts/edit/main.js deleted file mode 100644 index b51e421206e7..000000000000 --- a/awx/ui/client/src/inventory-scripts/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './edit.controller'; - -export default - angular.module('inventoryScriptsEdit', []) - .controller('InventoryScriptsEditController', controller); diff --git a/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js b/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js deleted file mode 100644 index 0dbf97a0ba9f..000000000000 --- a/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js +++ /dev/null @@ -1,82 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:CustomInventory - * @description This form is for adding/editing an organization -*/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW CUSTOM INVENTORY'), - editTitle: '{{ name }}', - name: 'inventory_script', - basePath: 'inventory_scripts', - stateTree: 'inventoryScripts', - // I18N for "CREATE INVENTORY_SCRIPT" - // on /#/inventory_scripts/add - breadcrumbName: i18n._('INVENTORY SCRIPT'), - showActions: true, - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - list: 'OrganizationList', - basePath: 'organizations', - required: true, - sourceModel: 'organization', - sourceField: 'name', - ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - script: { - label: i18n._('Custom Script'), - type: 'textarea', - class: 'Form-formGroup--fullWidth', - elementClass: 'Form-monospace', - required: true, - awDropFile: true, - ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)', - ngTrim: false, - rows: 10, - awPopOver: i18n._('Drag and drop your custom inventory script file here or create one in the field to import your custom inventory. Refer to the Ansible Tower documentation for example syntax.'), - dataTitle: i18n._('Custom Script'), - dataPlacement: 'right', - dataContainer: "body" - }, - }, - - buttons: { //for now always generates
\n"; - - // Add the related confirm field - if (field.associated) { - fld = field.associated; - field = form.fields[field.associated]; - scope[fld] = ''; - html += "
\n"; - html += "\n"; - html += '*'; - html += "Please confirm the password.\n"; - html += (field.awPassMatch) ? "This value does not match the password you entered previously. Please confirm that password.
\n" : ""; - html += "
\n"; - html += "
\n"; - } - }); - - scope.$emit(callback, html, url); - - // Password change - scope.clearPWConfirm = function (fld) { - // If password value changes, make sure password_confirm must be re-entered - scope[fld] = ''; - scope.job_launch_form[fld].$setValidity('awpassmatch', false); - scope.checkStatus(); - }; - - scope.checkStatus = function() { - if (!scope.job_launch_form.$invalid) { - $('#password-accept-button').removeAttr('disabled'); - } - else { - $('#password-accept-button').attr({ "disabled": "disabled" }); - } - }; - }; - } - -PromptForPasswords.$inject = - [ 'CredentialForm' ]; diff --git a/awx/ui/client/src/job-submission/job-submission.block.less b/awx/ui/client/src/job-submission/job-submission.block.less deleted file mode 100644 index e81b0d094165..000000000000 --- a/awx/ui/client/src/job-submission/job-submission.block.less +++ /dev/null @@ -1,261 +0,0 @@ -.JobSubmission { - padding: 20px!important; - display: none; - height: auto!important; - min-height: 400px!important; -} -.JobSubmission-container { - flex-direction: column; - display: flex; - height: auto; - min-height: 360px; -} -.JobSubmission-dialog { - padding: 0px; - margin-bottom: 20px; - .ui-dialog-buttonpane, .ui-dialog-titlebar { - display:none; - } -} -.JobSubmission-header { - display: flex; - flex: 0 0 auto; -} -.JobSubmission-title { - align-items: center; - flex: 1 0 auto; - display: flex; - word-wrap: break-word; - word-break: break-all; - max-width: 98%; -} -.JobSubmission-titleText { - color: @list-title-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; -} -.JobSubmission-titleLockup { - margin-left: 4px; - margin-right: 6px; - display: inline-block; - margin-top: 0px; - padding-bottom: 2px; - vertical-align: bottom; -} -.JobSubmission-titleLockup:before { - content: "\007C"; - color: @default-icon-hov; - display: block; - font-size: 13px; -} -.JobSubmission-close { - justify-content: flex-end; - display: flex; -} -.JobSubmission-exit{ - cursor:pointer; - padding:0px; - border: none; - height:20px; - font-size: 20px; - background-color:@default-bg; - color:@d7grey; - transition: color 0.2s; - line-height:1; -} -.JobSubmission-exit:hover{ - color:@default-icon; -} -.JobSubmission-stepsContainer { - display: flex; - flex: 0 0 auto; - margin-top: 25px; -} -.JobSubmission-steps { - display: flex; - margin-bottom: 20px; - min-height: 30px; -} -.JobSubmission-step { - color: @default-interface-txt; - background-color: @default-bg; - font-size: 12px; - border: 1px solid @default-border; - height: 30px; - border-radius: 5px; - margin-right: 20px; - padding-left: 10px; - padding-right: 10px; - padding-bottom: 5px; - padding-top: 5px; - transition: background-color 0.2s; - text-transform: uppercase; - line-height: 20px; - white-space: nowrap; -} -.JobSubmission-step:hover { - color: @btn-txt; - background-color: @btn-bg-hov; - cursor: pointer; -} -.JobSubmission-step--active { - color: @default-bg!important; - background-color: @default-icon!important; - border-color: @default-icon!important; - cursor: default!important; -} -.JobSubmission-step--disabled { - opacity: 0.65; - cursor: not-allowed!important; -} -.JobSubmission-formContainer { - display: flex; - flex: 1 0 auto; -} -.JobSubmission-form { - display: flex; - flex: 1 0 auto; - max-width: 100%; - flex-direction: column; -} -.JobSubmission-footerContainer { - display: flex; - flex: 0 0 auto; - margin-top: 15px; - justify-content: space-between; -} -.JobSubmission-footerPreview { - display: flex; -} -.JobSubmission-footerButtons { - justify-content: flex-end; - display: flex; - align-items: flex-end; -} -.JobSubmission-previewItem { - min-width: 150px; - font-weight: normal; - font-size: small; -} -.JobSubmission-previewItemTitle, .JobSubmission-previewItemSubTitle, .JobSubmission-selectedItemInfoSubTitle { - color: @default-interface-txt; -} -.JobSubmission-previewItemNone { - color: @default-icon; -} -.JobSubmission-actionButton { - background-color: @submit-button-bg; - color: @submit-button-text; - height: 30px; - padding-left:15px; - padding-right: 15px; - width: 85px; -} -.JobSubmission-actionButton:hover, -.JobSubmission-actionButton:focus { - color: @submit-button-text; - background-color: @submit-button-bg-hov; -} -.JobSubmission-defaultButton{ - background-color: @default-bg; - color: @btn-txt; - text-transform: uppercase; - border-radius: 5px; - border: 1px solid @btn-bord; - padding-left:15px; - padding-right: 15px; - height: 30px; - min-width: 85px; - margin-right: 20px; -} -.JobSubmission-defaultButton:hover{ - background-color: @btn-bg-hov; - color: @btn-txt; -} - -.JobSubmission-revertLink { - font-size: 12px; -} - -.JobSubmission-selectedItem { - display: flex; - flex: 1 0 auto; - margin-bottom: 15px; - align-items: baseline; -} -.JobSubmission-selectedItemInfo { - display: flex; - flex: 0 0 100%; - background-color: @default-no-items-bord; - border: 1px solid @default-border; - padding: 10px; - border-radius: 5px; - max-height: 120px; - overflow-y: scroll; -} -.JobSubmission-selectedItemRevert { - display: flex; - flex: 0 0 auto; -} -.JobSubmission-credentialSubSection { - display: flex; - justify-content: flex-end; - align-items: center; - margin-bottom: 15px; -} -.JobSubmission-selectedItemLabel, .JobSubmission-label { - color: @default-interface-txt; - margin-right: 10px; -} -.JobSubmission-label { - line-height: 24px; -} -.JobSubmission-selectedItemNone { - color: @default-icon; -} -.JobSubmission-selectedItemContainer { - display: block; - width: 100%; -} -.JobSubmission-instructions { - color: @default-interface-txt; - margin-top: 25px; - margin-bottom: 15px; -} -.JobSubmission-passwordButton { - padding: 5px 13px!important; -} -.JobSubmission .List-noItems { - margin-top: auto; -} -.JobSubmission-selectedItemLabel { - flex: 0 0 80px; - line-height: 29px; -} -.JobSubmission-previewTags--outer { - flex: 1 0 auto; - max-width: ~"calc(100% - 140px)"; -} -.JobSubmission-previewTags--inner { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} -.JobSubmission-previewTagLabel { - color: @default-interface-txt; -} -.JobSubmission-previewTagLabel--deletable{ - color: @default-list-header-bg; -} -.JobSubmission-previewTagRevert { - flex: 0 0 60px; - line-height: 29px; -} -.JobSubmission-previewTagContainer { - display: flex; -} - -.JobSubmission-credentialSubSection .select2 { - width: 50% !important; -} diff --git a/awx/ui/client/src/job-submission/job-submission.controller.js b/awx/ui/client/src/job-submission/job-submission.controller.js deleted file mode 100644 index 60744ef069ad..000000000000 --- a/awx/ui/client/src/job-submission/job-submission.controller.js +++ /dev/null @@ -1,584 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:JobSubmission - * @description This controller's for the Job Submission Modal -* The job-submission directive is intended to handle job launch/relaunch from a playbook. There are 4 potential steps involved in launching a job: -* -* Select an Inventory -* Select a Credential -* Extra prompts (extra vars, limit, job type, job tags) -* Fill in survey -* -* #Workflow when user hits launch button -* -* A 'get' call is made to the API's 'job_templates/:job_template_id/launch' endpoint for that job template. The response from the API will specify -* -*``` -* "credential_needed_to_start": true, -* "can_start_without_user_input": false, -* "ask_variables_on_launch": false, -* "passwords_needed_to_start": [], -* "variables_needed_to_start": [], -* "survey_enabled": false -*``` -* #Step 1 - Hit the launch/relaunch endpoint -* -* The launch/relaunch endpoint(s) let us know what the default values are for a particular job template. It also lets us know what the creator of -* the job template selected as "promptable" fields. -* -* #Step 2 - Gather inv/credential lists and job template survey questions -* -* If the job template allows for inventory or credential prompting then we need to go out and get the available inventories and credentials for the -* launching user. We also go out and get the survey from its endpoint if a survey has been created and is enabled for this job template (getsurveyquestions.factory). -* -* #Step 3 - Fill out the job launch form -* -* No server calls needed as a user fills out the form. Note that if no user input is required (no prompts, no passwords) then we skip ahead to the next -* step. -* -* #Step 4 - Launch the job: LaunchJob -* -* This is maybe the most crucial step. We have setup everything we need in order to gather information from the user and now we want to be sure -* we handle it correctly. And there are many scenarios to take into account. The first scenario we check for is is ``survey_enabled=true`` and -* ``prompt_for_vars=false``, in which case we want to make sure to include the extra_vars from the job template in the data being -* sent to the API (it is important to note that anything specified in the extra vars on job submission will override vars specified in the job template. -* Likewise, any variables specified in the extra vars that are duplicated by the survey vars, will get overridden by the survey vars). -* If the previous scenario is NOT the case, then we continue to gather the modal's answers regularly: gather the passwords, then the extra_vars, then -* any survey results. Also note that we must gather any required survey answers, as well as any optional survey answers that happened to be provided -* by the user. We also include the credential that was chosen if the user was prompted to select a credential. -* At this point we have all the info we need and we are almost ready to perform a POST to the '/launch' endpoint. We must lastly check -* if the user was not prompted for anything and therefore we don't want to pass any extra_vars to the POST. Once this is done we -* make the REST POST call and provide all the data to hte API. The response from the API will be the job ID, which is used to redirect the user -* to the job detail page for that job run. -* -* @Usage -* This is usage information. -*/ - -export default - [ '$scope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors', - 'LaunchJob', '$state', 'InventoryList', 'CredentialList', 'ParseTypeChange', - function($scope, GetBasePath, Wait, Rest, ProcessErrors, - LaunchJob, $state, InventoryList, CredentialList, ParseTypeChange) { - - var launch_url; - - var clearRequiredPasswords = function() { - $scope.ssh_password_required = false; - $scope.ssh_key_unlock_required = false; - $scope.become_password_required = false; - - $scope.ssh_password = ""; - $scope.ssh_key_unlock = ""; - $scope.become_password = ""; - }; - - var launchJob = function() { - LaunchJob({ - scope: $scope, - url: launch_url, - submitJobType: $scope.submitJobType, - relaunchHostType: $scope.relaunchHostType - }); - }; - - // This gets things started - goes out and hits the launch endpoint (based on launch/relaunch) and - // prepares the form fields, defauts, etc. - $scope.init = function() { - $scope.forms = {}; - $scope.passwords = {}; - $scope.selected_credentials = { - machine: null, - extra: [] - }; - - // As of 3.0, the only place the user can relaunch a - // playbook is on jobTemplates.edit (completed_jobs tab), - // jobs, and jobResults $states. - - if (!$scope.submitJobRelaunch) { - if($scope.submitJobType && $scope.submitJobType === 'job_template') { - launch_url = GetBasePath('job_templates') + $scope.submitJobId + '/launch/'; - } - else if($scope.submitJobType && $scope.submitJobType === 'workflow_job_template') { - launch_url = GetBasePath('workflow_job_templates') + $scope.submitJobId + '/launch/'; - } - } - else { - if($scope.submitJobType && $scope.submitJobType === 'workflow_job') { - launch_url = GetBasePath('workflow_jobs') + $scope.submitJobId + '/relaunch/'; - } - else { - launch_url = GetBasePath('jobs') + $scope.submitJobId + '/relaunch/'; - } - } - - $scope.$watch('selected_credentials.machine', function(){ - if($scope.selected_credentials.machine) { - if($scope.selected_credentials.machine.id === $scope.defaults.credential.id) { - clearRequiredPasswords(); - for(var i=0; i<$scope.passwords_needed_to_start.length; i++) { - var password = $scope.passwords_needed_to_start[i]; - switch(password) { - case "ssh_password": - $scope.ssh_password_required = true; - break; - case "ssh_key_unlock": - $scope.ssh_key_unlock_required = true; - break; - case "become_password": - $scope.become_password_required = true; - break; - } - } - } - else { - $scope.ssh_password_required = ($scope.selected_credentials.machine.inputs && $scope.selected_credentials.machine.inputs.password === "ASK") ? true : false; - $scope.ssh_key_unlock_required = ($scope.selected_credentials.machine.inputs && $scope.selected_credentials.machine.inputs.ssh_key_unlock === "ASK") ? true : false; - $scope.become_password_required = $scope.selected_credentials.machine.inputs && ($scope.selected_credentials.machine.inputs.become_password === "ASK") ? true : false; - } - } - else { - clearRequiredPasswords(); - } - }); - - // Get the job or job_template record - Wait('start'); - Rest.setUrl(launch_url); - Rest.get() - .then(({data}) => { - - // Put all the data that we get back about the launch onto scope - angular.extend($scope, data); - - // General catch-all for "other prompts" - used in this link function and to hide the Other Prompts tab when - // it should be hidden - $scope.has_other_prompts = (data.ask_verbosity_on_launch || data.ask_job_type_on_launch || data.ask_limit_on_launch || data.ask_tags_on_launch || data.ask_skip_tags_on_launch || data.ask_variables_on_launch || data.ask_diff_mode_on_launch) ? true : false; - $scope.password_needed = data.passwords_needed_to_start && data.passwords_needed_to_start.length > 0; - $scope.has_default_inventory = data.defaults && data.defaults.inventory && data.defaults.inventory.id; - $scope.has_default_credential = data.defaults && data.defaults.credential && data.defaults.credential.id; - $scope.has_default_vault_credential = data.defaults && data.defaults.vault_credential && data.defaults.vault_credential.id; - $scope.vault_password_required = ($scope.password_needed && data.passwords_needed_to_start.includes('vault_password')); - $scope.has_default_extra_credentials = data.defaults && data.defaults.extra_credentials && data.defaults.extra_credentials.length > 0; - - $scope.other_prompt_data = {}; - - let getChoices = (options, lookup) => { - return _.get(options, lookup, []).map(c => ({label: c[1], value: c[0]})); - }; - - let getChoiceFromValue = (choices, value) => { - return _.find(choices, item => item.value === value); - }; - - if ($scope.has_other_prompts) { - Rest.options() - .then(options => { - if ($scope.ask_job_type_on_launch) { - let choices = getChoices(options.data, 'actions.POST.job_type.choices'); - let initialValue = _.get(data, 'defaults.job_type'); - let initialChoice = getChoiceFromValue(choices, initialValue); - $scope.other_prompt_data.job_type_options = choices; - $scope.other_prompt_data.job_type = initialChoice; - } - if ($scope.ask_verbosity_on_launch) { - let choices = getChoices(options.data, 'actions.POST.verbosity.choices'); - let initialValue = _.get(data, 'defaults.verbosity'); - let initialChoice = getChoiceFromValue(choices, initialValue); - $scope.other_prompt_data.verbosity_options = choices; - $scope.other_prompt_data.verbosity = initialChoice; - } - }) - .catch((error) => { - ProcessErrors($scope, error.data, error.status, null, { - hdr: 'Error!', - msg: `Failed to get ${launch_url}. OPTIONS status: ${error.status}` - }); - }); - } - - if($scope.ask_limit_on_launch) { - $scope.other_prompt_data.limit = (data.defaults && data.defaults.limit) ? data.defaults.limit : ""; - } - - if($scope.ask_tags_on_launch) { - $scope.other_prompt_data.job_tags_options = (data.defaults && data.defaults.job_tags) ? data.defaults.job_tags.split(',') - .map((i) => ({name: i, label: i, value: i})) : []; - $scope.other_prompt_data.job_tags = $scope.other_prompt_data.job_tags_options; - } - - if($scope.ask_skip_tags_on_launch) { - $scope.other_prompt_data.skip_tags_options = (data.defaults && data.defaults.skip_tags) ? data.defaults.skip_tags.split(',') - .map((i) => ({name: i, label: i, value: i})) : []; - $scope.other_prompt_data.skip_tags = $scope.other_prompt_data.skip_tags_options; - } - - if($scope.ask_diff_mode_on_launch) { - $scope.other_prompt_data.diff_mode = (data.defaults && data.defaults.diff_mode) ? data.defaults.diff_mode : false; - } - - if($scope.ask_variables_on_launch) { - $scope.jobLaunchVariables = (data.defaults && data.defaults.extra_vars) ? data.defaults.extra_vars : "---"; - $scope.other_prompt_data.parseType = 'yaml'; - $scope.parseType = 'yaml'; - } - - if($scope.has_default_inventory) { - $scope.selected_inventory = angular.copy($scope.defaults.inventory); - } - - if($scope.has_default_credential) { - $scope.selected_credentials.machine = angular.copy($scope.defaults.credential); - } - - if($scope.has_default_vault_credential) { - $scope.selected_credentials.vault = angular.copy($scope.defaults.vault_credential); - } - - if($scope.has_default_extra_credentials) { - $scope.selected_credentials.extra = angular.copy($scope.defaults.extra_credentials); - } - - if( ($scope.submitJobType === 'workflow_job_template' && !$scope.survey_enabled) || ($scope.submitJobRelaunch && !$scope.password_needed) || (!$scope.submitJobRelaunch && $scope.can_start_without_user_input && !$scope.ask_inventory_on_launch && !$scope.ask_credential_on_launch && !$scope.has_other_prompts && !$scope.survey_enabled)) { - // The job can be launched if - // a) It's a relaunch and no passwords are needed - // or - // b) It's not a relaunch and there's not any prompting/surveys - launchJob(); - Wait('stop'); - } - else { - - var initiateModal = function() { - - // Go out and get the credential types - Rest.setUrl(GetBasePath('credential_types')); - Rest.get() - .then( (response) => { - let credentialTypeData = response.data; - let credential_types = {}; - $scope.credentialTypeOptions = []; - credentialTypeData.results.forEach((credentialType => { - credential_types[credentialType.id] = credentialType; - if(credentialType.kind.match(/^(machine|cloud|net|ssh)$/)) { - $scope.credentialTypeOptions.push({ - name: credentialType.name, - value: credentialType.id - }); - } - })); - $scope.credential_types = credential_types; - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get credential types. GET status: ' + status - }); - }); - - // Figure out which step the user needs to start on - if($scope.ask_inventory_on_launch) { - $scope.setStep("inventory", true); - } - else if($scope.ask_credential_on_launch || $scope.password_needed) { - $scope.setStep("credential", true); - } - else if($scope.has_other_prompts) { - $scope.setStep("otherprompts", true); - } - else if($scope.survey_enabled) { - $scope.setStep("survey", true); - } - - $scope.openLaunchModal(); - }; - - if($scope.submitJobRelaunch) { - // Go out and get some of the job details like inv, cred, name - Rest.setUrl(GetBasePath('jobs') + $scope.submitJobId); - Rest.get() - .then( (response) => { - let jobResultData = response.data; - $scope.job_template_data = { - name: jobResultData.name - }; - $scope.defaults = {}; - if(jobResultData.summary_fields.inventory) { - $scope.defaults.inventory = angular.copy(jobResultData.summary_fields.inventory); - $scope.selected_inventory = angular.copy(jobResultData.summary_fields.inventory); - } - if(jobResultData.summary_fields.credential) { - $scope.defaults.credential = angular.copy(jobResultData.summary_fields.credential); - $scope.selected_credentials.machine = angular.copy(jobResultData.summary_fields.credential); - } - initiateModal(); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get job details. GET returned status: ' + status }); - }); - } - else { - // Move forward with the modal - initiateModal(); - } - - } - - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get job template details. GET returned status: ' + status }); - }); - }; - - $scope.setStep = function(step, initialStep) { - $scope.step = step; - - if(step === "credential") { - $scope.credentialTabEnabled = true; - } - else if(step === "otherprompts") { - $scope.otherPromptsTabEnabled = true; - - if(!initialStep && $scope.step === 'otherprompts' && $scope.ask_variables_on_launch && !$scope.extra_vars_code_mirror_loaded) { - ParseTypeChange({ - scope: $scope, - variable: 'jobLaunchVariables', - field_id: 'job_launch_variables' - }); - - $scope.extra_vars_code_mirror_loaded = true; - } - } - else if(step === "survey") { - $scope.surveyTabEnabled = true; - } - - }; - - $scope.revertToDefaultInventory = function() { - if($scope.has_default_inventory) { - $scope.selected_inventory = angular.copy($scope.defaults.inventory); - } - else { - $scope.selected_inventory = null; - } - }; - - $scope.revertToDefaultCredentials = function() { - if($scope.has_default_credential) { - $scope.selected_credentials.machine = angular.copy($scope.defaults.credential); - } - else { - $scope.selected_credentials.machine = null; - } - if($scope.has_default_vault_credential) { - $scope.selected_credentials.vault = angular.copy($scope.defaults.vault_credential); - } - else { - $scope.selected_credentials.vault = null; - } - if($scope.has_default_extra_credentials) { - $scope.selected_credentials.extra = angular.copy($scope.defaults.extra_credentials); - } - else { - $scope.selected_credentials.extra = []; - } - }; - - $scope.toggle_credential = function(cred) { - $scope.credentials.forEach(function(row, i) { - if (row.id === cred.id) { - $scope.selected_credentials.machine = angular.copy(row); - $scope.credentials[i].checked = 1; - } else { - $scope.credentials[i].checked = 0; - } - }); - }; - - $scope.getActionButtonText = function() { - if($scope.step === "inventory") { - return ($scope.ask_credential_on_launch || $scope.password_needed || $scope.has_other_prompts || $scope.survey_enabled) ? "NEXT" : "LAUNCH"; - } - else if($scope.step === "credential") { - return ($scope.has_other_prompts || $scope.survey_enabled) ? "NEXT" : "LAUNCH"; - } - else if($scope.step === "otherprompts") { - return ($scope.survey_enabled) ? "NEXT" : "LAUNCH"; - } - else if($scope.step === "survey") { - return "LAUNCH"; - } - }; - - $scope.actionButtonDisabled = function() { - if($scope.step === "inventory") { - if($scope.selected_inventory) { - return false; - } - else { - $scope.credentialTabEnabled = false; - $scope.otherPromptsTabEnabled = false; - $scope.surveyTabEnabled = false; - return true; - } - } - else if($scope.step === "credential") { - if(($scope.selected_credentials.machine || $scope.selected_credentials.vault) && $scope.forms.credentialpasswords && $scope.forms.credentialpasswords.$valid) { - return false; - } - else { - $scope.otherPromptsTabEnabled = false; - $scope.surveyTabEnabled = false; - return true; - } - } - else if($scope.step === "otherprompts") { - if($scope.forms.otherprompts.$valid) { - return false; - } - else { - $scope.surveyTabEnabled = false; - return true; - } - } - else if($scope.step === "survey") { - if($scope.forms.survey.$valid) { - return false; - } - else { - return true; - } - } - - }; - - $scope.takeAction = function() { - if($scope.step === "inventory") { - // Check to see if there's another step after this one - if($scope.ask_credential_on_launch || $scope.password_needed) { - $scope.setStep("credential"); - } - else if($scope.has_other_prompts) { - $scope.setStep("otherprompts"); - } - else if($scope.survey_enabled) { - $scope.setStep("survey"); - } - else { - launchJob(); - } - } - else if($scope.step === "credential") { - if($scope.has_other_prompts) { - $scope.setStep("otherprompts"); - } - else if($scope.survey_enabled) { - $scope.setStep("survey"); - } - else { - launchJob(); - } - } - else if($scope.step === "otherprompts") { - if($scope.survey_enabled) { - $scope.setStep("survey"); - } - else { - launchJob(); - } - } - else { - launchJob(); - } - }; - - $scope.toggleForm = function(key) { - $scope.other_prompt_data[key] = !$scope.other_prompt_data[key]; - }; - - $scope.updateParseType = function() { - // This is what the ParseTypeChange factory is expecting - // It shares the same scope with this directive and will - // pull the new value of parseType out to determine which - // direction to convert the extra vars - - $scope.parseType = $scope.other_prompt_data.parseType; - $scope.parseTypeChange('parseType', 'jobLaunchVariables'); - }; - - $scope.showRevertCredentials = function(){ - let machineCredentialMatches = true; - let extraCredentialsMatch = true; - - if($scope.defaults.credential && $scope.defaults.credential.id) { - if(!$scope.selected_credentials.machine || ($scope.selected_credentials.machine && $scope.selected_credentials.machine.id !== $scope.defaults.credential.id)) { - machineCredentialMatches = false; - } - } - else { - if($scope.selected_credentials.machine && $scope.selected_credentials.machine.id) { - machineCredentialMatches = false; - } - } - - if($scope.defaults.extra_credentials && $scope.defaults.extra_credentials.length > 0) { - if($scope.selected_credentials.extra && $scope.selected_credentials.extra.length > 0) { - if($scope.defaults.extra_credentials.length !== $scope.selected_credentials.extra.length) { - extraCredentialsMatch = false; - } - else { - $scope.defaults.extra_credentials.forEach((defaultExtraCredential) =>{ - let matchesSelected = false; - $scope.selected_credentials.extra.forEach((selectedExtraCredential) =>{ - if(defaultExtraCredential.id === selectedExtraCredential.id) { - matchesSelected = true; - } - }); - if(!matchesSelected) { - extraCredentialsMatch = false; - } - }); - } - - } - else { - extraCredentialsMatch = false; - } - } - else { - if($scope.selected_credentials.extra && $scope.selected_credentials.extra.length > 0) { - extraCredentialsMatch = false; - } - } - - return machineCredentialMatches && extraCredentialsMatch ? false : true; - }; - - $scope.$on('inventorySelected', function(evt, selectedRow){ - $scope.selected_inventory = _.cloneDeep(selectedRow); - }); - - $scope.deleteMachineCred = function() { - $scope.selected_credentials.machine = null; - }; - - $scope.deleteExtraCred = function(index) { - $scope.selected_credentials.extra.splice(index, 1); - }; - - $scope.deleteSelectedInventory = function() { - $scope.selected_inventory = null; - }; - - } - ]; diff --git a/awx/ui/client/src/job-submission/job-submission.directive.js b/awx/ui/client/src/job-submission/job-submission.directive.js deleted file mode 100644 index d248e2cd05e0..000000000000 --- a/awx/ui/client/src/job-submission/job-submission.directive.js +++ /dev/null @@ -1,144 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import jobSubmissionController from './job-submission.controller'; - -export default [ 'templateUrl', 'CreateDialog', 'Wait', 'CreateSelect2', 'ParseTypeChange', 'GetSurveyQuestions', 'i18n', 'credentialTypesLookup', '$transitions', - function(templateUrl, CreateDialog, Wait, CreateSelect2, ParseTypeChange, GetSurveyQuestions, i18n, credentialTypesLookup, $transitions) { - return { - scope: { - submitJobId: '=', - submitJobType: '@', - submitJobRelaunch: '=', - relaunchHostType: '@' - }, - templateUrl: templateUrl('job-submission/job-submission'), - controller: jobSubmissionController, - restrict: 'E', - link: function(scope) { - - scope.openLaunchModal = function() { - if (scope.removeLaunchJobModalReady) { - scope.removeLaunchJobModalReady(); - } - scope.removeLaunchJobModalReady = scope.$on('LaunchJobModalReady', function() { - credentialTypesLookup() - .then(kinds => { - if(scope.ask_credential_on_launch) { - scope.credentialKind = "" + kinds.Machine; - scope.includeCredentialList = true; - } - }); - - // Go get the list/survey data that we need from the server - if(scope.ask_inventory_on_launch) { - scope.includeInventoryList = true; - } - if(scope.survey_enabled) { - GetSurveyQuestions({ - scope: scope, - id: scope.submitJobId, - submitJobType: scope.submitJobType - }); - - } - - $('#job-launch-modal').dialog('open'); - - // select2-ify the job type dropdown - CreateSelect2({ - element: '#job_launch_job_type', - multiple: false - }); - - CreateSelect2({ - element: '#job_launch_verbosity', - multiple: false - }); - - CreateSelect2({ - element: `#job-launch-credential-kind-select`, - multiple: false, - placeholder: i18n._('Select a credential') - }); - - CreateSelect2({ - element: '#job_launch_job_tags', - multiple: true, - addNew: true - }); - - CreateSelect2({ - element: '#job_launch_skip_tags', - multiple: true, - addNew: true - }); - - if(scope.step === 'otherprompts' && scope.ask_variables_on_launch) { - ParseTypeChange({ - scope: scope, - variable: 'jobLaunchVariables', - field_id: 'job_launch_variables' - }); - - scope.extra_vars_code_mirror_loaded = true; - } - - }); - - CreateDialog({ - id: 'job-launch-modal', - scope: scope, - width: 800, - minWidth: 400, - draggable: false, - dialogClass: 'JobSubmission-dialog', - onOpen: function() { - Wait('stop'); - }, - callback: 'LaunchJobModalReady' - }); - }; - - scope.clearDialog = function() { - // Destroy the dialog - if($("#job-launch-modal").hasClass('ui-dialog-content')) { - $('#job-launch-modal').dialog('destroy'); - } - // Remove the directive from the page - $('#content-container').find('submit-job').remove(); - - // Clear out the scope (we'll create a new scope the next time - // job launch is called) - scope.$destroy(); - }; - - // This function is used to hide/show the contents of a password - // within a form - scope.togglePassword = function(id) { - var buttonId = id + "_show_input_button", - inputId = id, - buttonInnerHTML = $(buttonId).html(); - if (buttonInnerHTML.indexOf("Show") > -1) { - $(buttonId).html("Hide"); - $(inputId).attr("type", "text"); - } else { - $(buttonId).html("Show"); - $(inputId).attr("type", "password"); - } - }; - - $transitions.onStart({}, function() { - scope.$evalAsync(function( scope ) { - scope.clearDialog(); - }); - }); - - scope.init(); - - } - }; -}]; diff --git a/awx/ui/client/src/job-submission/job-submission.partial.html b/awx/ui/client/src/job-submission/job-submission.partial.html deleted file mode 100644 index dcf03bf6cbc7..000000000000 --- a/awx/ui/client/src/job-submission/job-submission.partial.html +++ /dev/null @@ -1,375 +0,0 @@ - diff --git a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.controller.js b/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.controller.js deleted file mode 100644 index ba4aa8ff3264..000000000000 --- a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.controller.js +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ '$scope', 'CredentialList', 'i18n', 'QuerySet', 'GetBasePath', 'credentialTypesLookup', - function($scope, CredentialList, i18n, qs, GetBasePath, credentialTypesLookup) { - let credentialKinds = {}; - - let updateExtraCredentialsList = function() { - $scope.credentials.forEach((row, i) => { - $scope.credentials[i].checked = 0; - $scope.selectedCredentials.extra.forEach((extraCredential, j) => { - if (row.id === $scope.selectedCredentials.extra[j].id) { - $scope.credentials[i].checked = 1; - } - }); - }); - }; - - let updateMachineCredentialList = function() { - $scope.credentials.forEach((row, i) => { - $scope.credentials[i].checked = 0; - if (row.id === $scope.selectedCredentials.machine.id) { - $scope.credentials[i].checked = 1; - } - }); - }; - - let uncheckAllCredentials = function() { - $scope.credentials.forEach((row, i) => { - $scope.credentials[i].checked = 0; - }); - }; - - let init = function() { - $scope.credential_dataset = []; - $scope.credentials = []; - $scope.listRendered = false; - - let credList = _.cloneDeep(CredentialList); - credList.emptyListText = i18n._('No Credentials Matching This Type Have Been Created'); - $scope.list = credList; - - $scope.credential_default_params = { - order_by: 'name', - page_size: 5 - }; - - $scope.credential_queryset = { - order_by: 'name', - page_size: 5 - }; - - $scope.$watch('credentialKind', function(){ - $scope.credential_queryset.page = 1; - $scope.credential_default_params.credential_type = $scope.credential_queryset.credential_type = parseInt($scope.credentialKind); - - qs.search(GetBasePath('credentials'), $scope.credential_default_params) - .then(res => { - $scope.credential_dataset = res.data; - $scope.credentials = $scope.credential_dataset.results; - if(!$scope.listRendered) { - $scope.generateCredentialList(); - $scope.listRendered = true; - } - }); - }); - - $scope.$watchCollection('selectedCredentials.extra', () => { - if($scope.credentials && $scope.credentials.length > 0) { - if($scope.selectedCredentials.extra && $scope.selectedCredentials.extra.length > 0 && parseInt($scope.credentialKind) !== credentialKinds.Machine) { - updateExtraCredentialsList(); - } else if (parseInt($scope.credentialKind) !== credentialKinds.Machine) { - uncheckAllCredentials(); - } - } - }); - - $scope.$watch('selectedCredentials.machine', () => { - if($scope.credentials && $scope.credentials.length > 0) { - if($scope.selectedCredentials.machine && parseInt($scope.credentialKind) === credentialKinds.Machine) { - updateMachineCredentialList(); - } - else { - uncheckAllCredentials(); - } - } - }); - - $scope.$watchGroup(['credentials', 'selectedCredentials.machine'], () => { - if($scope.credentials && $scope.credentials.length > 0) { - if($scope.selectedCredentials.machine && parseInt($scope.credentialKind) === credentialKinds.Machine) { - updateMachineCredentialList(); - } - else if($scope.selectedCredentials.extra && $scope.selectedCredentials.extra.length > 0 && parseInt($scope.credentialKind) !== credentialKinds.Machine) { - updateExtraCredentialsList(); - } - else { - uncheckAllCredentials(); - } - } - }); - }; - - $scope.toggle_row = function(selectedRow) { - if(parseInt($scope.credentialKind) === credentialKinds.Machine) { - $scope.selectedCredentials.machine = _.cloneDeep(selectedRow); - } - else { - for (let i = $scope.selectedCredentials.extra.length - 1; i >= 0; i--) { - if(selectedRow.credential_type === $scope.selectedCredentials.extra[i].credential_type) { - $scope.selectedCredentials.extra.splice(i, 1); - } - } - $scope.selectedCredentials.extra.push(_.cloneDeep(selectedRow)); - } - }; - - credentialTypesLookup() - .then(kinds => { - credentialKinds = kinds; - init(); - }); - } - ]; diff --git a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.directive.js b/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.directive.js deleted file mode 100644 index af277ce648fb..000000000000 --- a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.directive.js +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import jobSubCredListController from './job-sub-cred-list.controller'; - -export default [ 'templateUrl', '$compile', 'generateList', - (templateUrl, $compile, GenerateList) => { - return { - scope: { - selectedCredentials: '=', - credentialKind: '=', - credentialTypes: '=' - }, - templateUrl: templateUrl('job-submission/lists/credential/job-sub-cred-list'), - controller: jobSubCredListController, - restrict: 'E', - link: scope => { - scope.generateCredentialList = function() { - let html = GenerateList.build({ - list: scope.list, - input_type: 'radio', - mode: 'lookup' - }); - $('#job-submission-credential-lookup').append($compile(html)(scope)); - }; - } - }; -}]; diff --git a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.partial.html b/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.partial.html deleted file mode 100644 index d184dc7efb53..000000000000 --- a/awx/ui/client/src/job-submission/lists/credential/job-sub-cred-list.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
-
-
diff --git a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.controller.js b/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.controller.js deleted file mode 100644 index 9a5bfdad9b94..000000000000 --- a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.controller.js +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ '$scope', - function($scope) { - - let updateInventoryList = function() { - $scope.inventories.forEach((row, i) => { - $scope.inventories[i].checked = 0; - if (row.id === $scope.selectedInventory.id) { - $scope.inventories[i].checked = 1; - } - }); - }; - - let uncheckAllInventories = function() { - $scope.inventories.forEach((row, i) => { - $scope.inventories[i].checked = 0; - }); - }; - - let init = function() { - $scope.$watch('selectedInventory', () => { - if($scope.inventories && $scope.inventories.length > 0) { - if($scope.selectedInventory) { - updateInventoryList(); - } - else { - uncheckAllInventories(); - } - } - }); - }; - - init(); - - $scope.toggle_row = function(selectedRow) { - let list = $scope.list; - let count = 0; - $scope[list.name].forEach(function(row) { - if (row.id === selectedRow.id) { - if (row.checked) { - row.success_class = 'success'; - } else { - row.checked = 1; - row.success_class = ''; - } - $scope.$emit('inventorySelected', row); - } else { - row.checked = 0; - row.success_class = ''; - } - if (row.checked) { - count++; - } - }); - }; - } - ]; diff --git a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.directive.js b/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.directive.js deleted file mode 100644 index 305643e0e387..000000000000 --- a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.directive.js +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import jobSubInvListController from './job-sub-inv-list.controller'; - -export default [ 'templateUrl', 'QuerySet', 'GetBasePath', 'generateList', '$compile', 'InventoryList', - (templateUrl, qs, GetBasePath, GenerateList, $compile, InventoryList) => { - return { - scope: { - selectedInventory: '=' - }, - templateUrl: templateUrl('job-submission/lists/inventory/job-sub-inv-list'), - controller: jobSubInvListController, - restrict: 'E', - link: scope => { - let toDestroy = []; - - scope.inventory_default_params = { - order_by: 'name', - page_size: 5 - }; - - scope.inventory_queryset = { - order_by: 'name', - page_size: 5 - }; - - // Fire off the initial search - qs.search(GetBasePath('inventory'), scope.inventory_default_params) - .then(res => { - scope.inventory_dataset = res.data; - scope.inventories = scope.inventory_dataset.results; - - let invList = _.cloneDeep(InventoryList); - let html = GenerateList.build({ - list: invList, - input_type: 'radio', - mode: 'lookup' - }); - - scope.list = invList; - - $('#job-submission-inventory-lookup').append($compile(html)(scope)); - - toDestroy.push(scope.$watchCollection('selectedInventory', () => { - if(scope.selectedInventory) { - // Loop across the inventories and see if one of them should be "checked" - scope.inventories.forEach((row, i) => { - if (row.id === scope.selectedInventory.id) { - scope.inventories[i].checked = 1; - } - else { - scope.inventories[i].checked = 0; - } - }); - } - })); - }); - - scope.$on('$destroy', () => toDestroy.forEach(watcher => watcher())); - } - }; -}]; diff --git a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.partial.html b/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.partial.html deleted file mode 100644 index 2d30395c7291..000000000000 --- a/awx/ui/client/src/job-submission/lists/inventory/job-sub-inv-list.partial.html +++ /dev/null @@ -1,3 +0,0 @@ -
-
-
diff --git a/awx/ui/client/src/job-submission/main.js b/awx/ui/client/src/job-submission/main.js deleted file mode 100644 index 563942818b0a..000000000000 --- a/awx/ui/client/src/job-submission/main.js +++ /dev/null @@ -1,35 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import LaunchJob from './job-submission-factories/launchjob.factory'; -import GetSurveyQuestions from './job-submission-factories/getsurveyquestions.factory'; -import AdhocRun from './job-submission-factories/adhoc-run.factory.js'; -import CheckPasswords from './job-submission-factories/check-passwords.factory'; -import CreateLaunchDialog from './job-submission-factories/create-launch-dialog.factory'; -import InventoryUpdate from './job-submission-factories/inventory-update.factory'; -import ProjectUpdate from './job-submission-factories/project-update.factory'; -import PromptForPasswords from './job-submission-factories/prompt-for-passwords.factory'; -import submitJob from './job-submission.directive'; -import credentialList from './lists/credential/job-sub-cred-list.directive'; -import inventoryList from './lists/inventory/job-sub-inv-list.directive'; -import awPasswordMin from './job-submission-directives/aw-password-min.directive'; -import awPasswordMax from './job-submission-directives/aw-password-max.directive'; - -export default - angular.module('jobSubmission', []) - .factory('LaunchJob', LaunchJob) - .factory('GetSurveyQuestions', GetSurveyQuestions) - .factory('AdhocRun', AdhocRun) - .factory('CheckPasswords', CheckPasswords) - .factory('CreateLaunchDialog', CreateLaunchDialog) - .factory('InventoryUpdate', InventoryUpdate) - .factory('ProjectUpdate', ProjectUpdate) - .factory('PromptForPasswords', PromptForPasswords) - .directive('submitJob', submitJob) - .directive('jobSubCredList', credentialList) - .directive('jobSubInvList', inventoryList) - .directive('awPasswordMin', awPasswordMin) - .directive('awPasswordMax', awPasswordMax); diff --git a/awx/ui/client/src/license/checkLicense.factory.js b/awx/ui/client/src/license/checkLicense.factory.js deleted file mode 100644 index 04a658fa8287..000000000000 --- a/awx/ui/client/src/license/checkLicense.factory.js +++ /dev/null @@ -1,69 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - ['$state', '$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', - 'ConfigService', - function($state, $rootScope, Rest, GetBasePath, ProcessErrors, - ConfigService){ - return { - get: function() { - var config = ConfigService.get(); - return config.license_info; - }, - - post: function(license, eula){ - var defaultUrl = GetBasePath('config'); - Rest.setUrl(defaultUrl); - var data = license; - data.eula_accepted = eula; - return Rest.post(JSON.stringify(data)) - .then((response) =>{ - return response.data; - }) - .catch(({res, status}) => { - ProcessErrors($rootScope, res, status, null, {hdr: 'Error!', - msg: 'Call to '+ defaultUrl + ' failed. Return status: '+ status}); - }); - }, - - valid: function(license) { - if (!license.valid_key){ - return false; - } - return true; - }, - - test: function(event){ - var license = this.get(); - if(license === null || !$rootScope.license_tested){ - if(this.valid(license) === false) { - $rootScope.licenseMissing = true; - $state.go('license'); - if(event){ - event.preventDefault(); - } - } - else { - $rootScope.licenseMissing = false; - } - } - else if(this.valid(license) === false) { - $rootScope.licenseMissing = true; - $state.go('license'); - if(event){ - event.preventDefault(); - } - } - else { - $rootScope.licenseMissing = false; - } - return; - } - - }; - } - ]; diff --git a/awx/ui/client/src/license/fileOnChange.directive.js b/awx/ui/client/src/license/fileOnChange.directive.js deleted file mode 100644 index 2e044413087b..000000000000 --- a/awx/ui/client/src/license/fileOnChange.directive.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [function(){ - return { - restrict: 'A', - link: function(scope, el, attrs){ - var onChange = scope.$eval(attrs.fileOnChange); - el.bind('change', onChange); - } - }; - }]; diff --git a/awx/ui/client/src/license/license.block.less b/awx/ui/client/src/license/license.block.less deleted file mode 100644 index 0625568fff07..000000000000 --- a/awx/ui/client/src/license/license.block.less +++ /dev/null @@ -1,145 +0,0 @@ -/* -* Style conventions -* .ModuleName-component-subComponent -* Naming describes components of the view -*/ -.License-container{ - .OnePlusTwo-container; -} - -.License-container--missing { - max-width: 800px; - margin: 0 auto; - padding: 0 20px; -} - -.License-field--label{ - .OnePlusTwo-left--detailsLabel; -} -.License-fileName{ - padding-left: 20px; -} -.License-management .CodeMirror-scroll{ - min-height: 140px; -} -.License-file textarea{ - display: block; - width: 100%; -} -.License-submit--success.ng-hide-add, .License-submit--success.ng-hide-remove { - transition: all ease-in-out 0.5s; -} -.License-submit--success{ - opacity: 1; - transition: all ease-in-out 0.5s; -} -.License-submit--success.ng-hide{ - opacity: 0; -} - -.License-eulaNotice{ - font-size: 12px; - width: 100%; - max-height: 129px; - padding: 15px; - padding-top: 10px; - margin-bottom: 10px; - border-radius: 4px; - border: 1px solid @login-notice-border; - background-color: @login-notice-bg; - color: @login-notice-text; - overflow-y: scroll; - overflow-x: visible; - white-space: pre-line; -} - -.License-field label{ - width: 155px; -} -.License-field--content{ - .OnePlusTwo-left--detailsContent; - text-transform: capitalize; -} -.License-field--key { - text-transform: none; -} -.License-field{ - .OnePlusTwo-left--detailsRow; -} -.License-field + .License-field { - margin-top: 20px; -} -.License-greenText{ - color: @submit-button-bg; - padding-right: 10px; -} -.License-redText{ - color: @default-err; - padding-right: 10px; -} -.License-fields{ - .OnePlusTwo-left--details; -} - -.License-titleText { - .OnePlusTwo-panelHeader; -} -.License-management{ - display: flex; -} -.License-management--missingLicense{ - height: auto; -} -.License-downloadLicenseButton{ - margin-bottom: 10px; - color:@default-bg; -} -.License-downloadLicenseButton:hover{ - background-color: @default-link-hov !important; - color:@default-bg !important; -} -.License-downloadLicenseButton:focus{ - background-color: @default-link-hov !important; - color:@default-bg !important; -} - -@media (min-width: 900px) { - .License-details { - margin-right: 20px; - } -} - -.License-submit--success{ - margin: 0; -} -.License-file--container { - input[type=file] { - display: none; - } -} -.License-upgradeText { - margin: 20px 0px; -} -.License-body { - margin-top: 25px; -} -.License-subTitleText { - text-transform: uppercase; - margin: 20px 0px 15px 0px; - color: @default-interface-txt; -} -.License-helperText { - color: @default-interface-txt; -} -.License-input--fake{ - border-top-right-radius: 4px !important; - border-bottom-right-radius: 4px !important; -} - -.License-detailsGroup { - margin-bottom: 20px; -} - -.License-detailsGroup--withSeparator { - border-top: 1px solid @default-icon-hov; -} diff --git a/awx/ui/client/src/license/license.controller.js b/awx/ui/client/src/license/license.controller.js deleted file mode 100644 index 35323e44588b..000000000000 --- a/awx/ui/client/src/license/license.controller.js +++ /dev/null @@ -1,146 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {N_} from "../i18n"; - -export default - ['Wait', '$state', '$scope', '$rootScope', - 'ProcessErrors', 'CheckLicense', 'moment','$window', - 'ConfigService', 'FeaturesService', 'pendoService', 'i18n', 'config', 'Rest', 'GetBasePath', - function(Wait, $state, $scope, $rootScope, ProcessErrors, CheckLicense, moment, - $window, ConfigService, FeaturesService, pendoService, i18n, config, Rest, GetBasePath) { - - const calcDaysRemaining = function(seconds) { - // calculate the number of days remaining on the license - let duration = moment.duration(seconds, 'seconds').asDays(); - - duration = Math.floor(duration); - if(duration < 0){ - duration = 0; - } - - duration = (duration!==1) ? `${duration} Days` : `${duration} Day`; - - return duration; - }; - - const calcExpiresOn = function(seconds) { - // calculate the expiration date of the license - return moment.unix(seconds).calendar(); - }; - - const reset = function() { - document.getElementById('License-form').reset(); - }; - - const init = function(config) { - // license/license.partial.html compares fileName - $scope.fileName = N_("No file selected."); - - if ($rootScope.licenseMissing) { - $scope.title = $rootScope.BRAND_NAME + i18n._(" License"); - } else { - $scope.title = i18n._("License Management"); - } - - $scope.license = config; - $scope.license.version = config.version.split('-')[0]; - $scope.time = {}; - $scope.time.remaining = calcDaysRemaining($scope.license.license_info.time_remaining); - $scope.time.expiresOn = calcExpiresOn($scope.license.license_info.license_date); - $scope.valid = CheckLicense.valid($scope.license.license_info); - $scope.compliant = $scope.license.license_info.compliant; - $scope.newLicense = {}; - - Rest.setUrl(`${GetBasePath('settings')}ui`); - Rest.get() - .then(({data}) => { - if (data.PENDO_TRACKING_STATE === 'off' && !$rootScope.licenseMissing) { - $scope.newLicense.pendo = false; - } else { - $scope.newLicense.pendo = true; - } - }) - .catch(() => { - // default pendo tracking to true when settings is not accessible - $scope.newLicense.pendo = true; - }); - }; - - init(config); - - $scope.getKey = function(event) { - // Mimic HTML5 spec, show filename - $scope.fileName = event.target.files[0].name; - // Grab the key from the raw license file - const raw = new FileReader(); - // readAsFoo runs async - raw.onload = function() { - try { - $scope.newLicense.file = JSON.parse(raw.result); - } catch(err) { - ProcessErrors($rootScope, null, null, null, - {msg: i18n._('Invalid file format. Please upload valid JSON.')}); - } - }; - - try { - raw.readAsText(event.target.files[0]); - } catch(err) { - ProcessErrors($rootScope, null, null, null, - {msg: i18n._('Invalid file format. Please upload valid JSON.')}); - } - }; - - // HTML5 spec doesn't provide a way to customize file input css - // So we hide the default input, show our own, and simulate clicks to the hidden input - $scope.fakeClick = function() { - if($scope.user_is_superuser) { - $('#License-file').click(); - } - }; - - $scope.downloadLicense = function() { - $window.open('https://www.ansible.com/license', '_blank'); - }; - - $scope.submit = function() { - Wait('start'); - CheckLicense.post($scope.newLicense.file, $scope.newLicense.eula) - .then(() => { - reset(); - - ConfigService.delete(); - ConfigService.getConfig() - .then(function(config) { - delete($rootScope.features); - FeaturesService.get(); - - if ($scope.newLicense.pendo) { - pendoService.updatePendoTrackingState('detailed'); - pendoService.issuePendoIdentity(); - } else { - pendoService.updatePendoTrackingState('off'); - } - - if ($rootScope.licenseMissing === true) { - $state.go('dashboard', { - licenseMissing: false - }); - } else { - init(config); - $scope.success = true; - $rootScope.licenseMissing = false; - // for animation purposes - const successTimeout = setTimeout(function() { - $scope.success = false; - clearTimeout(successTimeout); - }, 4000); - } - }); - }); - }; -}]; diff --git a/awx/ui/client/src/license/license.partial.html b/awx/ui/client/src/license/license.partial.html deleted file mode 100644 index 5c2acf0e5d3f..000000000000 --- a/awx/ui/client/src/license/license.partial.html +++ /dev/null @@ -1,146 +0,0 @@ -
-
-
-
Details
-
-
-
License
-
- Valid License - Invalid License -
-
-
-
Version
-
- {{license.version}} -
-
-
-
License Type
-
- {{license.license_info.license_type}} -
-
-
-
Subscription
-
- {{license.license_info.subscription_name}} -
-
-
-
License Key
-
- {{license.license_info.license_key}} -
-
-
-
Expires On
-
- {{time.expiresOn}} -
-
-
-
Time Remaining
-
- {{time.remaining}} -
-
-
-
Hosts Available
-
- {{license.license_info.available_instances}} -
-
-
-
Hosts Used
-
- {{license.license_info.current_instances}} -
-
-
-
Hosts Remaining
-
- {{license.license_info.free_instances}} -
-
-
-
If you are ready to upgrade, please contact us by clicking the button below
- -
-
-
-
-
{{title}}
-
-
Welcome to Ansible Tower! Please complete the steps below to acquire a license.
-
- - 1 - - - Please click the button below to visit Ansible's website to get a Tower license key. - -
- - - -
- - 2 - - - Choose your license file, agree to the End User License Agreement, and click submit. - -
- -
-
- * - License File -
-
- Browse - {{fileName|translate}} - -
-
- * - End User License Agreement -
-
{{ license.eula }}
-
-
- -
-
-
-
- -
-
-
- - Save successful! -
-
-
-
-
-
diff --git a/awx/ui/client/src/license/license.route.js b/awx/ui/client/src/license/license.route.js deleted file mode 100644 index 98ba25d79c64..000000000000 --- a/awx/ui/client/src/license/license.route.js +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../shared/template-url/template-url.factory'; -import { N_ } from '../i18n'; -import _ from 'lodash'; - -export default { - name: 'license', - route: '/license', - templateUrl: templateUrl('license/license'), - controller: 'licenseController', - data: {}, - ncyBreadcrumb: { - label: N_('LICENSE') - }, - onEnter: ['$state', 'ConfigService', (state, configService) => { - return configService.getConfig() - .then(config => { - if (_.get(config, 'license_info.license_type') === 'open') { - return state.go('setup'); - } - }); - }], - resolve: { - features: ['CheckLicense', '$rootScope', - function(CheckLicense, $rootScope) { - if($rootScope.licenseMissing === undefined){ - return CheckLicense.notify(); - } - - }], - config: ['ConfigService', 'CheckLicense', '$rootScope', - function(ConfigService, CheckLicense, $rootScope) { - ConfigService.delete(); - return ConfigService.getConfig() - .then(function(config){ - $rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false; - return config; - }); - }] - }, -}; diff --git a/awx/ui/client/src/license/main.js b/awx/ui/client/src/license/main.js deleted file mode 100644 index 90c5ff36f307..000000000000 --- a/awx/ui/client/src/license/main.js +++ /dev/null @@ -1,19 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './license.route'; -import controller from './license.controller'; -import CheckLicense from './checkLicense.factory'; -import fileOnChange from './fileOnChange.directive'; - -export default - angular.module('license', []) - .controller('licenseController', controller) - .directive('fileOnChange', fileOnChange) - .factory('CheckLicense', CheckLicense) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route); - }]); diff --git a/awx/ui/client/src/login/authenticationServices/authentication.service.js b/awx/ui/client/src/login/authenticationServices/authentication.service.js deleted file mode 100644 index 6285d8d43c3b..000000000000 --- a/awx/ui/client/src/login/authenticationServices/authentication.service.js +++ /dev/null @@ -1,177 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - - /** - * @ngdoc function - * @name shared.function:AuthService - * @description AuthService.js - * - * User authentication functions - * - */ - -export default - ['$http', '$rootScope', '$cookies', 'GetBasePath', 'Store', '$q', - '$injector', - function ($http, $rootScope, $cookies, GetBasePath, Store, $q, - $injector) { - return { - setToken: function (token, expires) { - $cookies.remove('token_expires'); - $cookies.remove('userLoggedIn'); - - $cookies.put('token_expires', expires); - $cookies.put('userLoggedIn', true); - $cookies.put('sessionExpired', false); - - $rootScope.userLoggedIn = true; - $rootScope.token_expires = expires; - $rootScope.sessionExpired = false; - }, - - isUserLoggedIn: function () { - if ($rootScope.userLoggedIn === undefined) { - // Browser refresh may have occurred - $rootScope.userLoggedIn = ($cookies.get('userLoggedIn') === 'true'); - $rootScope.sessionExpired = ($cookies.get('sessionExpired') === 'true'); - } - return $rootScope.userLoggedIn; - }, - retrieveToken: function (username, password) { - var getCSRFToken = $http({ - method: 'GET', - url: `/api/login/` - }); - - return getCSRFToken.then(function({data}) { - var csrfmiddlewaretoken = /name='csrfmiddlewaretoken' value='([0-9a-zA-Z]+)' \//.exec(data)[1]; - return $http({ - method: 'POST', - url: `/api/login/`, - data: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&csrfmiddlewaretoken=${csrfmiddlewaretoken}&next=%2fapi%2f`, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - }); - }); - }, - deleteToken: function () { - return $http({ - method: 'GET', - url: '/api/logout/' - }); - }, - - logout: function () { - // the following puts our primary scope up for garbage collection, which - // should prevent content flash from the prior user. - - var x, - deferred = $q.defer(), - ConfigService = $injector.get('ConfigService'), - SocketService = $injector.get('SocketService'), - scope = angular.element(document.getElementById('main-view')).scope(); - - this.deleteToken().then(() => { - if(scope){ - scope.$destroy(); - } - - if($cookies.get('lastPath')==='/portal'){ - $cookies.put( 'lastPath', '/portal'); - $rootScope.lastPath = '/portal'; - } - else if ($cookies.get('lastPath') !== '/home' || $cookies.get('lastPath') !== '/' || $cookies.get('lastPath') !== '/login' || $cookies.get('lastPath') !== '/logout'){ - // do nothing - $rootScope.lastPath = $cookies.get('lastPath'); - } - else { - // your last path was home - $cookies.remove('lastPath'); - $rootScope.lastPath = '/home'; - } - x = Store('sessionTime'); - if ($rootScope.current_user && x && x[$rootScope.current_user.id]) { - x[$rootScope.current_user.id].loggedIn = false; - } - Store('sessionTime', x); - - if ($cookies.getObject('current_user')) { - $rootScope.lastUser = $cookies.getObject('current_user').id; - } - ConfigService.delete(); - SocketService.disconnect(); - $cookies.remove('token_expires'); - $cookies.remove('current_user'); - $cookies.put('userLoggedIn', false); - $cookies.put('sessionExpired', false); - $cookies.putObject('current_user', {}); - $rootScope.current_user = {}; - $rootScope.license_tested = undefined; - $rootScope.userLoggedIn = false; - $rootScope.sessionExpired = false; - $rootScope.licenseMissing = true; - $rootScope.token_expires = null; - $rootScope.login_username = null; - $rootScope.login_password = null; - if ($rootScope.sessionTimer) { - $rootScope.sessionTimer.clearTimers(); - } - deferred.resolve(); - }); - - return deferred.promise; - - }, - - licenseTested: function () { - var license, result; - if ($rootScope.license_tested !== undefined) { - result = $rootScope.license_tested; - } else { - // User may have hit browser refresh - license = Store('license'); - $rootScope.version = license.version; - if (license && license.tested !== undefined) { - result = license.tested; - } else { - result = false; - } - } - return result; - }, - - getUser: function () { - return $http({ - method: 'GET', - url: GetBasePath('me') - }); - }, - - setUserInfo: function (response) { - // store the response values in $rootScope so we can get to them later - $rootScope.current_user = response.results[0]; - $cookies.putObject('current_user', response.results[0]); //keep in session cookie in the event of browser refresh - }, - - restoreUserInfo: function () { - $rootScope.current_user = $cookies.getObject('current_user'); - }, - - getUserInfo: function (key) { - // Access values returned from the Me API call - var cu; - if ($rootScope.current_user) { - return $rootScope.current_user[key]; - } - this.restoreUserInfo(); - cu = $cookies.getObject('current_user'); - return cu[key]; - } - }; - } -]; diff --git a/awx/ui/client/src/login/authenticationServices/isAdmin.factory.js b/awx/ui/client/src/login/authenticationServices/isAdmin.factory.js deleted file mode 100644 index 41b1b29447be..000000000000 --- a/awx/ui/client/src/login/authenticationServices/isAdmin.factory.js +++ /dev/null @@ -1,18 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name - * @description - * - * - */ - - export default - ['$rootScope', function($rootScope) { - return function() { return ($rootScope.current_user && $rootScope.current_user.is_superuser); }; - }]; diff --git a/awx/ui/client/src/login/authenticationServices/main.js b/awx/ui/client/src/login/authenticationServices/main.js deleted file mode 100644 index 11bb9987107c..000000000000 --- a/awx/ui/client/src/login/authenticationServices/main.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import authenticationService from './authentication.service'; -import isAdmin from './isAdmin.factory'; -import timer from './timer.factory'; -import pendoService from './pendo.service'; - -export default - angular.module('authentication', []) - .factory('Authorization', authenticationService) - .factory('IsAdmin', isAdmin) - .factory('Timer', timer) - .service('pendoService', pendoService); diff --git a/awx/ui/client/src/login/authenticationServices/pendo.service.js b/awx/ui/client/src/login/authenticationServices/pendo.service.js deleted file mode 100644 index a7296f6d8b4e..000000000000 --- a/awx/ui/client/src/login/authenticationServices/pendo.service.js +++ /dev/null @@ -1,148 +0,0 @@ -/************************************************* -* Copyright (c) 2015 Ansible, Inc. -* -* All Rights Reserved -*************************************************/ - - -export default ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', '$q', 'ConfigService', '$log', - 'AppStrings', - function ($rootScope, Rest, GetBasePath, ProcessErrors, $q, ConfigService, $log, AppStrings) { - return { - setPendoOptions: function (config) { - const tower_version = config.version.split('-')[0]; - const trial = (config.trial) ? config.trial : false; - let options = { - apiKey: AppStrings.get('PENDO_API_KEY'), - visitor: { - id: null, - role: null, - }, - account: { - id: null, - planLevel: config.license_type, - planPrice: config.instance_count, - creationDate: config.license_date, - trial: trial, - tower_version: tower_version, - ansible_version: config.ansible_version - } - }; - - if (config.analytics_status === 'detailed') { - this.setDetailed(options, config); - } else if (config.analytics_status === 'anonymous') { - this.setAnonymous(options); - } - - return options; - }, - - // Detailed mode sends: - // VisitorId: userid+hash of license_key - // AccountId: hash of license_key from license - setDetailed: function(options, config) { - // config.deployment_id is a hash of the tower license_key - options.visitor.id = $rootScope.current_user.id + '@' + config.deployment_id; - options.account.id = config.deployment_id; - }, - - // Anonymous mode sends: - // VisitorId: - // AccountId: - setAnonymous: function (options) { - options.visitor.id = 0; - options.account.id = "tower.ansible.com"; - }, - - setRole: function(options) { - const deferred = $q.defer(); - - if ($rootScope.current_user.is_superuser === true) { - options.visitor.role = 'admin'; - deferred.resolve(options); - } else { - Rest.setUrl(GetBasePath('users') + $rootScope.current_user.id + - '/admin_of_organizations/'); - Rest.get() - .then(function (response) { - if (response.data.count > 0) { - options.visitor.role = "orgadmin"; - deferred.resolve(options); - } else { - options.visitor.role = "user"; - deferred.resolve(options); - } - }) - .catch(function (response) { - ProcessErrors($rootScope, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get admin of org user list. GET returned status: ' + - response.status }); - deferred.reject('Could not resolve pendo role.'); - }); - } - - return deferred.promise; - }, - - bootstrap: function(){ - /* jshint ignore:start */ - (function(p,e,n,d,o){var v,w,x,y,z;o=p[d]=p[d]||{};o._q=[]; - v=['initialize','identify','updateOptions','pageLoad'];for(w=0,x=v.length;w - - diff --git a/awx/ui/client/src/login/loginModal/loginModal.block.less b/awx/ui/client/src/login/loginModal/loginModal.block.less deleted file mode 100644 index fc0dd5959b20..000000000000 --- a/awx/ui/client/src/login/loginModal/loginModal.block.less +++ /dev/null @@ -1,155 +0,0 @@ -/** @define LoginModal */ -.LoginModal-backDrop { - width: 100vw; - height: 100vh; - position: fixed; - top: 0; - left: 0; - z-index: 1041; - opacity: 0; - transition: 0.5s opacity; -} - -.LoginModal-backDrop.is-loggedOut { - opacity: 0.2; -} - -.LoginModal-dialog { - margin: 30px auto; - margin-top: 95px; -} - -.LoginModal-content { - max-width: 550px; - margin-left: auto; - margin-right: auto; - border: 0; - box-shadow: none; - background-color: #ddd; - border-radius: 4px; - opacity: 0; - transition: opacity 0.5s; - z-index: 1042; - position: relative; -} - -.LoginModal-content.is-loggedOut { - opacity: 1; - transition: opacity 0.5s; -} - -.LoginModal-header { - text-align: left; - background-color: #bbb; - border-bottom: 0; - border-top-right-radius: 4px; - border-top-left-radius: 4px; -} - -.LoginModal-body { - padding-top: 15px; - padding-bottom: 0px; - padding-left: 20px; - padding-right: 20px; -} - -.LoginModal-logoImage { - max-width: 112px; - margin: 20px 20px 10px 20px; -} - -.LoginModal-logoImage--notCustom { - max-width: @login-max-width; -} - -.LoginModal-alert { - margin-bottom: 20px; - font-size: 16px; - font-weight: normal; - color: @login-alert; - transition: opacity 0.2s; -} - -.LoginModal-alert--error { - color: @login-alert-error; - padding-bottom: 4px; -} - -.LoginModal-alert { - opacity: 1; - display: flex; -} - -.LoginModal-alert.ng-hide { - display: none; - opacity: 0; -} - -.LoginModal-alert.ng-hide-add { - display: none; - opacity: 0; -} - -.LoginModal-alert.ng-hide-remove { - display: block; -} - -.LoginModal-alertIcon { - display: flex; - align-items: center; - line-height: 19px; -} - -.LoginModal-alertIcon:before { - margin-right: 10px; -} - -.LoginModal-formGroup { - margin-bottom: 20px; -} - -.LoginModal-label { - color: @field-label; - font-weight: 400; -} - -.LoginModal-field { - color: @field-input-text; - background-color: @field-bg; - border: 1px solid @field-border; -} - -.LoginModal-footer { - display: flex; - flex-wrap: wrap-reverse; - align-items: center; - padding: 20px; - padding-top: 5px; - padding-bottom: 0px; - margin-top: 20px; -} - -.LoginModal-footerBlock { - flex: 1 0 auto; - margin-bottom: 20px; - display: flex; - max-width: 100%; -} - -.LoginModal-footerBlock--submit { - flex: initial; - margin-left: auto; - padding-left: 20px; -} - -.LoginModal-signInButton { - transition: background-color 0.2s; - background-color: @submit-button-bg; - color: @submit-button-text; -} - -.LoginModal-signInButton:hover, -.LoginModal-signInButton:focus { - color: @submit-button-text; - background-color: @submit-button-bg-hov; -} diff --git a/awx/ui/client/src/login/loginModal/loginModal.controller.js b/awx/ui/client/src/login/loginModal/loginModal.controller.js deleted file mode 100644 index a63963c2bc28..000000000000 --- a/awx/ui/client/src/login/loginModal/loginModal.controller.js +++ /dev/null @@ -1,176 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Authentication - * @description - * Controller for handling /#/login and /#/logout routes. - * - * (app.js) verifies the user is authenticated and that the user session is not expired. If either condition is not true, - * the user is redirected to /#/login and the Authentication controller. - * - * Methods for checking the session state are found in [js/shared/AuthService.js](/static/docs/api/shared.function:AuthService), which is referenced here as Authorization. - * - * #Login Modal Dialog - * - * The modal dialog prompting for username and password is found in templates/ui/index.html. - *``` - * - * - *``` - * HTML for the login form is generated, compiled and injected into
by the controller. This is done to associate the form with the controller's scope. Because - *
is outside of the ng-view container, it gets associated with $rootScope by default. In the controller we create a new scope using $rootScope.$new() and associate - * that with the login form. Doing this each time the controller is instantiated insures the form is clean and not pre-populated with a prior user's username and password. - * - * Just before the release of 2.0 a bug was discovered where clicking logout and then immediately clicking login without providing a username and password would successfully log - * the user back into the app. Implementing the above approach fixed this, forcing a new username/password to be entered each time the login dialog appears. - * - * - * @Usage - * This is usage information. - */ - -export default ['$log', '$cookies', '$compile', '$rootScope', - '$location', 'Authorization', 'Alert', 'Wait', 'Timer', - 'Empty', '$scope', 'pendoService', 'ConfigService', - 'CheckLicense', 'FeaturesService', 'SocketService', - function ($log, $cookies, $compile, $rootScope, $location, - Authorization, Alert, Wait, Timer, Empty, - scope, pendoService, ConfigService, CheckLicense, FeaturesService, - SocketService) { - var lastPath, lastUser, sessionExpired, loginAgain, preAuthUrl; - - loginAgain = function() { - setTimeout(function() { - $location.path('/logout'); - }, 1000); - }; - - scope.sessionExpired = (Empty($rootScope.sessionExpired)) ? $cookies.get('sessionExpired') : $rootScope.sessionExpired; - scope.login_username = ''; - scope.login_password = ''; - - - lastPath = function () { - return (Empty($rootScope.lastPath)) ? $cookies.get('lastPath') : $rootScope.lastPath; - }; - - lastUser = function(){ - if(!Empty($rootScope.lastUser) && $rootScope.lastUser === $rootScope.current_user.id){ - return true; - } - else { - return false; - } - }; - - preAuthUrl = $rootScope.preAuthUrl; - - $log.debug('User session expired: ' + sessionExpired); - $log.debug('Last URL: ' + lastPath()); - - $rootScope.loginConfig.promise.then(function () { - if ($AnsibleConfig.custom_logo) { - scope.customLogo = $rootScope.custom_logo; - scope.customLogoPresent = true; - } else { - scope.customLogo = "logo-login.svg"; - scope.customLogoPresent = false; - } - scope.customLoginInfo = $AnsibleConfig.custom_login_info; - scope.customLoginInfoPresent = (scope.customLoginInfo) ? true : false; - }); - - if (scope.removeAuthorizationGetLicense) { - scope.removeAuthorizationGetLicense(); - } - scope.removeAuthorizationGetLicense = scope.$on('AuthorizationGetLicense', function() { - ConfigService.getConfig().then(function(){ - CheckLicense.test(); - pendoService.issuePendoIdentity(); - FeaturesService.get(); - Wait("stop"); - if(!Empty(preAuthUrl)){ - $location.path(preAuthUrl); - delete $rootScope.preAuthUrl; - } - else { - if (lastPath() && lastUser()) { - // Go back to most recent navigation path - $location.path(lastPath()); - } else { - $location.url('/home'); - } - } - }) - .catch(function () { - Wait('stop'); - Alert('Error', 'Failed to access license information. GET returned status: ' + status, 'alert-danger', loginAgain); - }); - }); - - if (scope.removeAuthorizationGetUser) { - scope.removeAuthorizationGetUser(); - } - scope.removeAuthorizationGetUser = scope.$on('AuthorizationGetUser', function() { - // Get all the profile/access info regarding the logged in user - Authorization.getUser() - .then(({data}) => { - Authorization.setUserInfo(data); - Timer.init().then(function(timer){ - $rootScope.sessionTimer = timer; - SocketService.init(); - $rootScope.user_is_superuser = data.results[0].is_superuser; - $rootScope.user_is_system_auditor = data.results[0].is_system_auditor; - scope.$emit('AuthorizationGetLicense'); - }); - }) - .catch(({data, status}) => { - Authorization.logout().then( () => { - Wait('stop'); - Alert('Error', 'Failed to access user information. GET returned status: ' + status, 'alert-danger', loginAgain); - }); - }); - }); - - // Call the API to get an auth token - scope.systemLogin = function (username, password) { - $('.api-error').empty(); - if (Empty(username) || Empty(password)) { - scope.reset(); - scope.attemptFailed = true; - $('#login-username').focus(); - } else { - Wait('start'); - Authorization.retrieveToken(username, password) - .then(function (data) { - $('#login-modal').modal('hide'); - Authorization.setToken(data.data.expires); - scope.$emit('AuthorizationGetUser'); - }, - function (data) { - var key; - Wait('stop'); - if (data && data.data && data.data.non_field_errors && data.data.non_field_errors.length === 0) { - // show field specific errors returned by the API - for (key in data.data) { - scope[key + 'Error'] = data.data[key][0]; - } - } else { - scope.reset(); - scope.attemptFailed = true; - $('#login-username').focus(); - } - }); - } - }; -}]; diff --git a/awx/ui/client/src/login/loginModal/loginModal.directive.js b/awx/ui/client/src/login/loginModal/loginModal.directive.js deleted file mode 100644 index f9b3f8866b73..000000000000 --- a/awx/ui/client/src/login/loginModal/loginModal.directive.js +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import authenticationController from './loginModal.controller'; - -/* jshint unused: vars */ -export default - [ 'templateUrl', - 'Wait', - function(templateUrl, Wait) { - return { - restrict: 'E', - scope: true, - controller: authenticationController, - templateUrl: templateUrl('login/loginModal/loginModal'), - link: function(scope, element, attrs) { - var setLoginFocus = function () { - // Need to clear out any open dialog windows that might be open when this modal opens. - $('#login-username').focus(); - }; - - setLoginFocus(); - - // Hide any lingering modal dialogs - $('.modal[aria-hidden=false]').each(function () { - if ($(this).attr('id') !== 'login-modal') { - $(this).modal('hide'); - } - }); - - // Just in case, make sure the wait widget is not active - // and scroll the window to the top - Wait('stop'); - window.scrollTo(0,0); - - // Set focus to username field - $('#login-modal').on('shown.bs.modal', function () { - setLoginFocus(); - }); - - $('#login-password').bind('keypress', function (e) { - var code = (e.keyCode ? e.keyCode : e.which); - if (code === 13) { - $('#login-button').click(); - } - }); - - scope.reset = function () { - $('#login-form input').each(function () { - $(this).val(''); - }); - }; - } - }; - } - ]; diff --git a/awx/ui/client/src/login/loginModal/loginModal.partial.html b/awx/ui/client/src/login/loginModal/loginModal.partial.html deleted file mode 100644 index beecdbe0344c..000000000000 --- a/awx/ui/client/src/login/loginModal/loginModal.partial.html +++ /dev/null @@ -1,106 +0,0 @@ -
-
-
-
-
- - -
-
-
- Welcome to Ansible {{BRAND_NAME}}!  Please sign in. -
-
- -
- Your session timed out due to inactivity. Please sign in. -
-
-
- -
- Maximum per-user sessions reached. Please sign in. -
-
-
- -
- Invalid username and/or password. Please try again. -
-
-
- -
- {{ thirdPartyAttemptFailed }} -
-
-
-
- -
- -
- Please enter a username. -
-
-
-
-
- -
- -
- Please enter a password. -
-
-
-
-
-
NOTICE
{{ customLoginInfo | sanitize }}
-
- -
-
-
diff --git a/awx/ui/client/src/login/loginModal/loginModalNotice.block.less b/awx/ui/client/src/login/loginModal/loginModalNotice.block.less deleted file mode 100644 index 57cb035e8c29..000000000000 --- a/awx/ui/client/src/login/loginModal/loginModalNotice.block.less +++ /dev/null @@ -1,23 +0,0 @@ -/** @define LoginModalNotice */ -.LoginModalNotice { - font-size: 12px; - width: 100%; - max-height: 129px; - padding: 15px; - padding-top: 10px; - margin-bottom: 15px; - border-radius: 4px; - border: 1px solid @login-notice-border; - background-color: @login-notice-bg; - color: @login-notice-text; - overflow-y: scroll; - overflow-x: visible; - white-space: pre-wrap; -} - -.LoginModalNotice-title { - color: @login-notice-title; - font-weight: bold; - padding-bottom: 4px; - font-size: 14px; -} diff --git a/awx/ui/client/src/login/loginModal/main.js b/awx/ui/client/src/login/loginModal/main.js deleted file mode 100644 index 3d063d4e1c80..000000000000 --- a/awx/ui/client/src/login/loginModal/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import thirdPartySignOn from './thirdPartySignOn/main'; - -import loginModalDirective from './loginModal.directive'; - -export default - angular.module('loginModal', [thirdPartySignOn.name]) - .directive('loginModal', loginModalDirective); diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/main.js b/awx/ui/client/src/login/loginModal/thirdPartySignOn/main.js deleted file mode 100644 index e6f5f08b64c7..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import thirdPartySignOnDirective from './thirdPartySignOn.directive'; -import thirdPartySignOnService from './thirdPartySignOn.service'; - -export default - angular.module('thirdPartySignOn', []) - .directive('thirdPartySignOn', thirdPartySignOnDirective) - .factory('thirdPartySignOnService', thirdPartySignOnService); diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less deleted file mode 100644 index d61006bf505d..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less +++ /dev/null @@ -1,51 +0,0 @@ -/** @define ThirdPartySignOn */ - -.ThirdPartySignOn { - display: flex; - align-items: center; -} - -.ThirdPartySignOn-label { - flex: initial; - color: @third-party-label; -} - -.ThirdPartySignOn-item { - margin-left: 15px; -} - -.ThirdPartySignOn-button { - transition: color 0.2s; - flex: 1 0 auto; - height: 30px; - width: 30px; - border-radius: 50%; - color: @third-party-btn-text; - background-color: @third-party-btn-bg; - border: 0; - padding: 0; -} - -.ThirdPartySignOn-button--error { - color: @third-party-error; -} - -.ThirdPartySignOn-button:hover { - color: @third-party-btn-hov; -} - -.ThirdPartySignOn-button--error:hover { - color: @third-party-error-hov; -} - -.ThirdPartySignOn-icon { - font-size: 35px; -} - -.ThirdPartySignOn-icon--gitHub { - margin-top: -3px; -} - -.ThirdPartySignOn-icon--fontCustom { - font-size: 30px; -} diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.controller.js b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.controller.js deleted file mode 100644 index 8222eb8d4438..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.controller.js +++ /dev/null @@ -1,36 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:thirdPartySignOn - * @description - * Controller for handling third party supported login options. - */ - -export default ['$window', '$scope', 'thirdPartySignOnService', - function ($window, $scope, thirdPartySignOnService) { - - thirdPartySignOnService( - {scope: $scope, url: "api/v2/auth/"}).then(function (data) { - if (data && data.options && data.options.length > 0) { - $scope.thirdPartyLoginSupported = true; - $scope.loginItems = data.options; - } else { - $scope.thirdPartyLoginSupported = false; - } - - if (data && data.error) { - $scope.$parent.thirdPartyAttemptFailed = data.error; - } - }); - - $scope.goTo = function(link) { - // this is used because $location only lets you navigate inside - // the "/#/" path, and these are API urls. - $window.location.href = link; - }; - }]; diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.directive.js b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.directive.js deleted file mode 100644 index 91c6a085c241..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.directive.js +++ /dev/null @@ -1,23 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/* jshint unused: vars */ - -import thirdPartySignOnController from './thirdPartySignOn.controller'; - -export default - [ 'templateUrl', - function(templateUrl) { - return { - restrict: 'E', - scope: true, - controller: thirdPartySignOnController, - templateUrl: templateUrl('login/loginModal/thirdPartySignOn/thirdPartySignOn'), - link: function(scope, element, attrs) { - } - }; - } - ]; diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html deleted file mode 100644 index 9413193570ff..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- SIGN IN WITH -
-
- -
-
diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js deleted file mode 100644 index afc2c97a1770..000000000000 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js +++ /dev/null @@ -1,121 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:Permissions - * @description - * Gets the configured auth types based on the configurations set in the server - * - */ - - export default - ['$http', '$log', 'i18n', function($http, $log, i18n) { - return function (params) { - var url = params.url; - - return $http({ - method: 'GET', - url: url, - }).then(function (data) { - var options = [], - error = ""; - - function parseAzure(option) { - var newOption = {}; - - newOption.type = "azure"; - newOption.icon = "ThirdPartySignOn-icon--fontCustom icon-microsoft"; - newOption.link = option.login_url; - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s"), "Azure AD"); - - return newOption; - } - - function parseGoogle(option) { - var newOption = {}; - - newOption.type = "google"; - newOption.icon = "ThirdPartySignOn-icon--fontCustom icon-google"; - newOption.link = option.login_url; - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s"), "Google"); - - return newOption; - } - - function parseGithub(option, key) { - var newOption = {}; - - newOption.type = "github"; - newOption.icon = "fa-github ThirdPartySignOn-icon--gitHub"; - newOption.link = option.login_url; - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s"), "GitHub"); - - // if this is a GitHub team or org, add that to - // the tooltip - if (key.split("-")[1]){ - if (key.split("-")[1] === "team") { - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s Teams"), "GitHub"); - } else if (key.split("-")[1] === "org") { - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s Organizations"), "GitHub"); - } - } - - return newOption; - } - - function parseSaml(option, key) { - var newOption = {}; - - newOption.type = "saml"; - newOption.icon = "ThirdPartySignOn-icon--fontCustom icon-saml-02"; - newOption.link = option.login_url; - newOption.tooltip = i18n.sprintf(i18n._("Sign in with %s"), "SAML"); - - // add the idp of the saml type to the tooltip - if (key.split(":")[1]){ - newOption.tooltip += " (" + key.split(":")[1] + ")"; - } - - return newOption; - } - - function parseLoginOption(option, key) { - var finalOption; - - // set up the particular tooltip, icon, etc. - // needed by the login type - if (key.split("-")[0] === "azuread") { - finalOption = parseAzure(option, key); - } else if (key.split("-")[0] === "google") { - finalOption = parseGoogle(option, key); - } else if (key.split("-")[0] === "github") { - finalOption = parseGithub(option, key); - } else if (key.split(":")[0] === "saml") { - finalOption = parseSaml(option, key); - } - - // set the button to error red and set the error message to be passed to the login modal. - if (option.error) { - finalOption.button = "ThirdPartySignOn-button--error"; - error = option.error; - } - - options.push(finalOption); - } - - // iterate over each login option passed from the API - _.forEach(data.data, parseLoginOption); - - // return the options and the error to be utilized - // by the loginModal - return {"options": options, "error": error}; - }) - .catch(function (data) { - $log.error('Failed to get third-party login types. Returned status: ' + data.status ); - }); - }; - }]; diff --git a/awx/ui/client/src/login/logout.route.js b/awx/ui/client/src/login/logout.route.js deleted file mode 100644 index 47da767ec50d..000000000000 --- a/awx/ui/client/src/login/logout.route.js +++ /dev/null @@ -1,22 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import {templateUrl} from '../../shared/template-url/template-url.factory'; - -export default { - name: 'signOut', - route: '/logout', - controller: ['Authorization', '$state', function(Authorization, $state) { - Authorization.logout().then( () =>{ - $state.go('signIn'); - }); - - }], - ncyBreadcrumb: { - skip: true - }, - templateUrl: '/static/partials/blank.html' -}; diff --git a/awx/ui/client/src/login/main.js b/awx/ui/client/src/login/main.js deleted file mode 100644 index 4835feebd3d6..000000000000 --- a/awx/ui/client/src/login/main.js +++ /dev/null @@ -1,18 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import authentication from './authenticationServices/main'; -import loginModal from './loginModal/main'; - -import loginRoute from './login.route'; -import logoutRoute from './logout.route'; - -export default - angular.module('login', [authentication.name, loginModal.name]) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(loginRoute); - $stateExtender.addState(logoutRoute); - }]); diff --git a/awx/ui/client/src/management-jobs/card/card.controller.js b/awx/ui/client/src/management-jobs/card/card.controller.js deleted file mode 100644 index 5b6bff4f44aa..000000000000 --- a/awx/ui/client/src/management-jobs/card/card.controller.js +++ /dev/null @@ -1,147 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default - [ 'Wait', 'CreateDialog', 'GetBasePath' , - 'Rest' , - 'ProcessErrors', '$rootScope', '$state', - '$scope', 'CreateSelect2', 'i18n', '$transitions', - function( Wait, CreateDialog, GetBasePath, - Rest, ProcessErrors, - $rootScope, $state, $scope, - CreateSelect2, i18n, $transitions) { - - var defaultUrl = GetBasePath('system_job_templates') + "?order_by=name"; - - var getManagementJobs = function(){ - Rest.setUrl(defaultUrl); - Rest.get() - .then(({data}) => { - $scope.mgmtCards = data.results; - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, {hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Call to %s failed. Return status: %d'), (defaultUrl === undefined) ? "undefined" : defaultUrl, status )}); - }); - }; - getManagementJobs(); - - $scope.cleanupJob = true; - // This handles the case where the user refreshes the management job notifications page. - if($state.current.name === 'managementJobsList.notifications') { - $scope.activeCard = parseInt($state.params.management_id); - $scope.cardAction = "notifications"; - } - - $scope.goToNotifications = function(card){ - $state.transitionTo('managementJobsList.notifications',{ - card: card, - management_id: card.id - }); - }; - - $scope.submitJob = function (id, name) { - Wait('start'); - defaultUrl = GetBasePath('system_job_templates')+id+'/launch/'; - CreateDialog({ - id: 'prompt-for-days' , - title: name, - scope: $scope, - width: 500, - height: 300, - minWidth: 200, - callback: 'PromptForDays', - resizable: false, - onOpen: function(){ - $scope.$watch('prompt_for_days_form.$invalid', function(invalid) { - if (invalid === true) { - $('#prompt-for-days-launch').prop("disabled", true); - } else { - $('#prompt-for-days-launch').prop("disabled", false); - } - }); - - let fieldScope = $scope.$parent; - fieldScope.days_to_keep = 30; - $scope.prompt_for_days_form.$setPristine(); - $scope.prompt_for_days_form.$invalid = false; - }, - buttons: [ - { - "label": "Cancel", - "onClick": function() { - $(this).dialog('close'); - - }, - "class": "btn btn-default", - "id": "prompt-for-days-cancel" - }, - { - "label": "Launch", - "onClick": function() { - const extra_vars = {"days": $scope.days_to_keep }, - data = {}; - data.extra_vars = JSON.stringify(extra_vars); - - Rest.setUrl(defaultUrl); - Rest.post(data) - .then(({data}) => { - Wait('stop'); - $("#prompt-for-days").dialog("close"); - // $("#configure-dialog").dialog('close'); - $state.go('output', { id: data.system_job, type: 'system' }, { reload: true }); - }) - .catch(({data, status}) => { - let template_id = $scope.job_template_id; - template_id = (template_id === undefined) ? "undefined" : i18n.sprintf("%d", template_id); - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Failed updating job %s with variables. POST returned: %d'), template_id, status) }); - }); - }, - "class": "btn btn-primary", - "id": "prompt-for-days-launch" - } - ] - }); - - if ($scope.removePromptForDays) { - $scope.removePromptForDays(); - } - $scope.removePromptForDays = $scope.$on('PromptForDays', function() { - // $('#configure-dialog').dialog('close'); - $('#prompt-for-days').show(); - $('#prompt-for-days').dialog('open'); - Wait('stop'); - }); - }; - - $scope.configureSchedule = function(id) { - $state.transitionTo('managementJobsList.schedule', { - id: id - }); - }; - - var cleanUpStateChangeListener = $transitions.onSuccess({}, function(trans) { - if(trans.to().name === "managementJobsList") { - // We are on the management job list view - nothing needs to be highlighted - delete $scope.activeCard; - delete $scope.cardAction; - } - else if(trans.to().name === "managementJobsList.notifications") { - // We are on the notifications view - update the active card and the action - $scope.activeCard = parseInt(trans.params('to').management_id); - $scope.cardAction = "notifications"; - } - }); - - // Remove the listener when the scope is destroyed to avoid a memory leak - $scope.$on('$destroy', function() { - cleanUpStateChangeListener(); - }); - } - ]; diff --git a/awx/ui/client/src/management-jobs/card/card.partial.html b/awx/ui/client/src/management-jobs/card/card.partial.html deleted file mode 100644 index 008786dc7f6b..000000000000 --- a/awx/ui/client/src/management-jobs/card/card.partial.html +++ /dev/null @@ -1,45 +0,0 @@ -
- -
-
-
-
- MANAGEMENT JOBS -
- - {{ mgmtCards.length }} - -
-
-
- -
-

{{ card.name }}

-
- - - -
-
- - -

{{card.description || "Place organization description here"}}

- -
-
-
diff --git a/awx/ui/client/src/management-jobs/card/card.route.js b/awx/ui/client/src/management-jobs/card/card.route.js deleted file mode 100644 index 6ad8d5c448fe..000000000000 --- a/awx/ui/client/src/management-jobs/card/card.route.js +++ /dev/null @@ -1,22 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../../shared/template-url/template-url.factory'; -import {N_} from "../../i18n"; - -export default { - name: 'managementJobsList', - route: '/management_jobs', - templateUrl: templateUrl('management-jobs/card/card'), - controller: 'managementJobsCardController', - data: { - activityStream: true, - activityStreamTarget: 'job' - }, - ncyBreadcrumb: { - label: N_('MANAGEMENT JOBS') - }, -}; diff --git a/awx/ui/client/src/management-jobs/card/main.js b/awx/ui/client/src/management-jobs/card/main.js deleted file mode 100644 index e21f7f7e7303..000000000000 --- a/awx/ui/client/src/management-jobs/card/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './card.route'; -import controller from './card.controller'; - -export default - angular.module('managementJobsCard', []) - .controller('managementJobsCardController', controller) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route); - }]); diff --git a/awx/ui/client/src/management-jobs/card/mgmtcards.block.less b/awx/ui/client/src/management-jobs/card/mgmtcards.block.less deleted file mode 100644 index 57c09e84e3c0..000000000000 --- a/awx/ui/client/src/management-jobs/card/mgmtcards.block.less +++ /dev/null @@ -1,104 +0,0 @@ -.MgmtCards { - display: flex; - flex-flow: row wrap; -} - -.MgmtCards-card { - background-color: @default-bg; - padding: 20px; - border-radius: 5px; - border: 1px solid @b7grey; - align-items: baseline; - margin-top: 20px; - margin-right: 20px; - width: 32%; -} - -.MgmtCards-card--selected { - padding-left: 16px; - border-left: 5px solid @default-link; -} - -.MgmtCards-card--promptElements{ - padding-top: 10px; -} - -.MgmtCards-promptText{ - color:@default-interface-txt; -} - -.MgmtCards-header { - display: flex; - flex-wrap: nowrap; - align-items: baseline; - width: 100%; -} - -.MgmtCards-label { - margin-top: 0px; - font-size: 14px; - font-weight: bold; - color: @default-interface-txt; - margin-bottom: 25px; - overflow: hidden; - text-overflow: ellipsis; -} - -.MgmtCards-actionItems { - margin-left: auto; - display: flex; - flex-wrap: nowrap; -} - -.MgmtCards-actionItem { - margin-left: 15px; -} - -.MgmtCards-description { - margin-bottom: 20px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.MgmtCards-links { - width: 100%; - display: flex; - flex-wrap: wrap; - justify-content: space-between; -} - -.MgmtCards-link { - flex: initial; - width: ~"calc(50% - 20px)"; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-bottom: 20px; -} - -.MgmtCards-linkBadge { - margin-right: 10px; -} - -@media (max-width: 840px) { - .MgmtCards-card { - width: 100%; - margin-right: 0px; - } -} - -@media (min-width: 840px) and (max-width: 1240px) { - .MgmtCards-card { - width: ~"calc(50% - 10px)"; - } - } - -#prompt-for-days-facts, #prompt-for-days { - overflow-x: hidden; - font-family: "Open Sans"; - .label-text { - text-transform: uppercase; - font-weight: normal; - } -} diff --git a/awx/ui/client/src/management-jobs/main.js b/awx/ui/client/src/management-jobs/main.js deleted file mode 100644 index ef291e1ee5d9..000000000000 --- a/awx/ui/client/src/management-jobs/main.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import managementJobsCard from './card/main'; -import managementJobsScheduler from './scheduler/main'; -import managementJobsNotifications from './notifications/main'; - -export default - angular.module('managementJobs', [ - managementJobsCard.name, - managementJobsScheduler.name, - managementJobsNotifications.name - ]); diff --git a/awx/ui/client/src/management-jobs/notifications/main.js b/awx/ui/client/src/management-jobs/notifications/main.js deleted file mode 100644 index 91b92b53731e..000000000000 --- a/awx/ui/client/src/management-jobs/notifications/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './notification.route'; -import controller from './notification.controller'; - -export default - angular.module('managementJobsNotifications', []) - .controller('managementJobsNotificationsController', controller) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route); - }]); diff --git a/awx/ui/client/src/management-jobs/notifications/notification.controller.js b/awx/ui/client/src/management-jobs/notifications/notification.controller.js deleted file mode 100644 index 62e8dff8a3fd..000000000000 --- a/awx/ui/client/src/management-jobs/notifications/notification.controller.js +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ 'NotificationsList', 'GetBasePath', 'ToggleNotification', 'NotificationsListInit', - '$stateParams', 'Dataset', '$scope', - function( - NotificationsList, GetBasePath, ToggleNotification, NotificationsListInit, - $stateParams, Dataset, $scope) { - var defaultUrl = GetBasePath('system_job_templates'), - list = NotificationsList, - id = $stateParams.management_id; - - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - NotificationsListInit({ - scope: $scope, - url: defaultUrl, - id: id - }); - - $scope.$watch(`${list.iterator}_dataset`, function() { - // The list data has changed and we need to update which notifications are on/off - $scope.$emit('relatednotifications'); - }); - } - - $scope.toggleNotification = function(event, notifier_id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } - catch(e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: defaultUrl + id, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - - init(); - - } - ]; diff --git a/awx/ui/client/src/management-jobs/notifications/notification.route.js b/awx/ui/client/src/management-jobs/notifications/notification.route.js deleted file mode 100644 index a6b1f30d8a77..000000000000 --- a/awx/ui/client/src/management-jobs/notifications/notification.route.js +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import { N_ } from '../../i18n'; - -export default { - name: 'managementJobsList.notifications', - route: '/:management_id/notifications', - params: { - notification_search: {} - }, - searchPrefix: 'notification', - views: { - '@managementJobsList': { - controller: 'managementJobsNotificationsController', - templateProvider: function(NotificationsList, generateList, ParentObject, $filter) { - // include name of parent resource in listTitle - NotificationsList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('Notifications'); - let html = generateList.build({ - list: NotificationsList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return generateList.insertFormView() + html; - } - } - }, - resolve: { - Dataset: ['NotificationsList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('notification_templates')}`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath) { - let path = `${GetBasePath('system_job_templates')}${$stateParams.management_id}`; - Rest.setUrl(path); - return Rest.get(path).then((res) => res.data); - }] - }, - ncyBreadcrumb: { - parent: 'managementJobsList', - label: N_('NOTIFICATIONS') - } -}; diff --git a/awx/ui/client/src/management-jobs/notifications/notifications.partial.html b/awx/ui/client/src/management-jobs/notifications/notifications.partial.html deleted file mode 100644 index e5ebf859d707..000000000000 --- a/awx/ui/client/src/management-jobs/notifications/notifications.partial.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
-
diff --git a/awx/ui/client/src/management-jobs/scheduler/main.js b/awx/ui/client/src/management-jobs/scheduler/main.js deleted file mode 100644 index 0fff48415fdf..000000000000 --- a/awx/ui/client/src/management-jobs/scheduler/main.js +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -import { templateUrl } from '../../shared/template-url/template-url.factory'; -import controller from '../../scheduler/schedulerList.controller'; -import addController from '../../scheduler/schedulerAdd.controller'; -import editController from '../../scheduler/schedulerEdit.controller'; -import { N_ } from '../../i18n'; -import editScheduleResolve from '../../scheduler/editSchedule.resolve'; - - -export default -angular.module('managementJobScheduler', []) - .controller('managementJobController', controller) - .controller('managementJobAddController', addController) - .controller('managementJobEditController', editController) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState({ - searchPrefix: 'schedule', - name: 'managementJobsList.schedule', - route: '/management_jobs/:id/schedules', - ncyBreadcrumb: { - parent: 'managementJobsList', - label: N_('SCHEDULES') - }, - views: { - '@managementJobsList': { - templateProvider: function(ScheduleList, generateList, ParentObject, $filter) { - // include name of parent resource in listTitle - ScheduleList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('SCHEDULES'); - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return generateList.insertFormView() + html; - }, - controller: 'managementJobController', - } - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('system_job_templates')}${$stateParams.id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath) { - let path = `${GetBasePath('system_job_templates')}${$stateParams.id}`; - Rest.setUrl(path); - return Rest.get(path).then((res) => res.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('system_job_templates') + $stateParams.id + '/schedules'; - return list; - } - ] - } - }); - $stateExtender.addState({ - name: 'managementJobsList.schedule.add', - route: '/add', - ncyBreadcrumb: { - parent: 'managementJobsList.schedule', - label: N_('CREATE SCHEDULED JOB') - }, - views: { - 'form': { - templateUrl: templateUrl('management-jobs/scheduler/schedulerForm'), - controller: 'managementJobAddController', - } - } - }); - $stateExtender.addState({ - name: 'managementJobsList.schedule.edit', - route: '/edit/:schedule_id', - ncyBreadcrumb: { - parent: 'managementJobsList.schedule', - label: N_('EDIT SCHEDULED JOB') - }, - views: { - 'form': { - templateUrl: templateUrl('management-jobs/scheduler/schedulerForm'), - controller: 'managementJobEditController' - } - }, - resolve: editScheduleResolve() - }); - }]); diff --git a/awx/ui/client/src/management-jobs/scheduler/schedulerForm.partial.html b/awx/ui/client/src/management-jobs/scheduler/schedulerForm.partial.html deleted file mode 100644 index 89bd1c56df6d..000000000000 --- a/awx/ui/client/src/management-jobs/scheduler/schedulerForm.partial.html +++ /dev/null @@ -1,611 +0,0 @@ -
-
-
{{ schedulerName || "ADD SCHEDULE"}}
-
{{ schedulerName || "EDIT SCHEDULE"}}
-
-
- -
-
-
-
- -
- - -
- A schedule name is required. -
-
-
- -
- - -
-
-
-
-
- -
- - - : - - - - : - - - -
-
- The time must be in HH24:MM:SS format. -
-
-
- - -
-
- - -
-
-
-
- - -
A value is required.
-
This is not a valid number.
-
Please input a number greater than 1.
-
-
- Frequency Details
-
-
- - - -
- Please provide a value between 1 and 999. -
-
-
-
- -
- -
- The day must be between 1 and 31. -
-
-
-
- -
-
- - -
-
-
-
- * - -
-
- - -
-
- The day must be between 1 and 31. -
-
-
-
- -
-
- - - -
-
-
- -
-
- - - - - - - -
-
-
- Please select one or more days. -
-
-
- -
- -
-
-
- - -
- Please provide a value between 1 and 999. -
-
-
- -
- - -
-
- Please provide a valid date. -
-
-
-
-
-
-
-

- The scheduler options are invalid or incomplete. -

-
-
- -
- {{ rrule_nlp_description }} -
-
- -
- - - -
-
-
    -
  • - {{ occurrence.utc }} -
  • -
-
    -
  • - {{ occurrence.local }} -
  • -
-
- -
- - - -
-
-
diff --git a/awx/ui/client/src/network-ui/.gitignore b/awx/ui/client/src/network-ui/.gitignore deleted file mode 100644 index bc3cac3dd252..000000000000 --- a/awx/ui/client/src/network-ui/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/extracted diff --git a/awx/ui/client/src/network-ui/CONTRIBUTING.md b/awx/ui/client/src/network-ui/CONTRIBUTING.md deleted file mode 100644 index bf3c2b3a281e..000000000000 --- a/awx/ui/client/src/network-ui/CONTRIBUTING.md +++ /dev/null @@ -1,951 +0,0 @@ - - -Getting Started With Network UI Development -=========================================== - - -**Introduction** - -The Networking UI component of AWX works differently from the rest of the AWX -web UI to support high-scale interactive graphical design of networking -topologies. - -The Networking UI is a virtual graphical canvas where graphical elements are -drawn upon. This canvas supports panning (scrolling horizontally and -vertically) and scaling (zooming in and out), dynamic changing of modes, and -other features that would be very difficult or impossible to implement with -standard HTML events and rendering. - -This interface is more like computer graphics than it is building a styled text -document with interactive components. A good grasp of Cartesian coordinates, -trigonometry, and analytic geometry are useful when working with this code. - -* See: - -**Design choices** - -Certain design choices were made to make the UI performant and scale to a large -number of nodes in a diagram. These include the use of simple ES5 functions for -better performance over more advanced functions. For instance C-style for-loops -were many times faster than implementations of `forEach` or iterators which make -function calls during each iteration. This basic ES5 style should be followed -throughout the implementation of the Network UI. - -**AngularJS** - -The Networking UI component uses AngularJS 1.6.x for part of the rendering pipeline -but it is not a normal AngularJS web application. AngularJS makes use of -data-binding and watchers which I found do not scale to the number of elements -we are trying to support in the Networking UI. The Networking UI only uses -AngularJS for SVG rendering (using AngularJS templates) which does scale -sufficiently. - - -**AngularJS Controllers** - -Instead of creating many AngularJS controllers and directives the networking UI -uses one big controller to hold the state of the entire UI. Normally this is -an anti-pattern in AngularJS. Here is was necessary to scale to a large number -of on-screen elements. - -**AngularJS Directives** - -* See: - -AngularJS directives are used in the networking UI application using the element -matching style and the `templateUrl` option to include a template. A majority of -the directives are defined in `network.ui.app.js`. - -* See: [network.ui.app.js](network.ui.app.js) -``` - .directive('awxNetDeviceDetail', deviceDetail.deviceDetail) -``` - -* See: [device.detail.directive.js](device.detail.directive.js) -``` -function deviceDetail () { - return { restrict: 'A', templateUrl: '/static/network_ui/widgets/device_detail.html' }; -} -``` - -**AngularJS Templates** - -* See: - -Normal AngularJS templates are used with the networking UI controller. -The templates can be found in `/widgets`. Child -scopes are created for sub-templates using the `ng-repeat` directive. - -In this example the `awx-net-link` directive expects a Link model to be -passed to it. The Link model is defined in the `models.js` file. - -* See: [link.directive.js](link.directive.js) -* See: [link.partial.svg](link.partial.svg) - -* See: [network_ui.html](network_ui.partial.svg) -``` - - - -``` - -* See: [models.js](models.js) -``` -function Link(id, from_device, to_device, from_interface, to_interface) { - this.id = id; - this.from_device = from_device; - this.to_device = to_device; - this.from_interface = from_interface; - this.to_interface = to_interface; - this.selected = false; - this.remote_selected = false; - this.status = null; - this.edit_label = false; - this.name = ""; -} -``` - -The following example sets the toolbox.selected_item value to the variable -item which the directives used in the child scope expect to be set. - -* See: [inventory_toolbox.html](inventory_toolbox.partial.svg) -``` - -``` - - -**DOM (Document Object Model)** - -No state is stored in or attached to the DOM. All state is stored in -javascript objects attached to the network ui controller. - -Direct DOM manipulation should not be used in the network UI unless absolutely -necessary. JQuery should not be used. The DOM is generated through the use of -AngularJS templates. - -**SVG (Scalable Vector Graphics)** - -* See: - -The network UI is built as one large SVG element (the SVG canvas) with other -graphical elements (lines, circles, rectangles, paths, and text) absolutely -positioned within the outer most SVG element. The browser is not involved with -layout of the elements within the SVG. Each "widget" in the network UI needs -to track or calculate its own position on the SVG canvas. The z-level of the -elements are determined by the draw order on the canvas which is defined -in `network_ui.partial.svg`. Elements drawn first will be hidden behind -elements drawn later. - - - -**Rendering Pipeline** - -Event -> Javscript objects -> AngularJS templates -> SVG - -AngularJS is used to render the SVG inside the SVG canvas using directives -and templates. AngularJS is also used to schedule when the SVG canvas will -be updated. When an input event comes from the user, or an event is received -over the websocket, javascript objects will be updated according the the network -UI code. Then AngularJS will be notified that it needs to update the templates -either automatically for some events or explicitly using `$scope.$apply();` if -not handled automatically by AngularJS. The templates will render to SVG and be -included in the DOM for the rest of the AWX UI. - -Because the networking UI does not use watchers nor data-binding features of -AngularJS events flow in one way from event to javascript to angular to SVG. -Events do not flow backwards through this pipeline. - -Clicking on an SVG element will not send the event to that SVG element directly -from the browser. It must be routed through the network UI code first. - - -**SVG Primer** - -SVG uses tags to define graphical elements just like HTML uses tags to define -text documents. Commonly use tags include g, circle, rect, path, and text. -SVG elements are absolutely positioned within an SVG canvas. The group tag, g, -is similar to the div tag in HTML. Text in SVG must be contained in the text -tag and cannot be outside tags as in HTML. - -* See: - -Each tag that describes a visual element requires X and Y coordinates as input -to position that element. These coordinates are relative to position of the SVG -canvas. The network UI uses the entire page height and width for the SVG canvas -so that the position on the SVG on the canvas is the same as the position on -the page. - - -SVG supports graphical transformations on several tags to allow relative -positioning of sub-elements which makes calculating the X and Y positions -easier. The network UI uses transformations often for this purpose. -Transformations that are often used here are the translate, scale, and rotate -transforms. Translate moves the origin of the coordinate system to a new point -for the sub-elements. Scale multiplies the size of the units in a coordinate -system by some factor. Rotate performs a rotation about the origin by some -number of degrees. These functions are converted to a matrix operation on the -coordinate system which can be efficiently applied. It is often useful to use -the transforms to simplify the calculations of X and Y coordinates instead of -calculating those values in Javascript. Also these transforms make developing -widgets much easier since we only need to keep up with a single point for the -widget and all other points can be relatively positioned from that point. -Hard-coding positions in widget development is the normal case since transforms -can change the size and position of the widget when the widget is applied to -the canvas. Only when necessary should we calculate positions of parts of a -widget in javascript. - -* See: - - -SVG paths are a mini-language for defining graphics operations in one tag. It -is often used to create shapes that are more complex than lines, rectangles, -and circles. It is very useful for defining arcs. - -* See: - -**SVG and CSS** - -CSS and SVG work really nicely together for setting style, colors, and fonts in SVG. -The SVG uses different attributes for setting colors than does HTML elements. -Most SVG elements use `stroke` and `fill` to define the colors and `stroke-width` -to define the width of lines and curves. The attributes `font-family` and `font-size` -are used to set the font for text elements in SVG. The network UI uses the Less -CSS compiler and BEM naming conventions to simplify and organize CSS. - -* See: [style.less](style.less) -* See: -* See: - -**Events** - -All mouse and keyboard events are captured by the outer most element of the -network UI. Mouse movements, mouse clicks, and key presses are all routed by -the network UI code and not by the browser. This is done to implement -interactions with the virtual graphical canvas that are not supported by the -browser. "Simple" things like buttons and text fields have to be handled by -the network UI code instead of relying on the browser to route the mouse click -to the appropriate object. - - -The following code captures all the mouse movements, mouse clicks, mouse wheel, -and touch events and sends them to the corresponding network UI controller functions. - -* See: [network_ui.partial.svg](network_ui.partial.svg#L3) - -``` - -``` - - -Key events are captured by the following code: - -* See: [network.ui.controller.js](network.ui.controller.js) - -``` - $document.bind("keydown", $scope.onKeyDown); -``` - -**Event Processing** - -This code works as an event processing pipeline where the source of the events -may be mouse clicks, keystrokes, or messages from the server over the -websocket. This allows the appropriate processor to handle each event in turn -or delegate the message to another processor. - -The following diagram documents the pipeline processors that handle the events. -Events are injected into to the pipeline at `Start` and travel through the -pipeline along the arrows. Events may be handled at a node in the pipeline, -passed along to the next node, discarded, or transformed into another message -and sent along the pipeline. For instance `hotkeys_fsm` generates new and -different type of events based on key presses that are injected at the -beginning of the pipeline. - -![Event Pipeline](designs/pipeline.png) - - -**Describing Behavior with Finite State Machines** - -To implement complex UI interactions predictably and correctly is a tough -problem. Often the problem is solved by creating a large library of generic -reusable components that are rigorously tested and hardened by a large group of -developers over a period of several years. Eventually the myriad bugs are -hammered out at great expense. Only then can the UI components be reliably -used. This code does not follow that approach. - -The workflows this code supports require very specific UI components that are -not found in generic libraries. The interactions we want to support are not -available in generic libraries. This code develops from scratch only the -components that are necessary to implement the workflows of designing and -operating networks of devices. - -This code defines those elements using finite state machines to process the -events from user input and other software components. Programming with finite -state machines allows us to define formally complex behavior that would -normally be informally defined by branches, functions, object interactions, and -object inheritance. Formal definition eliminates much of the unexpected -behavior that causes defects in the software. - -* See: - -Finite state machines can be represented as a directed graph of labeled nodes and labeled edges -which can be both be represented visually and in machine readable code. - -The network UI uses finite state machines to describe what happens when the software receives -an input. - -**Link FSM** - -![Link FSM](designs/link.png) - -For example the link FSM describes how to connect devices with links. The FSM -diagram above maps out the states and events that will select a device to connect and another -device to connect to. FSMs traditionally start in the `Start` state. We get a free transition -to the `Ready` state by handling the special event called `start` and changing state to `Ready`. -Then when the `NewLink` event is received from a hot key or button click the FSM changes -state to the `Selecting` state. On a `MouseUp` event the FSM changes to the the `Connecting` state -if the mouse is over a device icon otherwise it stays in the `Selecting` state. In the `Connecting` -state the FSM changes to the `Connected` state when it receives a `MouseUp` event and the -mouse is over another device otherwise it goes back to the `Ready` state since the user cancelled -the connecting operation. Finally in the `Connected` state the FSM changes to the `Ready` state -for free using the `start` event so that the user can connect another set of devices. - -* See: [designs/link.yml](designs/link.yml) -* See: [link.js](link.js) - -The link FSM diagram has an equivalent machine readable representation in `designs/link.yml`. This -representation is useful for comparing the current implementation in `link.js` to the design to see if they -are out-of-sync. If they are out-of-sync either the design or the implementation can be updated depending -on if you are changing the design or implementation first. - -Tools are provided to facilitate the design-first and the implementation-first workflows. - -**Design-First Workflow** - -In the design-first workflow, first change the design and then update the -implementation to match. In this workflow we use the -[fsm-designer-svg](https://github.com/benthomasson/fsm-designer-svg) tool to -change the FSM diagram, then export the FSM to a file, then generate a skeleton -of the javascript code that implements the FSM. Then development of the logic -inside the event handlers can begin with a clear understanding of the state of -the system and what that event handler should do. - -Use `tools/fsm_generate_diffs.py` to generate the new skeleton code: - -``` - ./tools/fsm_generate_diffs.py designs/link.yml ./link.js -``` - -This will print out code for additional states or transitions needed in the implementation. -Copy those lines into the implementation code and fill out the event handler functions. - - -**Implementation-First Workflow** - -In the implementation-first workflow, first change the code and then update the -design to reflect the changes. This workflow is useful when the design doesn't -survive its impact with reality and the code adds additional requirements to -the design. Often in usabilty testing we find that we forgot to consider -handling a certain interaction or user input in a state. We can quickly add -that transition to the code and test it out. Once confirmed that the interaction -is correct we can update the design and run `./tools/fsm-diff` to make sure the two -are in sync. - - -Use `./extract.js` and `tools/fsm-diff` to compare the implementation to the design -and add any additional transitions to the FSM design. - -``` - ./extract.js link.js > ./extracted/link.yml - ./tools/fsm-diff designs/link.yml extracted/link.yml -``` - - -**Validating That Design Matches Implementation** - -Use the `make extract` and `make diff` Makefile targets to do a mass extact of the -FSMs from the implementation and a mass comparison against the designs. Take -note of any differences between design and implementation and update the appropriate -files as outlined in the workflows above. - -``` - make extract; make diff -``` - - -**Finite State Machine Implementation** - -The implementation of a finite state machine in the network UI is split into -two parts: the declaration of the states and the event-handlers which may cause -FSM transitions using `controller.changeState`. - -**FSM States** - -* See: -* See: - -States are implemented using an object-oriented style in ES5 using the -flyweight and singleton patterns. This means that the state objects store no -information on themselves and that there is only one instance of each state -class. All states should provide a `start` and `end` function which will be -called when a FSM state is entered and exited respectively. Subclassing -[fsm.State](fsm.js#L36) will provide empty `start` and `end` functions that -can be overridden as necessary. - -* See: [fsm.js](fsm.js#L2) - -The state variable is stored on another object called an FSMController (which -should not be confused with an AngularJS controller). The FSMController holds -all the state for each FSM instance. If you need more than one copy of an FSM -(for buttons for instance) use more than one instance of FSMController and -pass the same FSM starting state to their constructor e.g. `button.Start`. -Variables other than `state` should not be stored on the FSMController. A -special variable named `scope` is useful for that. The scope can be used -to hold arbitrary data that the FSM code will use in addition to the messages -in the event handlers. In the network UI often the `scope` is a reference -to the network UI AngularJS controller's scope. In the case of a button -the scope is a reference to the `Button` model. - -* See: [models.js](models.js#302) - -The following code creates a new instance of `FSMController` using the -`Button` model as the scope and the `button.Start` state as the initial -state. - -``` - this.fsm = new fsm.FSMController(this, button.Start, null); -``` - -* See: [link.js](link.js#L40) - -This code block defines the `_Selecting` class in ES5 style and uses the -`inherits` NPM module to define that the class is a subclass of `_State`. We -also create a single instance (a singleton) of this class named `Selecting`. - -``` - function _Selecting () { - this.name = 'Selecting'; - } - inherits(_Selecting, _State); - var Selecting = new _Selecting(); - exports.Selecting = Selecting; -``` - -**FSM Event Handlers and Transitions** - -After all the states are defined the event handlers for those state classes can be defined. -We do this to prevent forward references in the file. - -* See: [link.js](link.js#L134) - -In this code we define an event handler for the `MouseUp` event on the `Selecting` state. This -code should select a single device if the mouse is over that device. It should store -that device somewhere and change to the `Connecting` state. The code below creates a new -`Link` model and stores the `selected_device` in that object. The `new_link` object is -stored in the `controller.scope` for later use in the FSM. Finally the event handler changes -state using `controller.changeState` to change the state of the FSM to `Connecting`. - -Event handlers must start with the prefix of `on` and a suffix of the name of the messsage -type. The special functions `start` and `end` do not follow this rule nor do -they receive a message. - -The event handler must also define its `transitions` as a list so that `./extract.js` can -find them. - -``` - _Selecting.prototype.onMouseUp = function (controller) { - - var selected_device = controller.scope.select_items(false).last_selected_device; - if (selected_device !== null) { - controller.scope.new_link = new models.Link(controller.scope.link_id_seq(), selected_device, null, null, null, true); - controller.scope.links.push(controller.scope.new_link); - controller.changeState(Connecting); - } - }; - _Selecting.prototype.onMouseUp.transitions = ['Connecting']; - -``` - -**FSM Designs** - -All the finite state machines for the network UI have been designed using the -[fsm-designer-svg](https://github.com/benthomasson/fsm-designer-svg) tool -and their designs are stored in the `designs` directory. - -* See: [designs/README.md](designs/README.md) - - -**Data Models** - -There are two types of data structures used in the network UI: messages and -models. Models are used for long-lived data that is used to render the UI -whereas messages are used for ephemeral data that is passed from one part of -the system to another. Models may be unpacked or serialized into messages that -are sent to other FSMControllers in the client or sent over a websocket to the -server. - -* See: [models.js](models.js) - -The models defined in [models.js](models.js) are: - -* Device - a networking device i.e. a router, a switch, or a host -* Interface - a networking interface -* Link - a connection between interfaces -* Button - a UI button -* ToggleButton - a togglable UI button -* Task - a playbook task -* Group - a grouping of devices -* ToolBox - a UI element for holding things that can be placed on the virtual canvas -* Configuration - a configuration for a device -* Process - an application running on a device -* Stream - a flow of data between applications - - -**Message Types** - -Message types define the structure of the data that is passed between the server -and the client and between different parts of the client. This provides a known and -well defined data structure that can be counted up on the code. - -* See: [messages.js](messages.js) - -The messages defined are [messages.js](messages.js): - -* DeviceMove - Device has changed x,y position -* DeviceCreate - A device was created -* DeviceDestroy - A device was destroyed -* DeviceLabelEdit - The label of a device was changed -* DeviceSelected - A device was selected -* DeviceUnSelected - A device was unselected -* InterfaceCreate - An interface was created -* InterfaceLabelEdit - The label of an interface was changed -* LinkLabelEdit - The label of a link was changed -* LinkCreate - A link was created -* LinkDestroy - A link was destroyed -* LinkSelected - A link was selected -* LinkUnSelected - A link was unselected -* Undo - Undo the last operation -* Redo - Redo the last undone operation -* Deploy - Call the deploy playbook -* Destroy - Call the destroy playbook -* Discover - Call the discover playbook -* Layout - Call the layout function -* MultipleMessage - A collection of messages that should be handled together -* Coverage - A coverage report -* MouseEvent - A generic mouse event -* MouseWheelEvent - A mouse wheel event -* KeyEvent - A key press event -* TouchEvent - A touch screen event -* StartRecording - Start recording user interactions -* StopRecording - Stop recording user interactions -* ViewPort - Update the view port onto the virtual canvas -* NewDevice - Request for a new device -* PasteDevice - Paste a device from a toolbox -* PasteProcess - Paste a process from a toolbox -* NewGroup - Request for a new group -* PasteGroup - Paste a group from a toolbox -* PasteRack - Paste a rack from a toolbox -* PasteSite - Paste a site from a toolbox -* CopySite - Copy a stie to a toolbox -* GroupMove - A group has changed its x, y coordinates -* GroupCreate - A new group was created -* GroupDestroy - A group was destroyed -* GroupLabelEdit - The label for a group was changed -* GroupSelected - A group was selected -* GroupUnSelected - A group was unselected -* GroupMembership - The device membership of a group changed -* TableCellEdit - A table cell was chaged -* ProcessCreate - A new process was created -* StreamCreate - A new stream was created -* StreamDestroy - A stream was destroyed -* StreamLabelEdit - The label of a stream was changed -* StreamSelected - A stream was selected -* StreamUnSelected - A stream was unselected - - -Widget Development -================== - -When developing a new UI widget follow this process: - -For a widget named `new widget` do this: - -* Add a template in `widgets` for the new widget with name `new_widget.html` -* Add a directive that loads that template in `src` with name `new.widget.directive.js` -* Register the directive with the network UI application in `src/network.ui.app.js` using name `awxNetNewWidget` -* Add a tag that loads the directive into an existing template in `widgets`. If you are not sure add it to `widgets/network_ui.html`. -* Test that the directive is loaded when the page renders in a browser -* Iterate on the template for the new widget until the UI look matches the mockup -* Design the interaction behavior using [fsm-designer-svg](https://github.com/benthomasson/fsm-designer-svg) -* Export the FSM design to `designs` in a file named `designs/new_widget.yml` -* Create a new empty FSM implementation file in `src` named `src/new.wiget.fsm.js` -* Use the `./tools/fsm_generate_diffs.py` tool to generate the skeleton for the new FSM implementation -* Decide if you need any new data structures for your UI widget. If so, add them to `src/models.js`. -* Decide if you need any new messages to communicate between the UI and the server or between pieces of the UI. - If so, add them to `src/messages.js` -* Add the FSM implementation to a FSMController in `src/network.ui.controller.js` -* Write the logic in the event handlers to update the models, send any messages, and change states according to the design. -* Test the interaction manually in a browser -* Iterate on changing the event handlers until the desired interaction is acheived -* Update the design to match the implementation - -**Widget Development Example** - -This example follows development of the inventory toolbox widget. - -* Add a template in `widgets` for the new widget with name [inventory_toolbox.partial.svg](inventory_toolbox.partial.svg) - -``` - - - - - ... - -``` - -* Add a directive that loads that template in `src/network-ui` with name [inventory.toolbox.directive.js](inventory.toolbox.directive.js) - -``` - /* Copyright (c) 2017 Red Hat, Inc. */ - - function inventoryToolbox () { - return { restrict: 'A', templateUrl: '/static/network_ui/widgets/inventory_toolbox.html' }; - } - exports.inventoryToolbox = inventoryToolbox; -``` - - -* Register the directive with the network UI application in [network.ui.app.js](network.ui.app.js#L61) using name `awxNetInventoryToolbox` - -``` -... - var inventoryToolbox = require('./inventory.toolbox.directive.js'); -... - .directive('awxNetInventoryToolbox', inventoryToolbox.inventoryToolbox) -... -``` - -* Add a tag that loads the directive into an existing template in `src/network-ui` in [network_ui.partial.svg](network_ui.partial.svg#L94) - -``` - -``` - -* Test that the directive is loaded when the page renders in a browser -* Iterate on the template for the new widget until the UI look matches the mockup -* Design the interaction behavior using [fsm-designer-svg](https://github.com/benthomasson/fsm-designer-svg) - -![Toolbox](designs/toolbox.png) - -* Export the FSM design to `designs` in a file named `designs/toolbox.yml` - -``` - finite_state_machine_id: 14 - name: toolbox - states: - - id: 2 - label: Selected - x: 1180 - y: 959 - - id: 6 - label: Move - x: 1409 - y: 741 - - id: 3 - label: Ready - x: 892 - y: 429 - - id: 4 - label: Scrolling - x: 567 - y: 431 - - id: 5 - label: Start - x: 892 - y: 216 - - id: 7 - label: Selecting - x: 888 - y: 710 - - id: 1 - label: Dropping - x: 1358 - y: 431 - transitions: - - from_state: Selecting - label: onMouseDown - to_state: Selected - - from_state: Selected - label: onMouseMove - to_state: Move - - from_state: Selecting - label: onMouseDown - to_state: Ready - - from_state: Selected - label: onMouseUp - to_state: Ready - - from_state: Dropping - label: start - to_state: Ready - - from_state: Start - label: start - to_state: Ready - - from_state: Scrolling - label: onMouseWheel - to_state: Ready - - from_state: Ready - label: onMouseWheel - to_state: Scrolling - - from_state: Ready - label: onMouseDown - to_state: Selecting - - from_state: Move - label: onMouseUp - to_state: Dropping -``` - -* Create a new empty FSM implementation file in `src/network-ui` named `toolbox.fsm.js` - -``` - touch toolbox.fsm.js -``` - -* Use the `./tools/fsm_generate_diffs.py` tool to generate the skeleton for the new FSM implementation - -``` - ./tools/fsm_generate_diffs.py designs/toolbox.yml src/toolbox.fsm.js --append -``` - - -``` - var inherits = require('inherits'); - var fsm = require('./fsm.js'); - - function _State () { - } - inherits(_State, fsm._State); - - - function _Start () { - this.name = 'Start'; - } - inherits(_Start, _State); - var Start = new _Start(); - exports.Start = Start; - - function _Selected () { - this.name = 'Selected'; - } - inherits(_Selected, _State); - var Selected = new _Selected(); - exports.Selected = Selected; - - function _Dropping () { - this.name = 'Dropping'; - } - inherits(_Dropping, _State); - var Dropping = new _Dropping(); - exports.Dropping = Dropping; - - function _Ready () { - this.name = 'Ready'; - } - inherits(_Ready, _State); - var Ready = new _Ready(); - exports.Ready = Ready; - - function _Selecting () { - this.name = 'Selecting'; - } - inherits(_Selecting, _State); - var Selecting = new _Selecting(); - exports.Selecting = Selecting; - - function _Move () { - this.name = 'Move'; - } - inherits(_Move, _State); - var Move = new _Move(); - exports.Move = Move; - - function _Scrolling () { - this.name = 'Scrolling'; - } - inherits(_Scrolling, _State); - var Scrolling = new _Scrolling(); - exports.Scrolling = Scrolling; - - - - - _Start.prototype.start = function (controller) { - - controller.changeState(Ready); - - }; - _Start.prototype.start.transitions = ['Ready']; - - - - _Selected.prototype.onMouseMove = function (controller) { - - controller.changeState(Move); - - }; - _Selected.prototype.onMouseMove.transitions = ['Move']; - - _Selected.prototype.onMouseUp = function (controller) { - - controller.changeState(Ready); - - }; - _Selected.prototype.onMouseUp.transitions = ['Ready']; - - - - _Dropping.prototype.start = function (controller) { - - controller.changeState(Ready); - - }; - _Dropping.prototype.start.transitions = ['Ready']; - - - - _Ready.prototype.onMouseDown = function (controller) { - - controller.changeState(Selecting); - - }; - _Ready.prototype.onMouseDown.transitions = ['Selecting']; - - _Ready.prototype.onMouseWheel = function (controller) { - - controller.changeState(Scrolling); - - }; - _Ready.prototype.onMouseWheel.transitions = ['Scrolling']; - - - - _Selecting.prototype.onMouseDown = function (controller) { - - controller.changeState(Ready); - - controller.changeState(Selected); - - }; - _Selecting.prototype.onMouseDown.transitions = ['Ready', 'Selected']; - - - - _Move.prototype.onMouseUp = function (controller) { - - controller.changeState(Dropping); - - }; - _Move.prototype.onMouseUp.transitions = ['Dropping']; - - - - _Scrolling.prototype.onMouseWheel = function (controller) { - - controller.changeState(Ready); - - }; - _Scrolling.prototype.onMouseWheel.transitions = ['Ready']; - }; - _Ready.prototype.onMouseWheel.transitions = ['Scrolling']; - - - - _Selecting.prototype.onMouseDown = function (controller) { - - controller.changeState(Ready); - - controller.changeState(Selected); - - }; - _Selecting.prototype.onMouseDown.transitions = ['Ready', 'Selected']; - - - - _Move.prototype.onMouseUp = function (controller) { - - controller.changeState(Dropping); - - }; - _Move.prototype.onMouseUp.transitions = ['Dropping']; - - - - _Scrolling.prototype.onMouseWheel = function (controller) { - - controller.changeState(Ready); - - }; - _Scrolling.prototype.onMouseWheel.transitions = ['Ready']; - -``` - -* Decide if you need any new data structures for your UI widget. If so, add them to [src/models.js](src/models.js#L608). - -``` - function ToolBox(id, name, type, x, y, width, height) { - this.id = id; - this.name = name; - this.type = type; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.items = []; - this.spacing = 200; - this.scroll_offset = 0; - this.selected_item = null; - this.enabled = true; - } - exports.ToolBox = ToolBox; -``` - -* Decide if you need any new messages to communicate between the UI and the server or between pieces of the UI. - If so, add them to [messages.js](messages.js#L251) - -``` - function PasteDevice(device) { - this.device = device; - } - exports.PasteDevice = PasteDevice; -``` - -* Write the logic in the event handlers to update the models, send any messages, and change states according to the design. - -See: [toolbox.fsm.js](toolbox.fsm.js) - -* Add the FSM implementation to a FSMController in [network.ui.controller.js](network.ui.controller.js#L145) - -``` - $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller); -``` - -* Test the interaction manually in a browser -* Iterate on changing the event handlers until the desired interaction is achieved -* Update the design to match the implementation diff --git a/awx/ui/client/src/network-ui/Makefile b/awx/ui/client/src/network-ui/Makefile deleted file mode 100644 index 58991a791984..000000000000 --- a/awx/ui/client/src/network-ui/Makefile +++ /dev/null @@ -1,19 +0,0 @@ - - -.PHONY: check extract - -FSMS = animation time test mode buttons button toolbox site rack group stream link details.panel move device.detail view keybindings hotkeys null - - -extract: - mkdir -p extracted - for fsm in $(FSMS); do \ - ./extract.js ./$${fsm}.fsm.js > extracted/$${fsm}.yml; \ - done - - -check: extract - for fsm in $(FSMS); do \ - ./tools/fsm-diff ../../../../network_ui/designs/$$fsm.yml extracted/$$fsm.yml; \ - ./tools/copy-layout.py ../../../../network_ui/designs/$$fsm.yml extracted/$$fsm.yml; \ - done diff --git a/awx/ui/client/src/network-ui/animation.fsm.js b/awx/ui/client/src/network-ui/animation.fsm.js deleted file mode 100644 index dc1e737d50c2..000000000000 --- a/awx/ui/client/src/network-ui/animation.fsm.js +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2018 Benjamin Thomasson */ -/* Copyright (c) 2018 Red Hat, Inc. */ - -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, fsm._State); -var Start = new _Start(); -exports.Start = Start; - -function _Completed () { - this.name = 'Completed'; -} -inherits(_Completed, fsm._State); -var Completed = new _Completed(); -exports.Completed = Completed; - -function _Cancelled () { - this.name = 'Cancelled'; -} -inherits(_Cancelled, fsm._State); -var Cancelled = new _Cancelled(); -exports.Cancelled = Cancelled; - -function _Running () { - this.name = 'Running'; -} -inherits(_Running, fsm._State); -var Running = new _Running(); -exports.Running = Running; - - -_Start.prototype.start = function (controller) { - - controller.changeState(Running); -}; -_Start.prototype.start.transitions = ['Running']; - -_Running.prototype.start = function (controller) { - - controller.scope.interval = setInterval(function () { - controller.scope.frame_number = controller.scope.frame_number_seq(); - if (!controller.scope.active) { - return; - } - if (controller.scope.frame_number > controller.scope.steps) { - controller.scope.fsm.handle_message('AnimationCompleted'); - return; - } - controller.scope.callback(controller.scope); - controller.scope.scope.$apply(); - }, controller.scope.frame_delay); -}; - -_Running.prototype.onAnimationCancelled = function (controller) { - - controller.changeState(Cancelled); - -}; -_Running.prototype.onAnimationCancelled.transitions = ['Cancelled']; - -_Running.prototype.onAnimationCompleted = function (controller) { - - controller.changeState(Completed); - -}; -_Running.prototype.onAnimationCompleted.transitions = ['Completed']; - -_Completed.prototype.start = function (controller) { - controller.scope.active = false; - clearInterval(controller.scope.interval); -}; - -_Cancelled.prototype.start = function (controller) { - controller.scope.active = false; - clearInterval(controller.scope.interval); -}; diff --git a/awx/ui/client/src/network-ui/animations.js b/awx/ui/client/src/network-ui/animations.js deleted file mode 100644 index 74ead1a42303..000000000000 --- a/awx/ui/client/src/network-ui/animations.js +++ /dev/null @@ -1,23 +0,0 @@ - -function scale_animation (scope) { - - var initial_height = ((1 / scope.data.current_scale) - 1); - var height = (scope.data.end_height - initial_height) * (scope.frame_number / scope.steps) + initial_height; - scope.data.scope.current_scale = 1 / (1 + height); - scope.data.scope.updatePanAndScale(); - scope.data.scope.$emit('awxNet-UpdateZoomWidget', scope.data.scope.current_scale, scope.data.updateZoomBoolean); -} -exports.scale_animation = scale_animation; - -function pan_animation (scope) { - var incr_x = (scope.data.x2 - scope.data.x1) / scope.steps; - var incr_y = (scope.data.y2 - scope.data.y1) / scope.steps; - var v_x = incr_x * scope.frame_number + scope.data.x1; - var v_y = incr_y * scope.frame_number + scope.data.y1; - var p = scope.data.scope.to_pan(v_x, v_y); - scope.data.scope.panX = p.x + scope.data.scope.graph.width/2; - scope.data.scope.panY = p.y + scope.data.scope.graph.height/2; - scope.data.scope.first_channel.send("PanChanged", {}); - scope.data.scope.updatePanAndScale(); -} -exports.pan_animation = pan_animation; diff --git a/awx/ui/client/src/network-ui/button.fsm.js b/awx/ui/client/src/network-ui/button.fsm.js deleted file mode 100644 index f32839ecdcaa..000000000000 --- a/awx/ui/client/src/network-ui/button.fsm.js +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Clicked () { - this.name = 'Clicked'; -} -inherits(_Clicked, _State); -var Clicked = new _Clicked(); -exports.Clicked = Clicked; - -function _Pressed () { - this.name = 'Pressed'; -} -inherits(_Pressed, _State); -var Pressed = new _Pressed(); -exports.Pressed = Pressed; -function _Disabled () { - this.name = 'Disabled'; -} -inherits(_Disabled, _State); -var Disabled = new _Disabled(); -exports.Disabled = Disabled; - - - -// Begin ready state -_Ready.prototype.onMouseDown = function (controller) { - - controller.changeState(Pressed); - -}; -_Ready.prototype.onMouseDown.transitions = ['Pressed']; - -_Ready.prototype.start = function (controller) { - - controller.scope.enabled = true; - -}; - -_Ready.prototype.onDisable = function (controller) { - - controller.changeState(Disabled); - -}; -_Ready.prototype.onDisable.transitions = ['Disabled']; -// end ready state - - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - - -_Clicked.prototype.start = function (controller) { - - controller.scope.is_pressed = false; - controller.changeState(Ready); - controller.scope.callback(controller.scope); -}; -_Clicked.prototype.start.transitions = ['Ready']; - - -_Pressed.prototype.start = function (controller) { - controller.scope.is_pressed = true; -}; - -_Pressed.prototype.onMouseUp = function (controller) { - - controller.changeState(Clicked); - -}; -_Pressed.prototype.onMouseUp.transitions = ['Clicked']; - -_Disabled.prototype.onEnable = function (controller) { - - controller.changeState(Ready); - -}; -_Disabled.prototype.onEnable.transitions = ['Ready']; - -_Disabled.prototype.start = function (controller) { - - controller.scope.enabled = false; - -}; diff --git a/awx/ui/client/src/network-ui/buttons.fsm.js b/awx/ui/client/src/network-ui/buttons.fsm.js deleted file mode 100644 index 2a01a0bd3a65..000000000000 --- a/awx/ui/client/src/network-ui/buttons.fsm.js +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _ButtonPressed () { - this.name = 'ButtonPressed'; -} -inherits(_ButtonPressed, _State); -var ButtonPressed = new _ButtonPressed(); -exports.ButtonPressed = ButtonPressed; - - - - -_Ready.prototype.onMouseDown = function (controller, msg_type, $event) { - - var i = 0; - var buttons = controller.scope.all_buttons; - var button = null; - for (i = 0; i < buttons.length; i++) { - button = buttons[i]; - if (button.is_selected(controller.scope.mouseX, controller.scope.mouseY)) { - button.fsm.handle_message(msg_type, $event); - controller.changeState(ButtonPressed); - break; - } - button = null; - } - if (button === null) { - controller.delegate_channel.send(msg_type, $event); - } - -}; -_Ready.prototype.onMouseDown.transitions = ['ButtonPressed']; - -_Ready.prototype.onMouseMove = function (controller, msg_type, $event) { - - if (!controller.scope.hide_buttons) { - - var i = 0; - var buttons = controller.scope.all_buttons; - var button = null; - for (i = 0; i < buttons.length; i++) { - button = buttons[i]; - button.mouse_over = false; - if (button.is_selected(controller.scope.mouseX, controller.scope.mouseY)) { - button.mouse_over = true; - } - } - } - - controller.delegate_channel.send(msg_type, $event); -}; - - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - - - -_ButtonPressed.prototype.onMouseUp = function (controller, msg_type, $event) { - - var i = 0; - var buttons = controller.scope.all_buttons; - var button = null; - for (i = 0; i < buttons.length; i++) { - button = buttons[i]; - button.fsm.handle_message(msg_type, $event); - } - controller.changeState(Ready); - -}; -_ButtonPressed.prototype.onMouseUp.transitions = ['Ready']; diff --git a/awx/ui/client/src/network-ui/context.menu.button.directive.js b/awx/ui/client/src/network-ui/context.menu.button.directive.js deleted file mode 100644 index 8e984109cfd4..000000000000 --- a/awx/ui/client/src/network-ui/context.menu.button.directive.js +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/context_menu_button.partial.svg'); - -function contextMenuButton () { - return { - restrict: 'A', - templateUrl, - scope: { - contextMenuButton: '=', - contextMenu: '=' - } - }; -} -exports.contextMenuButton = contextMenuButton; diff --git a/awx/ui/client/src/network-ui/context.menu.directive.js b/awx/ui/client/src/network-ui/context.menu.directive.js deleted file mode 100644 index bf92043d3448..000000000000 --- a/awx/ui/client/src/network-ui/context.menu.directive.js +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/context_menu.partial.svg'); - -function contextMenu () { - return { - restrict: 'A', - templateUrl, - scope: { - contextMenu: '=' - } - }; -} -exports.contextMenu = contextMenu; diff --git a/awx/ui/client/src/network-ui/context_menu.partial.svg b/awx/ui/client/src/network-ui/context_menu.partial.svg deleted file mode 100644 index 883b532c043c..000000000000 --- a/awx/ui/client/src/network-ui/context_menu.partial.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/awx/ui/client/src/network-ui/context_menu_button.partial.svg b/awx/ui/client/src/network-ui/context_menu_button.partial.svg deleted file mode 100644 index 2c619cfb4dd5..000000000000 --- a/awx/ui/client/src/network-ui/context_menu_button.partial.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - -{{contextMenuButton.name}} - -{{contextMenuButton.name}} - diff --git a/awx/ui/client/src/network-ui/cursor.directive.js b/awx/ui/client/src/network-ui/cursor.directive.js deleted file mode 100644 index 340640efb0eb..000000000000 --- a/awx/ui/client/src/network-ui/cursor.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/cursor.partial.svg'); - -function cursor () { - return { restrict: 'A', templateUrl}; -} -exports.cursor = cursor; diff --git a/awx/ui/client/src/network-ui/cursor.partial.svg b/awx/ui/client/src/network-ui/cursor.partial.svg deleted file mode 100644 index a0f7233bd7d2..000000000000 --- a/awx/ui/client/src/network-ui/cursor.partial.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/awx/ui/client/src/network-ui/debug.directive.js b/awx/ui/client/src/network-ui/debug.directive.js deleted file mode 100644 index c593f0be5b1f..000000000000 --- a/awx/ui/client/src/network-ui/debug.directive.js +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/debug.partial.svg'); - -function debug () { - return { - restrict: 'A', - templateUrl, - link: function(){ - $('.NetworkUI__debug-text').each(function(index, option){ - let startingY = 15; - let offset = 20; - let y = startingY + (index * offset); - option.setAttribute('y', y); - }); - } - }; -} - -exports.debug = debug; diff --git a/awx/ui/client/src/network-ui/debug.partial.svg b/awx/ui/client/src/network-ui/debug.partial.svg deleted file mode 100644 index 8a852a9bd37c..000000000000 --- a/awx/ui/client/src/network-ui/debug.partial.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - view_port.x: {{view_port.x}} - view_port.y: {{view_port.y}} - view_port.width: {{view_port.width}} - view_port.height: {{view_port.height}} - width: {{graph.width}} - height: {{graph.height}} - rc: {{graph.right_column}} - Mouse down: {{onMouseDownResult}} - Mouse up: {{onMouseUpResult}} - Mouse move: {{onMouseMoveResult}} - Mouse over: {{onMouseOverResult}} - Mouse enter: {{onMouseEnterResult}} - Mouse leave: {{onMouseLeaveResult}} - Current scale: {{current_scale.toFixed(4)}} - Pan X: {{panX.toFixed(2)}} - Pan Y: {{panY.toFixed(2)}} - View State: {{view_controller.state.name}} - Mouse X: {{mouseX.toFixed(2)}} - Mouse Y: {{mouseY.toFixed(2)}} - Scaled X: {{scaledX.toFixed(2)}} - Scaled Y: {{scaledY.toFixed(2)}} - Key: {{last_key}} - Key Code: {{last_key_code}} - Move State: {{move_controller.state.name}} - Move Readonly State: {{move_readonly_controller.state.name}} - Selected devices: {{selected_devices.length}} - Selected links: {{selected_links.length}} - Link State: {{link_controller.state.name}} - Buttons State: {{buttons_controller.state.name}} - Time State: {{time_controller.state.name}} - Time Pointer: {{time_pointer}} - Group State: {{group_controller.state.name}} - Hotkeys State: {{hotkeys_controller.state.name}} - Mode State: {{mode_controller.state.name}} - Device Detail State: {{device_detail_controller.state.name}} - Site State: {{site_controller.state.name}} - Rack State: {{rack_controller.state.name}} - Stream State: {{stream_controller.state.name}} - App Toolbox State: {{app_toolbox_controller.state.name}} - Inventory Toolbox State: {{inventory_toolbox_controller.state.name}} - Rack Toolbox State: {{rack_toolbox_controller.state.name}} - Site Toolbox State: {{site_toolbox_controller.state.name}} - - - - - diff --git a/awx/ui/client/src/network-ui/default.directive.js b/awx/ui/client/src/network-ui/default.directive.js deleted file mode 100644 index 16c469f1882f..000000000000 --- a/awx/ui/client/src/network-ui/default.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/default.partial.svg'); - -function defaultd () { - return { restrict: 'A', templateUrl}; -} -exports.defaultd = defaultd; diff --git a/awx/ui/client/src/network-ui/default.partial.svg b/awx/ui/client/src/network-ui/default.partial.svg deleted file mode 100644 index 380fdd32a0ad..000000000000 --- a/awx/ui/client/src/network-ui/default.partial.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - {{item.name}} - - {{item.name}}{{item.edit_label?'_':''}} - - diff --git a/awx/ui/client/src/network-ui/designs/README.md b/awx/ui/client/src/network-ui/designs/README.md deleted file mode 100644 index 3a20f73bcd65..000000000000 --- a/awx/ui/client/src/network-ui/designs/README.md +++ /dev/null @@ -1,161 +0,0 @@ - -Finite State Machine Designs -============================ - -This directory contains the finite state machine designs that were used to -generate the skeleton of the javascript implementations and can be used to -check that the implementations still match the designs. - - -**Machine Readable FSM Schema** - -The machine readable FSM schema contains three top-level elements: `name`, `states`, and `transitions`. -* The `name` element is a string. -* The `states` element contains a list of `state` elements which have attributes `id`, `label`, and `x`, and `y`. -* The `transitions` element contains a list of `transition` elements which have attributes `from_state`, `to_state`, and `label`. - - -**Design Diagrams** - -The diagrams below are visual representations of the finite state machine designs in this directory. -The equivalent machine readable representations are linked as well. - ---- - -**Null FSM** -* See: null.yml - -The null FSM is an FSM that ignores all events. - -![Null FSM](null.png) - ---- - -**Button FSM** -* See: button.yml - -The button FSM describes how a button works. The key insight here is that a button is not -clicked if the mouse is not over the button on both the `MouseDown` and `MouseUp` events. Moving -the mouse off the button before `MouseUp` is not a click. - -![Button FSM](button.png) - ---- - -**Buttons FSM** -* See: buttons.yml - -The buttons FSM distributes events to the buttons which each have their own FSM. - -![Buttons FSM](buttons.png) - ---- - -**Device Detail FSM** -* See: device_detail.yml - -The device detail FSM describes interactions when zoomed into a device. - -![Device Detail FSM](device_detail.png) - ---- - -**Group FSM** -* See: group.yml - -The group FSM describes how to organize multiple devices together in a group. - -![Group FSM](group.png) - ---- - -**Hot Keys FSM** -* See: hotkeys.yml - -The hot keys FSM handles key events and generates new events like `NewLink` to implement -hot keys. - -![Hot Keys FSM](hotkeys.png) - ---- - -**Link FSM** -* See: link.yml - -The link FSM connects two devices together with a link. - -![Link](link.png) - ---- - -**Mode FSM** -* See: mode.yml - -The mode FSM controls the overall mode of the network UI application. - -![Mode](mode.png) - ---- - -**Move FSM** -* See: move.yml - -The move FSM controls placement of devices as well as editing the device labels. - -![Move](move.png) - ---- - -**Rack FSM** -* See: rack.yml - -The rack FSM controls organizing devices into a special group called a rack. - -![Rack](rack.png) - ---- - -**Site FSM** -* See: site.yml - -The site FSM controls organizing devices into a special group called a site. - -![Site](site.png) - ---- - -**Stream FSM** -* See: stream.yml - -The stream FSM controls how streams are defined between devices. - -![Stream](stream.png) - ---- - -**Time FSM** -* See: time.yml - -The time FSM controls undo/redo functionality of the network UI. - -![Time](time.png) - ---- - -**Toolbox FSM** -* See: toolbox.yml - -The toolbox FSM controls the drag-and-drop toolboxes and allow placement of new devices, applications, -racks, and sites onto the canvas. - -![Toolbox](toolbox.png) - ---- - -**View FSM** -* See: view.yml - -The view FSM controls the panning and scaling of the the virtual canvas through clicking-and-dragging -of the background and scrolling the mousewheel. - -![View](view.png) diff --git a/awx/ui/client/src/network-ui/designs/animation.yml b/awx/ui/client/src/network-ui/designs/animation.yml deleted file mode 100644 index c99b99dd1c2d..000000000000 --- a/awx/ui/client/src/network-ui/designs/animation.yml +++ /dev/null @@ -1,29 +0,0 @@ -diagram_id: 58 -name: animation_fsm -states: -- id: 4 - label: Cancelled - x: 590 - y: 602 -- id: 3 - label: Completed - x: 225 - y: 604 -- id: 2 - label: Running - x: 418 - y: 362 -- id: 1 - label: Start - x: 454 - y: 158 -transitions: -- from_state: Running - label: onAnimationCancelled - to_state: Cancelled -- from_state: Running - label: onAnimationCompleted - to_state: Completed -- from_state: Start - label: start - to_state: Running diff --git a/awx/ui/client/src/network-ui/designs/button.png b/awx/ui/client/src/network-ui/designs/button.png deleted file mode 100644 index 5a1bc7aaa1d9..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/button.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/button.yml b/awx/ui/client/src/network-ui/designs/button.yml deleted file mode 100644 index f037edb8f823..000000000000 --- a/awx/ui/client/src/network-ui/designs/button.yml +++ /dev/null @@ -1,43 +0,0 @@ -diagram_id: 66 -name: 'button_fsm' -finite_state_machine_id: 12 -states: -- id: 3 - label: Clicked - x: 331 - y: 568 -- id: 5 - label: Disabled - x: 719 - y: 283 -- id: 4 - label: Pressed - x: 606 - y: 563 -- id: 1 - label: Ready - x: 471 - y: 376 -- id: 2 - label: Start - x: 468 - y: 170 -transitions: -- from_state: Clicked - label: start - to_state: Ready -- from_state: Disabled - label: onEnable - to_state: Ready -- from_state: Pressed - label: onMouseUp - to_state: Clicked -- from_state: Ready - label: onDisable - to_state: Disabled -- from_state: Ready - label: onMouseDown - to_state: Pressed -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/buttons.png b/awx/ui/client/src/network-ui/designs/buttons.png deleted file mode 100644 index 8538b066143d..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/buttons.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/buttons.yml b/awx/ui/client/src/network-ui/designs/buttons.yml deleted file mode 100644 index b1cc56a24652..000000000000 --- a/awx/ui/client/src/network-ui/designs/buttons.yml +++ /dev/null @@ -1,28 +0,0 @@ -app: buttons_fsm -finite_state_machine_id: 7 -panX: 133 -panY: 41 -scaleXY: 1 -states: -- label: Start - size: 100 - x: 392 - y: 88 -- label: Ready - size: 100 - x: 392 - y: 281 -- label: ButtonPressed - size: 100 - x: 394 - y: 491 -transitions: -- from_state: Start - label: start - to_state: Ready -- from_state: Ready - label: onMouseDown - to_state: ButtonPressed -- from_state: ButtonPressed - label: onMouseUp - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/details.panel.png b/awx/ui/client/src/network-ui/designs/details.panel.png deleted file mode 100644 index d060f3bd2f34..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/details.panel.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/details.panel.yml b/awx/ui/client/src/network-ui/designs/details.panel.yml deleted file mode 100644 index 555d21c8be6f..000000000000 --- a/awx/ui/client/src/network-ui/designs/details.panel.yml +++ /dev/null @@ -1,26 +0,0 @@ -diagram_id: 70 -finite_state_machine_id: 21 -name: diagram -states: -- id: 1 - label: Start - x: 590 - y: 233 -- id: 2 - label: Collapsed - x: 594 - y: 490 -- id: 3 - label: Expanded - x: 919 - y: 491 -transitions: -- from_state: Start - label: start - to_state: Collapsed -- from_state: Expanded - label: onDetailsPanelClose - to_state: Collapsed -- from_state: Collapsed - label: onDetailsPanel - to_state: Expanded diff --git a/awx/ui/client/src/network-ui/designs/device.detail.png b/awx/ui/client/src/network-ui/designs/device.detail.png deleted file mode 100644 index 0f11ac8ffe02..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/device.detail.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/device.detail.yml b/awx/ui/client/src/network-ui/designs/device.detail.yml deleted file mode 100644 index fcb2f52eb654..000000000000 --- a/awx/ui/client/src/network-ui/designs/device.detail.yml +++ /dev/null @@ -1,19 +0,0 @@ -finite_state_machine_id: 19 -name: device_detail_fsm -states: -- id: 2 - label: Ready - x: 517 - y: 588 -- id: 3 - label: Disable - x: 770 - y: 455 -- id: 1 - label: Start - x: 507 - y: 336 -transitions: -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/group.png b/awx/ui/client/src/network-ui/designs/group.png deleted file mode 100644 index 5ca5ead53816..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/group.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/group.yml b/awx/ui/client/src/network-ui/designs/group.yml deleted file mode 100644 index f618170553a7..000000000000 --- a/awx/ui/client/src/network-ui/designs/group.yml +++ /dev/null @@ -1,119 +0,0 @@ -diagram_id: 61 -finite_state_machine_id: 5 -name: group_fsm -states: -- id: 12 - label: ContextMenu - x: 1228 - y: -74 -- id: 3 - label: CornerSelected - x: 526 - y: 554 -- id: 8 - label: Disable - x: 497 - y: 84 -- id: 9 - label: EditLabel - x: 1130 - y: 112 -- id: 6 - label: Move - x: 1297 - y: 786 -- id: 11 - label: Placing - x: 299 - y: 300 -- id: 7 - label: Ready - x: 733 - y: 304 -- id: 1 - label: Resize - x: 571 - y: 911 -- id: 4 - label: Selected1 - x: 839 - y: 640 -- id: 10 - label: Selected2 - x: 1179 - y: 435 -- id: 5 - label: Selected3 - x: 1528 - y: 360 -- id: 2 - label: Start - x: 744 - y: 69 -transitions: -- from_state: ContextMenu - label: onLabelEdit - to_state: EditLabel -- from_state: ContextMenu - label: onMouseDown - to_state: Ready -- from_state: CornerSelected - label: onMouseMove - to_state: Resize -- from_state: CornerSelected - label: onMouseUp - to_state: Selected1 -- from_state: EditLabel - label: onKeyDown - to_state: Selected2 -- from_state: EditLabel - label: onMouseDown - to_state: Ready -- from_state: Move - label: onMouseDown - to_state: Selected1 -- from_state: Move - label: onMouseUp - to_state: Selected2 -- from_state: Placing - label: onMouseDown - to_state: Resize -- from_state: Ready - label: onMouseDown - to_state: CornerSelected -- from_state: Ready - label: onMouseDown - to_state: Selected1 -- from_state: Ready - label: onNewGroup - to_state: Placing -- from_state: Resize - label: onMouseUp - to_state: Selected1 -- from_state: Selected1 - label: onMouseMove - to_state: Move -- from_state: Selected1 - label: onMouseUp - to_state: Selected2 -- from_state: Selected2 - label: onKeyDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Selected3 -- from_state: Selected2 - label: onNewGroup - to_state: Ready -- from_state: Selected3 - label: onMouseMove - to_state: Move -- from_state: Selected3 - label: onMouseUp - to_state: ContextMenu -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/hotkeys.png b/awx/ui/client/src/network-ui/designs/hotkeys.png deleted file mode 100644 index d21ff09cc639..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/hotkeys.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/hotkeys.yml b/awx/ui/client/src/network-ui/designs/hotkeys.yml deleted file mode 100644 index 6d237bda46eb..000000000000 --- a/awx/ui/client/src/network-ui/designs/hotkeys.yml +++ /dev/null @@ -1,25 +0,0 @@ -finite_state_machine_id: 1 -name: hotkeys_fsm -states: -- id: 2 - label: Enabled - x: 585 - y: 396 -- id: 1 - label: Start - x: 585 - y: 160 -- id: 3 - label: Disabled - x: 331 - y: 408 -transitions: -- from_state: Enabled - label: onDisable - to_state: Disabled -- from_state: Disabled - label: onEnable - to_state: Enabled -- from_state: Start - label: start - to_state: Enabled diff --git a/awx/ui/client/src/network-ui/designs/keybindings.png b/awx/ui/client/src/network-ui/designs/keybindings.png deleted file mode 100644 index b6a0b89a1962..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/keybindings.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/keybindings.yml b/awx/ui/client/src/network-ui/designs/keybindings.yml deleted file mode 100644 index b98167e288b1..000000000000 --- a/awx/ui/client/src/network-ui/designs/keybindings.yml +++ /dev/null @@ -1,38 +0,0 @@ -diagram_id: 68 -finite_state_machine_id: 18 -name: diagram -states: -- id: 1 - label: Enabled - x: 842 - y: 533 -- id: 2 - label: Start - x: 839 - y: 270 -- id: 3 - label: Disabled - x: 1412 - y: 522 -transitions: -- from_state: Start - label: start - to_state: Enabled -- from_state: Disabled - label: onBindDocument - to_state: Enabled -- from_state: Enabled - label: onUnbindDocument - to_state: Disabled -- from_state: Disabled - label: onDetailsPanelClose - to_state: Enabled -- from_state: Enabled - label: onDetailsPanel - to_state: Disabled -- from_state: Enabled - label: onSearchDropdown - to_state: Disabled -- from_state: Disabled - label: onSearchDropdownClose - to_state: Enabled diff --git a/awx/ui/client/src/network-ui/designs/link.png b/awx/ui/client/src/network-ui/designs/link.png deleted file mode 100644 index 4058fd551955..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/link.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/link.yml b/awx/ui/client/src/network-ui/designs/link.yml deleted file mode 100644 index 7b3a7ea16c06..000000000000 --- a/awx/ui/client/src/network-ui/designs/link.yml +++ /dev/null @@ -1,42 +0,0 @@ -finite_state_machine_id: 4 -name: link_fsm -states: -- id: 5 - label: Selecting - x: -429 - y: 63 -- id: 2 - label: Start - x: 15 - y: -221 -- id: 4 - label: Connecting - x: -429 - y: 466 -- id: 3 - label: Connected - x: 47 - y: 453 -- id: 1 - label: Ready - x: 26 - y: 61 -transitions: -- from_state: Ready - label: onNewLink - to_state: Selecting -- from_state: Selecting - label: onMouseUp - to_state: Connecting -- from_state: Connecting - label: onMouseUp - to_state: Connected -- from_state: Connecting - label: onMouseUp - to_state: Ready -- from_state: Connected - label: start - to_state: Ready -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/mode.png b/awx/ui/client/src/network-ui/designs/mode.png deleted file mode 100644 index b8dff5610da2..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/mode.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/mode.yml b/awx/ui/client/src/network-ui/designs/mode.yml deleted file mode 100644 index b124a3d32ee0..000000000000 --- a/awx/ui/client/src/network-ui/designs/mode.yml +++ /dev/null @@ -1,96 +0,0 @@ -diagram_id: 68 -finite_state_machine_id: 9 -name: mode_fsm -states: -- id: 7 - label: Device - x: 558 - y: 821 -- id: 2 - label: Interface - x: 340 - y: 1053 -- id: 5 - label: MultiSite - x: 569 - y: -88 -- id: 4 - label: Process - x: 833 - y: 1051 -- id: 6 - label: Rack - x: 571 - y: 486 -- id: 3 - label: Site - x: 564 - y: 201 -- id: 1 - label: Start - x: 568 - y: -379 -transitions: -- from_state: Device - label: onMouseWheel - to_state: Process -- from_state: Device - label: onMouseWheel - to_state: Rack -- from_state: Device - label: onMouseWheel - to_state: Interface -- from_state: Device - label: onScaleChanged - to_state: Interface -- from_state: Device - label: onScaleChanged - to_state: Rack -- from_state: Device - label: onScaleChanged - to_state: Process -- from_state: Interface - label: onMouseWheel - to_state: Device -- from_state: Interface - label: onScaleChanged - to_state: Device -- from_state: MultiSite - label: onMouseWheel - to_state: Site -- from_state: MultiSite - label: onScaleChanged - to_state: Site -- from_state: Process - label: onMouseWheel - to_state: Device -- from_state: Process - label: onScaleChanged - to_state: Device -- from_state: Rack - label: onMouseWheel - to_state: Site -- from_state: Rack - label: onMouseWheel - to_state: Device -- from_state: Rack - label: onScaleChanged - to_state: Site -- from_state: Rack - label: onScaleChanged - to_state: Device -- from_state: Site - label: onMouseWheel - to_state: MultiSite -- from_state: Site - label: onMouseWheel - to_state: Rack -- from_state: Site - label: onScaleChanged - to_state: MultiSite -- from_state: Site - label: onScaleChanged - to_state: Rack -- from_state: Start - label: start - to_state: MultiSite diff --git a/awx/ui/client/src/network-ui/designs/move.png b/awx/ui/client/src/network-ui/designs/move.png deleted file mode 100644 index e199991c7655..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/move.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/move.readonly.png b/awx/ui/client/src/network-ui/designs/move.readonly.png deleted file mode 100644 index 95db906bcd4c..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/move.readonly.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/move.readonly.yml b/awx/ui/client/src/network-ui/designs/move.readonly.yml deleted file mode 100644 index 6d1245d772ca..000000000000 --- a/awx/ui/client/src/network-ui/designs/move.readonly.yml +++ /dev/null @@ -1,65 +0,0 @@ -diagram_id: 91 -name: diagram -states: -- id: 0 - label: ContextMenu - x: 826 - y: 1008 -- id: 1 - label: Disable - x: 914 - y: 115 -- id: 5 - label: Ready - x: 702 - y: 327 -- id: 6 - label: Selected1 - x: 397 - y: 332 -- id: 7 - label: Selected2 - x: 268 - y: 735 -- id: 8 - label: Selected3 - x: 225 - y: 1021 -- id: 9 - label: Start - x: 704 - y: 128 -transitions: -- from_state: ContextMenu - label: onDetailsPanel - to_state: Selected2 -- from_state: ContextMenu - label: onMouseDown - to_state: Selected2 -- from_state: Ready - label: onMouseDown - to_state: Selected1 -- from_state: Selected1 - label: onMouseUp - to_state: Selected2 -- from_state: Selected2 - label: onKeyDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Selected3 -- from_state: Selected2 - label: onMouseDown - to_state: Ready -- from_state: Selected3 - label: '' - to_state: Selected3 -- from_state: Selected3 - label: onMouseMove - to_state: Selected2 -- from_state: Selected3 - label: onMouseUp - to_state: ContextMenu -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/move.yml b/awx/ui/client/src/network-ui/designs/move.yml deleted file mode 100644 index 42e42b6dfd49..000000000000 --- a/awx/ui/client/src/network-ui/designs/move.yml +++ /dev/null @@ -1,107 +0,0 @@ -diagram_id: 87 -name: move -states: -- id: 8 - label: ContextMenu - x: 826 - y: 1008 -- id: 0 - label: Disable - x: 914 - y: 115 -- id: 6 - label: EditLabel - x: 765 - y: 684 -- id: 4 - label: Move - x: 118 - y: 594 -- id: 5 - label: Placing - x: 263 - y: 89 -- id: 2 - label: Ready - x: 702 - y: 327 -- id: 3 - label: Selected1 - x: 397 - y: 332 -- id: 7 - label: Selected2 - x: 268 - y: 735 -- id: 9 - label: Selected3 - x: 361 - y: 961 -- id: 1 - label: Start - x: 704 - y: 128 -transitions: -- from_state: ContextMenu - label: onDetailsPanel - to_state: Selected2 -- from_state: ContextMenu - label: onLabelEdit - to_state: EditLabel -- from_state: ContextMenu - label: onMouseDown - to_state: Selected2 -- from_state: EditLabel - label: onKeyDown - to_state: Selected2 -- from_state: EditLabel - label: onMouseDown - to_state: Ready -- from_state: Move - label: onMouseDown - to_state: Selected1 -- from_state: Move - label: onMouseUp - to_state: Selected1 -- from_state: Placing - label: onMouseDown - to_state: Selected1 -- from_state: Placing - label: onMouseMove - to_state: Move -- from_state: Ready - label: onMouseDown - to_state: Selected1 -- from_state: Ready - label: onNewDevice - to_state: Placing -- from_state: Ready - label: onPasteDevice - to_state: Selected2 -- from_state: Selected1 - label: onMouseMove - to_state: Move -- from_state: Selected1 - label: onMouseUp - to_state: Selected2 -- from_state: Selected2 - label: onKeyDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Selected3 -- from_state: Selected2 - label: onMouseDown - to_state: Ready -- from_state: Selected2 - label: onNewDevice - to_state: Ready -- from_state: Selected3 - label: onMouseMove - to_state: Move -- from_state: Selected3 - label: onMouseUp - to_state: ContextMenu -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/null.png b/awx/ui/client/src/network-ui/designs/null.png deleted file mode 100644 index f095a1cad41b..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/null.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/null.yml b/awx/ui/client/src/network-ui/designs/null.yml deleted file mode 100644 index 5218cfe1f722..000000000000 --- a/awx/ui/client/src/network-ui/designs/null.yml +++ /dev/null @@ -1,15 +0,0 @@ -finite_state_machine_id: 17 -name: null_fsm -states: -- id: 1 - label: Start - x: 391 - y: 132 -- id: 2 - label: Ready - x: 402 - y: 346 -transitions: -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/pipeline.png b/awx/ui/client/src/network-ui/designs/pipeline.png deleted file mode 100644 index c5fb2b12f760..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/pipeline.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/pipeline.yml b/awx/ui/client/src/network-ui/designs/pipeline.yml deleted file mode 100644 index 43052f2b2da6..000000000000 --- a/awx/ui/client/src/network-ui/designs/pipeline.yml +++ /dev/null @@ -1,233 +0,0 @@ -channels: -- from_fsm: buttons_fsm - from_fsm_id: 7 - inbox: '' - outbox: '' - to_fsm: button_fsm - to_fsm_id: 12 - type: '' -- from_fsm: buttons_fsm - from_fsm_id: 7 - inbox: '' - outbox: '' - to_fsm: toolbox_fsm - to_fsm_id: 14 - type: '' -- from_fsm: details_panel_fsm - from_fsm_id: 21 - inbox: '' - outbox: '' - to_fsm: move_fsm - to_fsm_id: 3 - type: '' -- from_fsm: device_detail_fsm - from_fsm_id: 19 - inbox: '' - outbox: '' - to_fsm: view_fsm - to_fsm_id: 2 - type: '' -- from_fsm: group_fsm - from_fsm_id: 5 - inbox: '' - outbox: '' - to_fsm: stream_fsm - to_fsm_id: 20 - type: '' -- from_fsm: hotkeys_fsm - from_fsm_id: 1 - inbox: '' - outbox: '' - to_fsm: null_fsm - to_fsm_id: 17 - type: '' -- from_fsm: keybindings_fsm - from_fsm_id: 18 - inbox: '' - outbox: '' - to_fsm: hotkeys_fsm - to_fsm_id: 1 - type: '' -- from_fsm: link_fsm - from_fsm_id: 4 - inbox: '' - outbox: '' - to_fsm: details_panel_fsm - to_fsm_id: 21 - type: '' -- from_fsm: mode_fsm - from_fsm_id: 9 - inbox: '' - outbox: '' - to_fsm: time_fsm - to_fsm_id: 8 - type: '' -- from_fsm: move_fsm - from_fsm_id: 3 - inbox: '' - outbox: '' - to_fsm: device_detail_fsm - to_fsm_id: 19 - type: '' -- from_fsm: rack_fsm - from_fsm_id: 6 - inbox: '' - outbox: '' - to_fsm: group_fsm - to_fsm_id: 5 - type: '' -- from_fsm: site_fsm - from_fsm_id: 22 - inbox: '' - outbox: '' - to_fsm: rack_fsm - to_fsm_id: 6 - type: '' -- from_fsm: stream_fsm - from_fsm_id: 20 - inbox: '' - outbox: '' - to_fsm: link_fsm - to_fsm_id: 4 - type: '' -- from_fsm: test_fsm - from_fsm_id: 23 - inbox: '' - outbox: '' - to_fsm: mode_fsm - to_fsm_id: 9 - type: '' -- from_fsm: time_fsm - from_fsm_id: 8 - inbox: '' - outbox: '' - to_fsm: buttons_fsm - to_fsm_id: 7 - type: '' -- from_fsm: toolbox_fsm - from_fsm_id: 14 - inbox: '' - outbox: '' - to_fsm: site_fsm - to_fsm_id: 22 - type: '' -- from_fsm: view_fsm - from_fsm_id: 2 - inbox: '' - outbox: '' - to_fsm: keybindings_fsm - to_fsm_id: 18 - type: '' -diagram_id: 85 -fsms: -- id: 12 - name: button_fsm - x1: -2438 - x2: -3026 - y1: -934 - y2: -1532 -- id: 7 - name: buttons_fsm - x1: -2650 - x2: -2850 - y1: -16 - y2: -619 -- id: 21 - name: details_panel_fsm - x1: 5669 - x2: 5140 - y1: -64 - y2: -521 -- id: 19 - name: device_detail_fsm - x1: 7667 - x2: 7214 - y1: -110 - y2: -562 -- id: 5 - name: group_fsm - x1: 3685 - x2: 2256 - y1: 278 - y2: -906 -- id: 1 - name: hotkeys_fsm - x1: 9692 - x2: 9281 - y1: -124 - y2: -549 -- id: 18 - name: keybindings_fsm - x1: 9223 - x2: 8370 - y1: -71 - y2: -614 -- id: 4 - name: link_fsm - x1: 5080 - x2: 4436 - y1: 154 - y2: -732 -- id: 9 - name: mode_fsm - x1: -3760 - x2: -4453 - y1: 192 - y2: -1439 -- id: 3 - name: move_fsm - x1: 6968 - x2: 5813 - y1: 146 - y2: -935 -- id: 17 - name: null_fsm - x1: 10125 - x2: 9925 - y1: -129 - y2: -543 -- id: 6 - name: rack_fsm - x1: 2214 - x2: 1047 - y1: 127 - y2: -753 -- id: 22 - name: site_fsm - x1: 964 - x2: -190 - y1: 128 - y2: -768 -- id: 20 - name: stream_fsm - x1: 4376 - x2: 3868 - y1: 56 - y2: -643 -- id: 23 - name: test_fsm - x1: -4569 - x2: -5140 - y1: 72 - y2: -863 -- id: 8 - name: time_fsm - x1: -3122 - x2: -3693 - y1: -69 - y2: -553 -- id: 14 - name: toolbox_fsm - x1: -680 - x2: -1722 - y1: 265 - y2: -904 -- id: 2 - name: view_fsm - x1: 8311 - x2: 7734 - y1: -25 - y2: -684 -name: diagram -states: [] -transitions: [] diff --git a/awx/ui/client/src/network-ui/designs/rack.png b/awx/ui/client/src/network-ui/designs/rack.png deleted file mode 100644 index 505cfdda6b85..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/rack.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/rack.yml b/awx/ui/client/src/network-ui/designs/rack.yml deleted file mode 100644 index 3a5f7cae8c74..000000000000 --- a/awx/ui/client/src/network-ui/designs/rack.yml +++ /dev/null @@ -1,83 +0,0 @@ -diagram_id: 65 -finite_state_machine_id: 6 -name: rack_fsm -states: -- id: 9 - label: ContextMenu - x: 898 - y: 1016 -- id: 2 - label: Disable - x: 760 - y: 468 -- id: 7 - label: EditLabel - x: 600 - y: 934 -- id: 8 - label: Move - x: -69 - y: 861 -- id: 1 - label: Ready - x: 532 - y: 560 -- id: 4 - label: Selected1 - x: 214 - y: 566 -- id: 5 - label: Selected2 - x: 220 - y: 810 -- id: 6 - label: Selected3 - x: 249 - y: 1047 -- id: 3 - label: Start - x: 582 - y: 334 -transitions: -- from_state: ContextMenu - label: onLabelEdit - to_state: EditLabel -- from_state: ContextMenu - label: onMouseDown - to_state: Ready -- from_state: EditLabel - label: onKeyDown - to_state: Selected2 -- from_state: EditLabel - label: onMouseDown - to_state: Ready -- from_state: Move - label: onMouseUp - to_state: Selected2 -- from_state: Ready - label: onMouseDown - to_state: Selected1 -- from_state: Selected1 - label: onMouseMove - to_state: Move -- from_state: Selected1 - label: onMouseUp - to_state: Selected2 -- from_state: Selected2 - label: onKeyDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Selected3 -- from_state: Selected3 - label: onMouseMove - to_state: Move -- from_state: Selected3 - label: onMouseUp - to_state: ContextMenu -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/site.png b/awx/ui/client/src/network-ui/designs/site.png deleted file mode 100644 index 72d256f552e0..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/site.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/site.yml b/awx/ui/client/src/network-ui/designs/site.yml deleted file mode 100644 index ab807f28d1b7..000000000000 --- a/awx/ui/client/src/network-ui/designs/site.yml +++ /dev/null @@ -1,83 +0,0 @@ -diagram_id: 63 -finite_state_machine_id: 22 -name: site_fsm -states: -- id: 9 - label: ContextMenu - x: 887 - y: 1031 -- id: 2 - label: Disable - x: 760 - y: 468 -- id: 7 - label: EditLabel - x: 600 - y: 934 -- id: 8 - label: Move - x: -69 - y: 861 -- id: 1 - label: Ready - x: 532 - y: 560 -- id: 4 - label: Selected1 - x: 214 - y: 566 -- id: 5 - label: Selected2 - x: 220 - y: 810 -- id: 6 - label: Selected3 - x: 249 - y: 1047 -- id: 3 - label: Start - x: 582 - y: 334 -transitions: -- from_state: ContextMenu - label: onLabelEdit - to_state: EditLabel -- from_state: ContextMenu - label: onMouseDown - to_state: Ready -- from_state: EditLabel - label: onKeyDown - to_state: Selected2 -- from_state: EditLabel - label: onMouseDown - to_state: Ready -- from_state: Move - label: onMouseUp - to_state: Selected2 -- from_state: Ready - label: onMouseDown - to_state: Selected1 -- from_state: Selected1 - label: onMouseMove - to_state: Move -- from_state: Selected1 - label: onMouseUp - to_state: Selected2 -- from_state: Selected2 - label: onKeyDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Ready -- from_state: Selected2 - label: onMouseDown - to_state: Selected3 -- from_state: Selected3 - label: onMouseMove - to_state: Move -- from_state: Selected3 - label: onMouseUp - to_state: ContextMenu -- from_state: Start - label: start - to_state: Ready diff --git a/awx/ui/client/src/network-ui/designs/stream.png b/awx/ui/client/src/network-ui/designs/stream.png deleted file mode 100644 index 3a00d21e9768..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/stream.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/stream.yml b/awx/ui/client/src/network-ui/designs/stream.yml deleted file mode 100644 index cf12e9531219..000000000000 --- a/awx/ui/client/src/network-ui/designs/stream.yml +++ /dev/null @@ -1,42 +0,0 @@ -finite_state_machine_id: 20 -name: stream_fsm -states: -- id: 4 - label: Connecting - x: 344 - y: 312 -- id: 5 - label: Selecting - x: 311 - y: 23 -- id: 1 - label: Ready - x: 36 - y: 28 -- id: 3 - label: Connected - x: 55 - y: 317 -- id: 2 - label: Start - x: 43 - y: -188 -transitions: -- from_state: Ready - label: onNewStream - to_state: Selecting -- from_state: Start - label: start - to_state: Ready -- from_state: Connected - label: start - to_state: Ready -- from_state: Connecting - label: onMouseUp - to_state: Ready -- from_state: Connecting - label: onMouseUp - to_state: Connected -- from_state: Selecting - label: onMouseUp - to_state: Connecting diff --git a/awx/ui/client/src/network-ui/designs/test.yml b/awx/ui/client/src/network-ui/designs/test.yml deleted file mode 100644 index 37092ab24535..000000000000 --- a/awx/ui/client/src/network-ui/designs/test.yml +++ /dev/null @@ -1,50 +0,0 @@ -diagram_id: 69 -finite_state_machine_id: 23 -name: diagram -states: -- id: 1 - label: Disabled - x: 895 - y: 344 -- id: 4 - label: Loading - x: 524 - y: 710 -- id: 5 - label: Ready - x: 722 - y: 509 -- id: 6 - label: Reporting - x: 926 - y: 721 -- id: 3 - label: Running - x: 720 - y: 922 -- id: 2 - label: Start - x: 702 - y: 186 -transitions: -- from_state: Disabled - label: onEnableTest - to_state: Ready -- from_state: Loading - label: start - to_state: Running -- from_state: Ready - label: onDisableTest - to_state: Disabled -- from_state: Ready - label: start - to_state: Loading -- from_state: Reporting - label: start - to_state: Loading -- from_state: Running - label: onTestCompleted - to_state: Reporting -- from_state: Start - label: start - to_state: Disabled diff --git a/awx/ui/client/src/network-ui/designs/time.png b/awx/ui/client/src/network-ui/designs/time.png deleted file mode 100644 index cec5fe69ee86..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/time.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/time.yml b/awx/ui/client/src/network-ui/designs/time.yml deleted file mode 100644 index 6efaa5f38c2c..000000000000 --- a/awx/ui/client/src/network-ui/designs/time.yml +++ /dev/null @@ -1,37 +0,0 @@ -finite_state_machine_id: 8 -name: time_fsm -states: -- id: 1 - label: Present - x: 256 - y: 123 -- id: 2 - label: Start - x: 245 - y: -161 -- id: 3 - label: Past - x: -115 - y: 129 -transitions: -- from_state: Past - label: onRedo - to_state: Present -- from_state: Past - label: onMouseWheel - to_state: Present -- from_state: Past - label: onKeyDown - to_state: Present -- from_state: Start - label: start - to_state: Present -- from_state: Present - label: onUndo - to_state: Past -- from_state: Present - label: onMouseWheel - to_state: Past -- from_state: Present - label: onKeyDown - to_state: Past diff --git a/awx/ui/client/src/network-ui/designs/toolbox.png b/awx/ui/client/src/network-ui/designs/toolbox.png deleted file mode 100644 index 14f676bddcbc..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/toolbox.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/toolbox.yml b/awx/ui/client/src/network-ui/designs/toolbox.yml deleted file mode 100644 index 99fd550b542e..000000000000 --- a/awx/ui/client/src/network-ui/designs/toolbox.yml +++ /dev/null @@ -1,98 +0,0 @@ -finite_state_machine_id: 14 -name: toolbox_fsm -states: -- id: 9 - label: Disabled - x: 885 - y: 141 -- id: 7 - label: OffScreen - x: 1140 - y: 217 -- id: 1 - label: Selected - x: 1180 - y: 959 -- id: 2 - label: Move - x: 1409 - y: 741 -- id: 3 - label: Ready - x: 892 - y: 429 -- id: 4 - label: Scrolling - x: 567 - y: 431 -- id: 5 - label: Selecting - x: 888 - y: 710 -- id: 6 - label: Dropping - x: 1358 - y: 431 -- id: 8 - label: Start - x: 672 - y: 196 -- id: 10 - label: OffScreen2 - x: 1115 - y: -12 -transitions: -- from_state: Ready - label: onDisable - to_state: Disabled -- from_state: OffScreen2 - label: onToggleToolbox - to_state: Disabled -- from_state: OffScreen2 - label: onEnable - to_state: OffScreen -- from_state: Ready - label: onToggleToolbox - to_state: OffScreen -- from_state: Selecting - label: onMouseDown - to_state: Selected -- from_state: Selected - label: onMouseMove - to_state: Move -- from_state: Selecting - label: onMouseDown - to_state: Ready -- from_state: Selected - label: onMouseUp - to_state: Ready -- from_state: Dropping - label: start - to_state: Ready -- from_state: Start - label: start - to_state: Ready -- from_state: Scrolling - label: onMouseWheel - to_state: Ready -- from_state: OffScreen - label: onToggleToolbox - to_state: Ready -- from_state: Disabled - label: onEnable - to_state: Ready -- from_state: Ready - label: onMouseWheel - to_state: Scrolling -- from_state: Ready - label: onMouseDown - to_state: Selecting -- from_state: Move - label: onMouseUp - to_state: Dropping -- from_state: OffScreen - label: onDisable - to_state: OffScreen2 -- from_state: Disabled - label: onToggleToolbox - to_state: OffScreen2 diff --git a/awx/ui/client/src/network-ui/designs/view.png b/awx/ui/client/src/network-ui/designs/view.png deleted file mode 100644 index e0d7f261b2ec..000000000000 Binary files a/awx/ui/client/src/network-ui/designs/view.png and /dev/null differ diff --git a/awx/ui/client/src/network-ui/designs/view.yml b/awx/ui/client/src/network-ui/designs/view.yml deleted file mode 100644 index 75f3c5cb4731..000000000000 --- a/awx/ui/client/src/network-ui/designs/view.yml +++ /dev/null @@ -1,45 +0,0 @@ -finite_state_machine_id: 2 -name: view_fsm -states: -- id: 1 - label: Start - x: 498 - y: 175 -- id: 2 - label: Ready - x: 506 - y: 395 -- id: 3 - label: Scale - x: 310 - y: 626 -- id: 4 - label: Pan - x: 741 - y: 631 -- id: 5 - label: Pressed - x: 739 - y: 392 -transitions: -- from_state: Scale - label: onMouseWheel - to_state: Ready -- from_state: Start - label: start - to_state: Ready -- from_state: Ready - label: onMouseWheel - to_state: Scale -- from_state: Ready - label: onMouseDown - to_state: Pressed -- from_state: Pressed - label: onMouseMove - to_state: Pan -- from_state: Pressed - label: onMouseUp - to_state: Ready -- from_state: Pan - label: onMouseUp - to_state: Ready diff --git a/awx/ui/client/src/network-ui/details.panel.fsm.js b/awx/ui/client/src/network-ui/details.panel.fsm.js deleted file mode 100644 index 2d8560594db8..000000000000 --- a/awx/ui/client/src/network-ui/details.panel.fsm.js +++ /dev/null @@ -1,62 +0,0 @@ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Collapsed () { - this.name = 'Collapsed'; -} -inherits(_Collapsed, _State); -var Collapsed = new _Collapsed(); -exports.Collapsed = Collapsed; - -function _Expanded () { - this.name = 'Expanded'; -} -inherits(_Expanded, _State); -var Expanded = new _Expanded(); -exports.Expanded = Expanded; - - - - -_Start.prototype.start = function (controller, msg_type, $event) { - - controller.scope.$parent.vm.rightPanelIsExpanded = false; - controller.changeState(Collapsed); - controller.handle_message(msg_type, $event); - -}; -_Start.prototype.start.transitions = ['Collapsed']; - - - -_Collapsed.prototype.onDetailsPanel = function (controller, msg_type, $event) { - - controller.scope.$parent.vm.rightPanelIsExpanded = true; - controller.changeState(Expanded); - controller.handle_message(msg_type, $event); - -}; -_Collapsed.prototype.onDetailsPanel.transitions = ['Expanded']; - - - -_Expanded.prototype.onDetailsPanelClose = function (controller, msg_type, $event) { - - controller.scope.$parent.vm.rightPanelIsExpanded = false; - controller.scope.$parent.vm.keyPanelExpanded = false; - controller.changeState(Collapsed); - controller.handle_message(msg_type, $event); -}; -_Expanded.prototype.onDetailsPanelClose.transitions = ['Collapsed']; diff --git a/awx/ui/client/src/network-ui/extract.js b/awx/ui/client/src/network-ui/extract.js deleted file mode 100755 index 79edb17f602e..000000000000 --- a/awx/ui/client/src/network-ui/extract.js +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env node -var YAML = require('yamljs'); - -function Iterator(o){ - var k=Object.keys(o); - return { - next:function(){ - return k.shift(); - } - }; -} - -var myArgs = process.argv.slice(2); -var implementation = require(myArgs[0]); -var states = []; -var transitions = []; -var data = {states: states, - transitions: transitions}; - -var state_iter = Iterator(implementation); -var transition_iter = null; -var next_state = state_iter.next(); -var next_transition = null; -var state = null; -var transition = null; -var i = 0; -while(next_state !== undefined) { - state = implementation[next_state]; - transition_iter = Iterator(state.constructor.prototype); - next_transition = transition_iter.next(); - while (next_transition !== undefined) { - transition = state.constructor.prototype[next_transition]; - if (transition.transitions !== undefined) { - for (i = 0; i < transition.transitions.length; i++) { - transitions.push({from_state: next_state, - to_state:transition.transitions[i], - label:next_transition}); - } - } - next_transition = transition_iter.next(); - } - states.push({label: state.name}); - next_state = state_iter.next(); -} - - -console.log(YAML.stringify(data)); diff --git a/awx/ui/client/src/network-ui/extract_messages.js b/awx/ui/client/src/network-ui/extract_messages.js deleted file mode 100755 index aee32413de86..000000000000 --- a/awx/ui/client/src/network-ui/extract_messages.js +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env node -var YAML = require('yamljs'); - -function Iterator(o){ - var k=Object.keys(o); - return { - next:function(){ - return k.shift(); - } - }; -} - -var myArgs = process.argv.slice(2); -var implementation = require(myArgs[0]); -var messages = []; -var data = {messages: messages}; -var message_iter = Iterator(implementation); -var field_iter = null; -var next_message = message_iter.next(); -var next_field = null; -var message = null; -var message_instance = null; -var fields = null; -// var field = null; -// var i = 0; -while(next_message !== undefined) { - message = implementation[next_message]; - try { - message_instance = new message(); - } catch(err) { - next_message = message_iter.next(); - continue; - } - fields = []; - field_iter = Iterator(message_instance); - next_field = field_iter.next(); - while (next_field !== undefined) { - fields.push(next_field); - // field = message.constructor.prototype[next_field]; - // if (field.transitions !== undefined) { - // for (i = 0; i < field.transitions.length; i++) { - // transitions.push({from_message: next_message, - // to_message:field.transitions[i], - // label:next_field}); - // } - // } - next_field = field_iter.next(); - } - if(message_instance.msg_type !== null && message_instance.msg_type !== undefined) { - messages.push({msg_type: message_instance.msg_type, - fields: fields}); - } - next_message = message_iter.next(); -} - - -console.log(YAML.stringify(data)); diff --git a/awx/ui/client/src/network-ui/fsm.js b/awx/ui/client/src/network-ui/fsm.js deleted file mode 100644 index ffd833623d9b..000000000000 --- a/awx/ui/client/src/network-ui/fsm.js +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var messages = require('./messages.js'); - -function Channel(from_controller, to_controller, tracer) { - this.tracer = tracer; - this.from_controller = from_controller; - this.to_controller = to_controller; - this.trace = false; -} -exports.Channel = Channel; - -Channel.prototype.send = function(msg_type, message) { - this.to_controller.handle_message(msg_type, message); -}; - -function NullChannel(from_controller, tracer) { - this.tracer = tracer; - this.from_controller = from_controller; - this.trace = false; -} - -NullChannel.prototype.send = function() { -}; - -function FSMController (scope, name, initial_state, tracer) { - this.scope = scope; - this.name = name; - this.state = initial_state; - this.delegate_channel = new NullChannel(this, tracer); - this.tracer = tracer; - this.trace = true; - this.handling_message_type = 'start'; - this.state.start(this); - this.handling_message_type = null; -} -exports.FSMController = FSMController; - -FSMController.prototype.changeState = function (state) { - var old_handling_message_type; - if(this.state !== null) { - old_handling_message_type = this.handling_message_type; - this.handling_message_type = 'end'; - this.state.end(this); - this.handling_message_type = old_handling_message_type; - } - if (this.trace) { - this.tracer.send_trace_message(new messages.FSMTrace(this.tracer.trace_order_seq(), - this.name, - this.state.name, - state.name, - this.handling_message_type)); - } - this.state = state; - if(state !== null) { - old_handling_message_type = this.handling_message_type; - this.handling_message_type = 'start'; - state.start(this); - this.handling_message_type = old_handling_message_type; - } -}; - -FSMController.prototype.handle_message = function(msg_type, message) { - - var old_handling_message_type = this.handling_message_type; - this.handling_message_type = msg_type; - var handler_name = 'on' + msg_type; - if (typeof(this.state[handler_name]) !== "undefined") { - this.state[handler_name](this, msg_type, message); - } else { - this.default_handler(msg_type, message); - } - this.handling_message_type = old_handling_message_type; -}; - -FSMController.prototype.default_handler = function(msg_type, message) { - this.delegate_channel.send(msg_type, message); -}; - -function _State () { -} - -_State.prototype.start = function () { -}; - -_State.prototype.end = function () { -}; - -var State = new _State(); -exports.State = State; -exports._State = _State; diff --git a/awx/ui/client/src/network-ui/host.directive.js b/awx/ui/client/src/network-ui/host.directive.js deleted file mode 100644 index aa0b13d3c427..000000000000 --- a/awx/ui/client/src/network-ui/host.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/host.partial.svg'); - -function host () { - return { restrict: 'A', templateUrl}; -} -exports.host = host; diff --git a/awx/ui/client/src/network-ui/host.partial.svg b/awx/ui/client/src/network-ui/host.partial.svg deleted file mode 100644 index 86e5c875c2e5..000000000000 --- a/awx/ui/client/src/network-ui/host.partial.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} - - {{item.name}}{{item.edit_label?'_':''}} - - diff --git a/awx/ui/client/src/network-ui/hotkeys.fsm.js b/awx/ui/client/src/network-ui/hotkeys.fsm.js deleted file mode 100644 index abc3a3cc7595..000000000000 --- a/awx/ui/client/src/network-ui/hotkeys.fsm.js +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Enabled () { - this.name = 'Enabled'; -} -inherits(_Enabled, _State); -var Enabled = new _Enabled(); -exports.Enabled = Enabled; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Disabled () { - this.name = 'Disabled'; -} -inherits(_Disabled, _State); -var Disabled = new _Disabled(); -exports.Disabled = Disabled; - - - - -_Enabled.prototype.onDisable = function (controller) { - - controller.changeState(Disabled); - -}; -_Enabled.prototype.onDisable.transitions = ['Disabled']; - - -_Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { - - var scope = controller.scope; - - if ($event.key === 'r' && ($event.ctrlKey || $event.metaKey)) { - location.reload(); - } - - if ($event.key === 'd') { - scope.debug.hidden = !scope.debug.hidden; - return; - } - if ($event.key === 'i') { - scope.hide_interfaces = !scope.hide_interfaces; - return; - } - if($event.keyCode === 27){ - // 27 is the escape key - scope.reset_fsm_state(); - return; - } - - if ($event.key === '0') { - scope.jump_to_animation(0, 0, 1.0); - } - - controller.delegate_channel.send(msg_type, $event); -}; - -_Start.prototype.start = function (controller) { - - controller.changeState(Enabled); - -}; -_Start.prototype.start.transitions = ['Enabled']; - - - -_Disabled.prototype.onEnable = function (controller) { - - controller.changeState(Enabled); - -}; -_Disabled.prototype.onEnable.transitions = ['Enabled']; - - diff --git a/awx/ui/client/src/network-ui/inventory.toolbox.directive.js b/awx/ui/client/src/network-ui/inventory.toolbox.directive.js deleted file mode 100644 index d3cfa8b65e2c..000000000000 --- a/awx/ui/client/src/network-ui/inventory.toolbox.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/inventory_toolbox.partial.svg'); - -function inventoryToolbox () { - return { restrict: 'A', templateUrl}; -} -exports.inventoryToolbox = inventoryToolbox; diff --git a/awx/ui/client/src/network-ui/inventory_toolbox.partial.svg b/awx/ui/client/src/network-ui/inventory_toolbox.partial.svg deleted file mode 100644 index 88d4c67cfe15..000000000000 --- a/awx/ui/client/src/network-ui/inventory_toolbox.partial.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{toolbox.name}} - - diff --git a/awx/ui/client/src/network-ui/keybindings.fsm.js b/awx/ui/client/src/network-ui/keybindings.fsm.js deleted file mode 100644 index 3e9fcd8ee499..000000000000 --- a/awx/ui/client/src/network-ui/keybindings.fsm.js +++ /dev/null @@ -1,93 +0,0 @@ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Disabled () { - this.name = 'Disabled'; -} -inherits(_Disabled, _State); -var Disabled = new _Disabled(); -exports.Disabled = Disabled; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Enabled () { - this.name = 'Enabled'; -} -inherits(_Enabled, _State); -var Enabled = new _Enabled(); -exports.Enabled = Enabled; - - - - -_Disabled.prototype.onBindDocument = function (controller) { - - $(document).bind("keydown", controller.scope.onKeyDown); - controller.changeState(Enabled); - -}; -_Disabled.prototype.onBindDocument.transitions = ['Enabled']; - - - -_Start.prototype.start = function (controller) { - - $(document).bind("keydown", controller.scope.onKeyDown); - controller.changeState(Enabled); - -}; -_Start.prototype.start.transitions = ['Enabled']; - - - -_Enabled.prototype.onUnbindDocument = function (controller) { - - $(document).unbind("keydown", controller.scope.onKeyDown); - controller.changeState(Disabled); - -}; -_Enabled.prototype.onUnbindDocument.transitions = ['Disabled']; - -_Disabled.prototype.onDetailsPanelClose = function (controller) { - - $(document).bind("keydown", controller.scope.onKeyDown); - controller.changeState(Enabled); - -}; -_Disabled.prototype.onDetailsPanelClose.transitions = ['Enabled']; - -_Disabled.prototype.onSearchDropdownClose = function (controller) { - - $(document).bind("keydown", controller.scope.onKeyDown); - controller.changeState(Enabled); - -}; -_Disabled.prototype.onSearchDropdownClose.transitions = ['Enabled']; - - - -_Enabled.prototype.onDetailsPanel = function (controller) { - - $(document).unbind("keydown", controller.scope.onKeyDown); - controller.changeState(Disabled); - -}; -_Enabled.prototype.onDetailsPanel.transitions = ['Disabled']; - -_Enabled.prototype.onSearchDropdown = function (controller) { - - $(document).unbind("keydown", controller.scope.onKeyDown); - controller.changeState(Disabled); - -}; -_Enabled.prototype.onSearchDropdown.transitions = ['Disabled']; diff --git a/awx/ui/client/src/network-ui/link.directive.js b/awx/ui/client/src/network-ui/link.directive.js deleted file mode 100644 index 446f56b14f05..000000000000 --- a/awx/ui/client/src/network-ui/link.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/link.partial.svg'); - -function link () { - return { restrict: 'A', templateUrl}; -} -exports.link = link; diff --git a/awx/ui/client/src/network-ui/link.partial.svg b/awx/ui/client/src/network-ui/link.partial.svg deleted file mode 100644 index bd9f9f3641ef..000000000000 --- a/awx/ui/client/src/network-ui/link.partial.svg +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - {{link.name}} -{{link.name}}{{link.edit_label?'_':''}} - - - - {{link.from_interface.name}} -{{link.from_interface.name}}{{link.from_interface.edit_label ?'_':''}} - - - - {{link.to_interface.name}} -{{link.to_interface.name}}{{link.to_interface.edit_label?'_':''}} - - - - - - - - diff --git a/awx/ui/client/src/network-ui/messages.js b/awx/ui/client/src/network-ui/messages.js deleted file mode 100644 index 88950cee742e..000000000000 --- a/awx/ui/client/src/network-ui/messages.js +++ /dev/null @@ -1,240 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - - -function serialize(message) { - return JSON.stringify([message.constructor.name, message]); -} -exports.serialize = serialize; - -function DeviceMove(sender, id, x, y, previous_x, previous_y) { - this.msg_type = "DeviceMove"; - this.sender = sender; - this.id = id; - this.x = x; - this.y = y; - this.previous_x = previous_x; - this.previous_y = previous_y; -} -exports.DeviceMove = DeviceMove; - -function DeviceCreate(sender, id, x, y, name, type, host_id) { - this.msg_type = "DeviceCreate"; - this.sender = sender; - this.id = id; - this.x = x; - this.y = y; - this.name = name; - this.type = type; - this.host_id = host_id; -} -exports.DeviceCreate = DeviceCreate; - -function DeviceDestroy(sender, id, previous_x, previous_y, previous_name, previous_type, previous_host_id) { - this.msg_type = "DeviceDestroy"; - this.sender = sender; - this.id = id; - this.previous_x = previous_x; - this.previous_y = previous_y; - this.previous_name = previous_name; - this.previous_type = previous_type; - this.previous_host_id = previous_host_id; -} -exports.DeviceDestroy = DeviceDestroy; - -function DeviceSelected(sender, id) { - this.msg_type = "DeviceSelected"; - this.sender = sender; - this.id = id; -} -exports.DeviceSelected = DeviceSelected; - -function DeviceUnSelected(sender, id) { - this.msg_type = "DeviceUnSelected"; - this.sender = sender; - this.id = id; -} -exports.DeviceUnSelected = DeviceUnSelected; - -function InterfaceCreate(sender, device_id, id, name) { - this.msg_type = "InterfaceCreate"; - this.sender = sender; - this.device_id = device_id; - this.id = id; - this.name = name; -} -exports.InterfaceCreate = InterfaceCreate; - -function LinkCreate(sender, id, from_device_id, to_device_id, from_interface_id, to_interface_id) { - this.msg_type = "LinkCreate"; - this.id = id; - this.sender = sender; - this.name = ''; - this.from_device_id = from_device_id; - this.to_device_id = to_device_id; - this.from_interface_id = from_interface_id; - this.to_interface_id = to_interface_id; -} -exports.LinkCreate = LinkCreate; - -function LinkDestroy(sender, id, from_device_id, to_device_id, from_interface_id, to_interface_id, name) { - this.msg_type = "LinkDestroy"; - this.id = id; - this.sender = sender; - this.name = name; - this.from_device_id = from_device_id; - this.to_device_id = to_device_id; - this.from_interface_id = from_interface_id; - this.to_interface_id = to_interface_id; -} -exports.LinkDestroy = LinkDestroy; - -function LinkSelected(sender, id) { - this.msg_type = "LinkSelected"; - this.sender = sender; - this.id = id; -} -exports.LinkSelected = LinkSelected; - -function LinkUnSelected(sender, id) { - this.msg_type = "LinkUnSelected"; - this.sender = sender; - this.id = id; -} -exports.LinkUnSelected = LinkUnSelected; - -function MultipleMessage(sender, messages) { - this.msg_type = "MultipleMessage"; - this.sender = sender; - this.messages = messages; -} -exports.MultipleMessage = MultipleMessage; - - -function MouseEvent(sender, x, y, type, trace_id) { - this.msg_type = "MouseEvent"; - this.sender = sender; - this.x = x; - this.y = y; - this.type = type; - this.trace_id = trace_id; -} -exports.MouseEvent = MouseEvent; - -function MouseWheelEvent(sender, delta, deltaX, deltaY, type, metaKey, trace_id) { - this.msg_type = "MouseWheelEvent"; - this.sender = sender; - this.delta = delta; - this.deltaX = deltaX; - this.deltaY = deltaY; - this.type = type; - this.originalEvent = {metaKey: metaKey}; - this.trace_id = trace_id; -} -exports.MouseWheelEvent = MouseWheelEvent; - -function KeyEvent(sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey, trace_id) { - this.msg_type = "KeyEvent"; - this.sender = sender; - this.key = key; - this.keyCode = keyCode; - this.type = type; - this.altKey = altKey; - this.shiftKey = shiftKey; - this.ctrlKey = ctrlKey; - this.metaKey = metaKey; - this.trace_id = trace_id; -} -exports.KeyEvent = KeyEvent; - -function StartRecording(sender, trace_id) { - this.msg_type = "StartRecording"; - this.sender = sender; - this.trace_id = trace_id; -} -exports.StartRecording = StartRecording; - -function StopRecording(sender, trace_id) { - this.msg_type = "StopRecording"; - this.sender = sender; - this.trace_id = trace_id; -} -exports.StopRecording = StopRecording; - -function ViewPort(sender, scale, panX, panY, graph_width, graph_height, trace_id) { - this.msg_type = "ViewPort"; - this.sender = sender; - this.scale = scale; - this.panX = panX; - this.panY = panY; - this.graph_width = graph_width; - this.graph_height = graph_height; - this.trace_id = trace_id; -} -exports.ViewPort = ViewPort; - -function PasteDevice(device) { - this.device = device; -} -exports.PasteDevice = PasteDevice; - -function FSMTrace(order, fsm_name, from_state, to_state, recv_message_type) { - this.msg_type = 'FSMTrace'; - this.order = order; - this.sender = 0; - this.trace_id = 0; - this.fsm_name = fsm_name; - this.from_state = from_state; - this.to_state = to_state; - this.recv_message_type = recv_message_type; -} -exports.FSMTrace = FSMTrace; - -function Snapshot(sender, devices, links, inventory_toolbox, order, trace_id) { - this.msg_type = 'Snapshot'; - this.sender = 0; - this.devices = devices; - this.links = links; - this.inventory_toolbox = inventory_toolbox; - this.order = order; - this.trace_id = trace_id; -} -exports.Snapshot = Snapshot; - -function EnableTest() { - this.msg_type = "EnableTest"; -} -exports.EnableTest = EnableTest; - -function DisableTest() { - this.msg_type = "DisableTest"; -} -exports.DisableTest = DisableTest; - -function StartTest() { - this.msg_type = "StartTest"; -} -exports.StartTest = StartTest; - -function TestCompleted() { - this.msg_type = "TestCompleted"; -} -exports.TestCompleted = TestCompleted; - -function TestResult(sender, id, name, result, date, code_under_test) { - this.msg_type = "TestResult"; - this.sender = sender; - this.id = id; - this.name = name; - this.result = result; - this.date = date; - this.code_under_test = code_under_test; -} -exports.TestResult = TestResult; - -function Coverage(sender, coverage, result_id) { - this.msg_type = "Coverage"; - this.sender = sender; - this.coverage = coverage; - this.result_id = result_id; -} -exports.Coverage = Coverage; diff --git a/awx/ui/client/src/network-ui/mode.fsm.js b/awx/ui/client/src/network-ui/mode.fsm.js deleted file mode 100644 index 22cfeec656dd..000000000000 --- a/awx/ui/client/src/network-ui/mode.fsm.js +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); -var move = require('./move.fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Rack () { - this.name = 'Rack'; -} -inherits(_Rack, _State); -var Rack = new _Rack(); -exports.Rack = Rack; - - -_Start.prototype.start = function (controller) { - - controller.scope.inventory_toolbox_controller.handle_message('Disable', {}); - controller.changeState(Rack); -}; -_Start.prototype.start.transitions = ['MultiSite']; - - -_Rack.prototype.start = function (controller) { - controller.scope.current_mode = controller.state.name; - controller.scope.inventory_toolbox_controller.handle_message('Enable', {}); - controller.scope.move_controller.changeState(move.Ready); -}; diff --git a/awx/ui/client/src/network-ui/models.js b/awx/ui/client/src/network-ui/models.js deleted file mode 100644 index 2a25033ed5ab..000000000000 --- a/awx/ui/client/src/network-ui/models.js +++ /dev/null @@ -1,380 +0,0 @@ -/* Copyright (c) 2017-2018 Red Hat, Inc. */ -var fsm = require('./fsm.js'); -var button = require('./button.fsm.js'); -var util = require('./util.js'); -var animation_fsm = require('./animation.fsm.js'); - -function Device(id, name, x, y, type, host_id) { - this.id = id; - this.host_id = host_id ? host_id: 0; - this.name = name; - this.x = x; - this.y = y; - this.height = type === "host" ? 20 : 37.5; - this.width = 37.5; - this.size = 37.5; - this.type = type; - this.selected = false; - this.remote_selected = false; - this.moving = false; - this.icon = false; - this.tasks = []; - this.shape = type === "router" ? "circular" : "rectangular"; - this.interface_seq = util.natural_numbers(0); - this.interfaces = []; - this.interfaces_by_name = {}; - this.variables = {}; -} -exports.Device = Device; - -Device.prototype.toJSON = function () { - return {id: this.id, - name: this.name, - x: this.x, - y: this.y, - type: this.type, - interfaces: this.interfaces.map(function (x) { - return x.toJSON(); - }), - variables: this.variables - }; -}; - -Device.prototype.is_selected = function (x, y) { - - return (x > this.x - this.width && - x < this.x + this.width && - y > this.y - this.height && - y < this.y + this.height); - -}; - -Device.prototype.describeArc = util.describeArc; - - -function Interface(id, name) { - this.id = id; - this.name = name; - this.link = null; - this.device = null; - this.edit_label = false; - this.dot_x = null; - this.dot_y = null; -} -exports.Interface = Interface; - -Interface.prototype.toJSON = function () { - - return {id: this.id, - name: this.name}; -}; - -Interface.prototype.is_selected = function (x, y) { - - if (this.link === null || this.device === null) { - return false; - } - - var d = Math.sqrt(Math.pow(x - this.device.x, 2) + Math.pow(y - this.device.y, 2)); - return this.link.is_selected(x, y) && (d < this.dot_d + 30); -}; - -Interface.prototype.dot_distance = function () { - this.dot_d = Math.sqrt(Math.pow(this.device.x - this.dot_x, 2) + Math.pow(this.device.y - this.dot_y, 2)); -}; - -Interface.prototype.dot = function () { - if (this.link === null || this.device === null) { - return; - } - if (this.link.to_device === null || this.link.from_device === null) { - return; - } - var p; - if (this.device.shape === "circular") { - - var theta = this.link.slope_rads(); - if (this.link.from_interface === this) { - theta = theta + Math.PI; - } - p = {x: this.device.x - this.device.size * Math.cos(theta), - y: this.device.y - this.device.size * Math.sin(theta)}; - this.dot_x = p.x; - this.dot_y = p.y; - this.dot_distance(); - return; - } - - var x1; - var y1; - var x2; - var y2; - var x3; - var y3; - var x4; - var y4; - var param1; - var param2; - - x3 = this.link.to_device.x; - y3 = this.link.to_device.y; - x4 = this.link.from_device.x; - y4 = this.link.from_device.y; - - x1 = this.device.x - this.device.width; - y1 = this.device.y - this.device.height; - x2 = this.device.x + this.device.width; - y2 = this.device.y - this.device.height; - - p = util.intersection(x3, y3, x4, y4, x1, y1, x2, y2); - param1 = util.pCase(p.x, p.y, x1, y1, x2, y2); - param2 = util.pCase(p.x, p.y, x3, y3, x4, y4); - if (param1 >= 0 && param1 <= 1 && param2 >= 0 && param2 <= 1) { - this.dot_x = p.x; - this.dot_y = p.y; - this.dot_distance(); - return; - } - - - x1 = this.device.x - this.device.width; - y1 = this.device.y + this.device.height; - x2 = this.device.x + this.device.width; - y2 = this.device.y + this.device.height; - - p = util.intersection(x3, y3, x4, y4, x1, y1, x2, y2); - param1 = util.pCase(p.x, p.y, x1, y1, x2, y2); - param2 = util.pCase(p.x, p.y, x3, y3, x4, y4); - if (param1 >= 0 && param1 <= 1 && param2 >= 0 && param2 <= 1) { - this.dot_x = p.x; - this.dot_y = p.y; - this.dot_distance(); - return; - } - - x1 = this.device.x + this.device.width; - y1 = this.device.y - this.device.height; - x2 = this.device.x + this.device.width; - y2 = this.device.y + this.device.height; - - p = util.intersection(x3, y3, x4, y4, x1, y1, x2, y2); - param1 = util.pCase(p.x, p.y, x1, y1, x2, y2); - param2 = util.pCase(p.x, p.y, x3, y3, x4, y4); - if (param1 >= 0 && param1 <= 1 && param2 >= 0 && param2 <= 1) { - this.dot_x = p.x; - this.dot_y = p.y; - this.dot_distance(); - return; - } - - x1 = this.device.x - this.device.width; - y1 = this.device.y - this.device.height; - x2 = this.device.x - this.device.width; - y2 = this.device.y + this.device.height; - - p = util.intersection(x3, y3, x4, y4, x1, y1, x2, y2); - param1 = util.pCase(p.x, p.y, x1, y1, x2, y2); - param2 = util.pCase(p.x, p.y, x3, y3, x4, y4); - if (param1 >= 0 && param1 <= 1 && param2 >= 0 && param2 <= 1) { - this.dot_x = p.x; - this.dot_y = p.y; - this.dot_distance(); - return; - } - -}; - -function Link(id, from_device, to_device, from_interface, to_interface) { - this.id = id; - this.from_device = from_device; - this.to_device = to_device; - this.from_interface = from_interface; - this.to_interface = to_interface; - this.selected = false; - this.remote_selected = false; - this.status = null; - this.edit_label = false; - this.name = ""; -} -exports.Link = Link; - -Link.prototype.toJSON = function () { - - return {from_device_id: this.from_device.id, - to_device_id: this.to_device.id, - from_interface_id: this.from_interface.id, - to_interface_id: this.to_interface.id, - name: this.name}; -}; - -Link.prototype.is_selected = function (x, y) { - // Is the distance to the mouse location less than 25 if on the label side - // or 5 on the other from the shortest line to the link? - - if (this.to_device === null) { - return false; - } - var d = util.pDistance(x, - y, - this.from_device.x, - this.from_device.y, - this.to_device.x, - this.to_device.y); - if (util.cross_z_pos(x, - y, - this.from_device.x, - this.from_device.y, - this.to_device.x, - this.to_device.y)) { - return d < 10; - } else { - return d < 10; - } -}; - -Link.prototype.slope_rads = function () { - //Return the slope in degrees for this link. - var x1 = this.from_device.x; - var y1 = this.from_device.y; - var x2 = this.to_device.x; - var y2 = this.to_device.y; - return Math.atan2(y2 - y1, x2 - x1); -}; - -Link.prototype.slope = function () { - //Return the slope in degrees for this link. - var x1 = this.from_device.x; - var y1 = this.from_device.y; - var x2 = this.to_device.x; - var y2 = this.to_device.y; - return Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 180; -}; - -Link.prototype.pDistanceLine = function (x, y) { - - var x1 = this.from_device.x; - var y1 = this.from_device.y; - var x2 = this.to_device.x; - var y2 = this.to_device.y; - return util.pDistanceLine(x, y, x1, y1, x2, y2); -}; - - -Link.prototype.length = function () { - //Return the length of this link. - var x1 = this.from_device.x; - var y1 = this.from_device.y; - var x2 = this.to_device.x; - var y2 = this.to_device.y; - return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2)); -}; - -Link.prototype.plength = function (x, y) { - //Return the length of this link. - var x1 = this.from_device.x; - var y1 = this.from_device.y; - var x2 = this.to_device.x; - var y2 = this.to_device.y; - return util.pDistance(x, y, x1, y1, x2, y2); -}; - -function ContextMenu(name, x, y, width, height, callback, enabled, buttons, tracer) { - this.name = name; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.callback = callback; - this.is_pressed = false; - this.mouse_over = false; - this.enabled = false; - this.buttons = buttons; - this.fsm = new fsm.FSMController(this, "button_fsm", enabled ? button.Start : button.Disabled, tracer); -} -exports.ContextMenu = ContextMenu; - - -ContextMenu.prototype.is_selected = function (x, y) { - - return (x > this.x && - x < this.x + this.width && - y > this.y && - y < this.y + this.height); - -}; - -function ContextMenuButton(name, x, y, width, height, callback, tracer) { - this.name = name; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.callback = callback; - this.is_pressed = false; - this.mouse_over = false; - this.enabled = true; - this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); -} -exports.ContextMenuButton = ContextMenuButton; - - -ContextMenuButton.prototype.is_selected = function (x, y) { - - return (x > this.x && - x < this.x + this.width && - y > this.y && - y < this.y + this.height); - -}; - - -function ToolBox(id, name, type, x, y, width, height) { - this.id = id; - this.name = name; - this.type = type; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.items = []; - this.spacing = 200; - this.scroll_offset = 0; - this.selected_item = null; - this.enabled = true; -} -exports.ToolBox = ToolBox; - -function Test(name, event_trace, fsm_trace, pre_test_snapshot, post_test_snapshot) { - this.name = name; - this.event_trace = event_trace; - this.fsm_trace = fsm_trace; - this.pre_test_snapshot = pre_test_snapshot; - this.post_test_snapshot = post_test_snapshot; -} -exports.Test = Test; - -function TestResult(id, name, result, date, code_under_test) { - this.id = id; - this.name = name; - this.result = result; - this.date = date; - this.code_under_test = code_under_test; -} -exports.TestResult = TestResult; - -function Animation(id, steps, data, scope, tracer, callback) { - - this.id = id; - this.steps = steps; - this.active = true; - this.frame_number_seq = util.natural_numbers(-1); - this.frame_number = 0; - this.data = data; - this.data.updateZoomBoolean = data.updateZoomBoolean !== undefined ? data.updateZoomBoolean : true; - this.callback = callback; - this.scope = scope; - this.interval = null; - this.frame_delay = 17; - this.fsm = new fsm.FSMController(this, "animation_fsm", animation_fsm.Start, tracer); -} -exports.Animation = Animation; diff --git a/awx/ui/client/src/network-ui/move.fsm.js b/awx/ui/client/src/network-ui/move.fsm.js deleted file mode 100644 index 6744d8a91ed6..000000000000 --- a/awx/ui/client/src/network-ui/move.fsm.js +++ /dev/null @@ -1,397 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); -var models = require('./models.js'); -var messages = require('./messages.js'); -var util = require('./util.js'); - -function _State () { -} -inherits(_State, fsm._State); - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Disable () { - this.name = 'Disable'; -} -inherits(_Disable, _State); -var Disable = new _Disable(); -exports.Disable = Disable; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Selected2 () { - this.name = 'Selected2'; -} -inherits(_Selected2, _State); -var Selected2 = new _Selected2(); -exports.Selected2 = Selected2; - -function _Selected3 () { - this.name = 'Selected3'; -} -inherits(_Selected3, _State); -var Selected3 = new _Selected3(); -exports.Selected3 = Selected3; - -function _Move () { - this.name = 'Move'; -} -inherits(_Move, _State); -var Move = new _Move(); -exports.Move = Move; - -function _Selected1 () { - this.name = 'Selected1'; -} -inherits(_Selected1, _State); -var Selected1 = new _Selected1(); -exports.Selected1 = Selected1; - -function _Placing () { - this.name = 'Placing'; -} -inherits(_Placing, _State); -var Placing = new _Placing(); -exports.Placing = Placing; - - -function _ContextMenu () { - this.name = 'ContextMenu'; -} -inherits(_ContextMenu, _State); -var ContextMenu = new _ContextMenu(); -exports.ContextMenu = ContextMenu; - - -_State.prototype.onUnselectAll = function (controller, msg_type, $event) { - - controller.changeState(Ready); - controller.delegate_channel.send(msg_type, $event); -}; - -_Ready.prototype.onPasteDevice = function (controller, msg_type, message) { - - var scope = controller.scope; - var device = null; - var remote_device = null; - var intf = null; - var link = null; - var new_link = null; - var i = 0; - var c_messages = []; - - scope.pressedX = scope.mouseX; - scope.pressedY = scope.mouseY; - scope.pressedScaledX = scope.scaledX; - scope.pressedScaledY = scope.scaledY; - - device = new models.Device(controller.scope.device_id_seq(), - message.device.name, - scope.scaledX, - scope.scaledY, - message.device.type, - message.device.host_id); - device.variables = message.device.variables; - scope.update_links_in_vars_by_device(device.name, device.variables); - scope.devices.push(device); - scope.devices_by_name[message.device.name] = device; - c_messages.push(new messages.DeviceCreate(scope.client_id, - device.id, - device.x, - device.y, - device.name, - device.type, - device.host_id)); - for (i=0; i < message.device.interfaces.length; i++) { - intf = new models.Interface(message.device.interfaces[i].id, message.device.interfaces[i].name); - device.interfaces.push(intf); - device.interfaces_by_name[message.device.interfaces[i].name] = intf; - intf.device = device; - c_messages.push(new messages.InterfaceCreate(controller.scope.client_id, - device.id, - intf.id, - intf.name)); - } - if (scope.links_in_vars_by_device[device.name] !== undefined) { - for (i=0; i < scope.links_in_vars_by_device[device.name].length; i++) { - link = scope.links_in_vars_by_device[device.name][i]; - if (device.interfaces_by_name[link.from_interface] === undefined) { - intf = new models.Interface(device.interface_seq(), link.from_interface); - device.interfaces.push(intf); - device.interfaces_by_name[link.from_interface] = intf; - intf.device = device; - c_messages.push(new messages.InterfaceCreate(controller.scope.client_id, - device.id, - intf.id, - intf.name)); - } - if (scope.devices_by_name[link.to_device] !== undefined) { - remote_device = scope.devices_by_name[link.to_device]; - if (remote_device.interfaces_by_name[link.to_interface] === undefined) { - intf = new models.Interface(remote_device.interface_seq(), link.to_interface); - remote_device.interfaces.push(intf); - remote_device.interfaces_by_name[link.to_interface] = intf; - intf.device = remote_device; - c_messages.push(new messages.InterfaceCreate(controller.scope.client_id, - remote_device.id, - intf.id, - intf.name)); - } - } - if (scope.devices_by_name[link.to_device] === undefined) { - continue; - } - if (scope.devices_by_name[link.to_device].interfaces_by_name[link.to_interface] === undefined) { - continue; - } - new_link = new models.Link(scope.link_id_seq(), - device, - scope.devices_by_name[link.to_device], - device.interfaces_by_name[link.from_interface], - scope.devices_by_name[link.to_device].interfaces_by_name[link.to_interface]); - c_messages.push(new messages.LinkCreate(controller.scope.client_id, - new_link.id, - new_link.from_device.id, - new_link.to_device.id, - new_link.from_interface.id, - new_link.to_interface.id)); - device.interfaces_by_name[link.from_interface].link = new_link; - scope.devices_by_name[link.to_device].interfaces_by_name[link.to_interface].link = new_link; - scope.links.push(new_link); - scope.updateInterfaceDots(); - } - } - scope.selected_devices.push(device); - device.selected = true; - console.log(c_messages); - scope.$emit('awxNet-addSearchOption', device); - scope.send_control_message(new messages.MultipleMessage(controller.scope.client_id, c_messages)); - controller.changeState(Selected2); -}; -_Ready.prototype.onPasteDevice.transitions = ['Selected2']; - -_Ready.prototype.onMouseDown = function (controller, msg_type, $event) { - - var last_selected = controller.scope.select_items($event.shiftKey); - - if (last_selected.last_selected_device !== null) { - controller.changeState(Selected1); - } else if (last_selected.last_selected_link !== null) { - controller.changeState(Selected1); - } else if (last_selected.last_selected_interface !== null) { - controller.changeState(Selected1); - } else { - controller.delegate_channel.send(msg_type, $event); - } -}; -_Ready.prototype.onMouseDown.transitions = ['Selected1']; - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - - -_Selected2.prototype.onMouseDown = function (controller, msg_type, $event) { - - var last_selected = null; - - if (controller.scope.selected_devices.length === 1) { - var current_selected_device = controller.scope.selected_devices[0]; - var last_selected_device = controller.scope.select_items($event.shiftKey).last_selected_device; - if (current_selected_device === last_selected_device) { - controller.changeState(Selected3); - return; - } - } - - if (controller.scope.selected_links.length === 1) { - var current_selected_link = controller.scope.selected_links[0]; - last_selected = controller.scope.select_items($event.shiftKey); - if (current_selected_link === last_selected.last_selected_link) { - controller.changeState(Selected3); - return; - } - } - - if (controller.scope.selected_interfaces.length === 1) { - var current_selected_interface = controller.scope.selected_interfaces[0]; - last_selected = controller.scope.select_items($event.shiftKey); - if (current_selected_interface === last_selected.last_selected_interface) { - controller.changeState(Selected3); - return; - } - } - controller.scope.first_channel.send('BindDocument', {}); - controller.changeState(Ready); - controller.handle_message(msg_type, $event); -}; -_Selected2.prototype.onMouseDown.transitions = ['Ready', 'Selected3']; - -_Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { - - if ($event.keyCode === 8) { - //Delete - controller.scope.deleteDevice(); - } - - controller.delegate_channel.send(msg_type, $event); -}; -_Selected2.prototype.onKeyDown.transitions = ['Ready']; - -_Selected1.prototype.onMouseMove = function (controller) { - - controller.changeState(Move); - -}; -_Selected1.prototype.onMouseMove.transitions = ['Move']; - -_Selected1.prototype.onMouseUp = function (controller) { - - if(controller.scope.$parent.vm.rightPanelIsExpanded){ - controller.scope.onDetailsContextButton(); - } - controller.changeState(Selected2); - -}; -_Selected1.prototype.onMouseUp.transitions = ['Selected2']; - -_Selected1.prototype.onMouseDown = util.noop; - -_Move.prototype.start = function (controller) { - - var devices = controller.scope.selected_devices; - var i = 0; - var j = 0; - for (i = 0; i < devices.length; i++) { - devices[i].moving = true; - for (j = 0; j < controller.scope.devices.length; j++) { - if ((Math.pow(devices[i].x - controller.scope.devices[j].x, 2) + - Math.pow(devices[i].y - controller.scope.devices[j].y, 2)) < 160000) { - controller.scope.devices[j].moving = true; - } - } - } -}; - -_Move.prototype.end = function (controller) { - - var devices = controller.scope.devices; - var i = 0; - for (i = 0; i < devices.length; i++) { - devices[i].moving = false; - } -}; - -_Move.prototype.onMouseMove = function (controller) { - - var devices = controller.scope.selected_devices; - - var diffX = controller.scope.scaledX - controller.scope.pressedScaledX; - var diffY = controller.scope.scaledY - controller.scope.pressedScaledY; - var i = 0; - var j = 0; - var previous_x, previous_y; - for (i = 0; i < devices.length; i++) { - previous_x = devices[i].x; - previous_y = devices[i].y; - devices[i].x = devices[i].x + diffX; - devices[i].y = devices[i].y + diffY; - for (j = 0; j < devices[i].interfaces.length; j++) { - devices[i].interfaces[j].dot(); - if (devices[i].interfaces[j].link !== null) { - devices[i].interfaces[j].link.to_interface.dot(); - devices[i].interfaces[j].link.from_interface.dot(); - } - } - controller.scope.send_control_message(new messages.DeviceMove(controller.scope.client_id, - devices[i].id, - devices[i].x, - devices[i].y, - previous_x, - previous_y)); - } - controller.scope.pressedScaledX = controller.scope.scaledX; - controller.scope.pressedScaledY = controller.scope.scaledY; - -}; - -_Move.prototype.onMouseUp = function (controller, msg_type, $event) { - - controller.changeState(Selected1); - controller.handle_message(msg_type, $event); -}; -_Move.prototype.onMouseUp.transitions = ['Selected1']; - -_Move.prototype.onMouseDown = function (controller) { - - controller.changeState(Selected1); -}; -_Move.prototype.onMouseDown.transitions = ['Selected1']; - -_Selected3.prototype.onMouseUp = function (controller, msg_type, $event) { - let context_menu = controller.scope.context_menus[0]; - context_menu.enabled = true; - context_menu.x = $event.x; - context_menu.y = $event.y; - context_menu.buttons.forEach(function(button, index){ - button.x = $event.x; - let menuPaddingTop = 5; - button.y = $event.y + menuPaddingTop + (button.height * index); - }); - - controller.changeState(ContextMenu); -}; -_Selected3.prototype.onMouseUp.transitions = ['ContextMenu']; - -_Selected3.prototype.onMouseMove = function (controller) { - controller.changeState(Move); -}; -_Selected3.prototype.onMouseMove.transitions = ['Move']; - -_Placing.prototype.onMouseDown = function (controller) { - - controller.changeState(Selected1); - -}; -_Placing.prototype.onMouseDown.transitions = ['Selected1']; - -_Placing.prototype.onMouseMove = function (controller) { - - controller.changeState(Move); - -}; -_Placing.prototype.onMouseMove.transitions = ['Move']; - - -_ContextMenu.prototype.end = function (controller) { - - controller.scope.removeContextMenu(); -}; - -_ContextMenu.prototype.onMouseDown = function (controller) { - - controller.changeState(Selected2); - -}; -_ContextMenu.prototype.onMouseDown.transitions = ['Selected2']; - -_ContextMenu.prototype.onDetailsPanel = function (controller, msg_type, $event) { - - controller.changeState(Selected2); - controller.handle_message(msg_type, $event); -}; -_ContextMenu.prototype.onDetailsPanel.transitions = ['Selected2']; diff --git a/awx/ui/client/src/network-ui/move.readonly.fsm.js b/awx/ui/client/src/network-ui/move.readonly.fsm.js deleted file mode 100644 index aa0e1958e049..000000000000 --- a/awx/ui/client/src/network-ui/move.readonly.fsm.js +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); -var util = require('./util.js'); - -function _State () { -} -inherits(_State, fsm._State); - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Disable () { - this.name = 'Disable'; -} -inherits(_Disable, _State); -var Disable = new _Disable(); -exports.Disable = Disable; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Selected2 () { - this.name = 'Selected2'; -} -inherits(_Selected2, _State); -var Selected2 = new _Selected2(); -exports.Selected2 = Selected2; - -function _Selected3 () { - this.name = 'Selected3'; -} -inherits(_Selected3, _State); -var Selected3 = new _Selected3(); -exports.Selected3 = Selected3; - -function _Selected1 () { - this.name = 'Selected1'; -} -inherits(_Selected1, _State); -var Selected1 = new _Selected1(); -exports.Selected1 = Selected1; - -function _ContextMenu () { - this.name = 'ContextMenu'; -} -inherits(_ContextMenu, _State); -var ContextMenu = new _ContextMenu(); -exports.ContextMenu = ContextMenu; - - -_State.prototype.onUnselectAll = function (controller, msg_type, $event) { - - controller.changeState(Ready); - controller.delegate_channel.send(msg_type, $event); -}; - - -_Ready.prototype.onMouseDown = function (controller, msg_type, $event) { - - var last_selected = controller.scope.select_items($event.shiftKey); - - if (last_selected.last_selected_device !== null) { - controller.changeState(Selected1); - } else if (last_selected.last_selected_link !== null) { - controller.changeState(Selected1); - } else if (last_selected.last_selected_interface !== null) { - controller.changeState(Selected1); - } else { - controller.delegate_channel.send(msg_type, $event); - } -}; -_Ready.prototype.onMouseDown.transitions = ['Selected1']; - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - - -_Selected2.prototype.onMouseDown = function (controller, msg_type, $event) { - - var last_selected = null; - - if (controller.scope.selected_devices.length === 1) { - var current_selected_device = controller.scope.selected_devices[0]; - var last_selected_device = controller.scope.select_items($event.shiftKey).last_selected_device; - if (current_selected_device === last_selected_device) { - controller.changeState(Selected3); - return; - } - } - - if (controller.scope.selected_links.length === 1) { - var current_selected_link = controller.scope.selected_links[0]; - last_selected = controller.scope.select_items($event.shiftKey); - if (current_selected_link === last_selected.last_selected_link) { - controller.changeState(Selected3); - return; - } - } - - if (controller.scope.selected_interfaces.length === 1) { - var current_selected_interface = controller.scope.selected_interfaces[0]; - last_selected = controller.scope.select_items($event.shiftKey); - if (current_selected_interface === last_selected.last_selected_interface) { - controller.changeState(Selected3); - return; - } - } - controller.scope.first_channel.send('BindDocument', {}); - controller.changeState(Ready); - controller.handle_message(msg_type, $event); -}; -_Selected2.prototype.onMouseDown.transitions = ['Ready', 'Selected3']; - - -_Selected1.prototype.onMouseUp = function (controller) { - - if(controller.scope.$parent.vm.rightPanelIsExpanded){ - controller.scope.onDetailsContextButton(); - } - controller.changeState(Selected2); - -}; -_Selected1.prototype.onMouseUp.transitions = ['Selected2']; - -_Selected1.prototype.onMouseDown = util.noop; - -_Selected3.prototype.onMouseUp = function (controller, msg_type, $event) { - let context_menu = controller.scope.context_menus[0]; - context_menu.enabled = true; - context_menu.x = $event.x; - context_menu.y = $event.y; - context_menu.buttons.forEach(function(button, index){ - button.x = $event.x; - let menuPaddingTop = 5; - button.y = $event.y + menuPaddingTop + (button.height * index); - }); - - controller.changeState(ContextMenu); -}; -_Selected3.prototype.onMouseUp.transitions = ['ContextMenu']; - -_Selected3.prototype.onMouseMove = function (controller) { - controller.changeState(Selected2); -}; -_Selected3.prototype.onMouseMove.transitions = ['Selected2']; - -_ContextMenu.prototype.end = function (controller) { - - controller.scope.removeContextMenu(); -}; - -_ContextMenu.prototype.onMouseDown = function (controller) { - - controller.changeState(Selected2); - -}; -_ContextMenu.prototype.onMouseDown.transitions = ['Selected2']; - -_ContextMenu.prototype.onDetailsPanel = function (controller, msg_type, $event) { - - controller.changeState(Selected2); - controller.handle_message(msg_type, $event); -}; -_ContextMenu.prototype.onDetailsPanel.transitions = ['Selected2']; diff --git a/awx/ui/client/src/network-ui/network-details/details.block.less b/awx/ui/client/src/network-ui/network-details/details.block.less deleted file mode 100644 index 802e67fd3e75..000000000000 --- a/awx/ui/client/src/network-ui/network-details/details.block.less +++ /dev/null @@ -1,29 +0,0 @@ -.Networking-panelHeader { - display: flex; - height: 30px; - width:100%; -} - -.Networking-panelHeaderText { - color: @default-interface-txt; - flex: 1 0 auto; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - text-transform: uppercase; -} - -.Networking-noItems{ - margin-top: 0px; -} - -.Networking-form{ - font-weight: normal; -} - -.Networking-saveConfirmation{ - font-weight: normal; - color: @default-succ; - text-align: right; - margin-top:15px; -} diff --git a/awx/ui/client/src/network-ui/network-details/details.controller.js b/awx/ui/client/src/network-ui/network-details/details.controller.js deleted file mode 100644 index ff30b97e9f48..000000000000 --- a/awx/ui/client/src/network-ui/network-details/details.controller.js +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$scope', 'HostsService', - function($scope, HostsService){ - - function codemirror () { - return { - init:{} - }; - } - $scope.codeMirror = new codemirror(); - $scope.formCancel = function(){ - $scope.$parent.$broadcast('awxNet-closeDetailsPanel'); - }; - - $scope.formSave = function(){ - var host = { - id: $scope.item.id, - variables: $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables, - name: $scope.item.name, - description: $scope.item.description, - enabled: $scope.item.enabled - }; - HostsService.put(host).then(function(response){ - $scope.saveConfirmed = true; - if(_.has(response, "data")){ - $scope.$parent.$broadcast('awxNet-hostUpdateSaved', response.data); - } - setTimeout(function(){ - $scope.saveConfirmed = false; - }, 3000); - }); - }; - - $scope.$parent.$on('awxNet-showDetails', (e, data, canAdd) => { - if (!_.has(data, 'host_id')) { - $scope.item = data; - $scope.canAdd = canAdd; - } else { - $scope.item = data; - } - if ($scope.codeMirror.init) { - $scope.codeMirror.init($scope.item.variables); - } - }); - }]; diff --git a/awx/ui/client/src/network-ui/network-details/details.directive.js b/awx/ui/client/src/network-ui/network-details/details.directive.js deleted file mode 100644 index d05f36439071..000000000000 --- a/awx/ui/client/src/network-ui/network-details/details.directive.js +++ /dev/null @@ -1,22 +0,0 @@ -/************************************************* - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import detailsController from './details.controller'; - -const templateUrl = require('~network-ui/network-details/details.partial.html'); - -export default [ - function() { - return { - scope:{ - item: "=", - canAdd: '@' - }, - templateUrl, - controller: detailsController, - restrict: 'E', - }; -}]; diff --git a/awx/ui/client/src/network-ui/network-details/details.partial.html b/awx/ui/client/src/network-ui/network-details/details.partial.html deleted file mode 100644 index f7771e89160e..000000000000 --- a/awx/ui/client/src/network-ui/network-details/details.partial.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- DETAILS | {{item.name}} -
-
- -
- {{item.type}} DETAILS NOT AVAILABLE -
- -
-
-
- -
- -
Please enter a value.
-
-
-
-
- -
- -
-
-
-
- - -
-
-
- -
-
- Save Complete -
-
diff --git a/awx/ui/client/src/network-ui/network-details/main.js b/awx/ui/client/src/network-ui/network-details/main.js deleted file mode 100644 index ffa06f41e404..000000000000 --- a/awx/ui/client/src/network-ui/network-details/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import awxNetDetailsPanel from './details.directive'; - -export default - angular.module('networkDetailsDirective', []) - .directive('awxNetDetailsPanel', awxNetDetailsPanel); diff --git a/awx/ui/client/src/network-ui/network-nav/main.js b/awx/ui/client/src/network-ui/network-nav/main.js deleted file mode 100644 index 666130a0afc4..000000000000 --- a/awx/ui/client/src/network-ui/network-nav/main.js +++ /dev/null @@ -1,56 +0,0 @@ -import NetworkingController from './network.nav.controller'; -import NetworkingStrings from './network.nav.strings'; - -const MODULE_NAME = 'at.features.networking'; - -const networkNavTemplate = require('~network-ui/network-nav/network.nav.view.html'); - -function NetworkingResolve ($stateParams, resourceData) { - const resolve = { - inventory: { - id: $stateParams.inventory_id, - name: $stateParams.inventory_name - }, - canEdit: resourceData.data.summary_fields.user_capabilities.edit - }; - if (!resolve.inventory.name) { - resolve.inventory.name = resourceData.data.name; - } - return resolve; -} - -NetworkingResolve.$inject = [ - '$stateParams', - 'resourceData' -]; -function NetworkingRun ($stateExtender, strings) { - $stateExtender.addState({ - name: 'inventories.edit.networking', - route: '/networking', - ncyBreadcrumb: { - label: strings.get('state.BREADCRUMB_LABEL') - }, - views: { - 'networking@': { - templateUrl: networkNavTemplate, - controller: NetworkingController, - controllerAs: 'vm' - } - }, - resolve: { - resolvedModels: NetworkingResolve - } - }); -} - -NetworkingRun.$inject = [ - '$stateExtender', - 'NetworkingStrings' -]; - -angular - .module(MODULE_NAME, []) - .service('NetworkingStrings', NetworkingStrings) - .run(NetworkingRun); - -export default MODULE_NAME; diff --git a/awx/ui/client/src/network-ui/network-nav/network.nav.block.less b/awx/ui/client/src/network-ui/network-nav/network.nav.block.less deleted file mode 100644 index 552c0151bc88..000000000000 --- a/awx/ui/client/src/network-ui/network-nav/network.nav.block.less +++ /dev/null @@ -1,205 +0,0 @@ -.Networking-shell{ - display:flex; - flex-direction: column; - width:100%; - align-items: flex-end; - position:absolute; - z-index: 1100; -} - -.Networking-top{ - width:100%; -} - -.Networking-header{ - border-top: 1px solid @at-color-panel-border; - border-bottom: 1px solid @at-color-panel-border; - display:flex; - height: 40px; - width:100%; - background-color: @default-bg; -} - -.Networking-headerTitle{ - color: @default-interface-txt; - flex: 1 0 auto; - font-size: 14px; - font-weight: bold; - padding-left: 20px; - align-items: center; - display: flex; -} - -.Netowrking-headerActions{ - align-items: center; - display: flex; - flex: 1 0 auto; - justify-content: flex-end; - flex-wrap: wrap; - max-width: 100%; -} - -.Networking-headerActionItem{ - justify-content: flex-end; - display: flex; - padding-right: 20px; - font-size: 20px; -} - -.Networking-toolbarIcon{ - font-size: 16px; - height: 30px; - min-width: 30px; - color: @default-icon; - background-color: inherit; - border: none; - border-radius: 5px; - margin-left: 5px; -} - -.Networking-toolbarIcon:hover{ - background-color:@default-link; - color: @default-bg; -} - -.Networking-toolbarIcon--selected{ - background-color:@default-link; - color: @default-bg; - border-bottom-right-radius: 0px; - border-bottom-left-radius: 0px; -} - -.Networking-canvasPanel{ - width:100% -} - -.Networking-detailPanel{ - border-left: 1px solid @at-color-panel-border; - border-bottom: 1px solid @at-color-panel-border; - width:400px; - height: calc(~"100vh - 115px"); - padding: 20px; - color: @default-interface-txt; - font-size: 14px; - font-weight: bold; - background-color: @default-bg; - position: absolute; - top:115px; - right:0px; -} - -.Networking-toolbar{ - min-height: 40px; - width:100%; - background-color: @ebgrey; - display:flex; - flex: 1 0 auto; - justify-content: space-between; - flex-wrap: wrap; - align-items: center; - border-bottom: 1px solid @at-color-panel-border; -} - -.Networking-toolbarLeftSide{ - display: flex; - flex-wrap: wrap; - min-width: 400px; - padding-left: 20px; - height: 40px; - align-items: center; -} - -.Networking-toolbarRightSide{ - align-items: center; - flex-wrap: wrap; - display: flex; - min-width: 500px; - padding-right: 20px; - height: 40px; - justify-content: flex-end; -} - -.Networking-actionsDropDownContainer{ - height: 30px; - flex: 1 0 auto; - display: flex; - margin-top:-5px; - margin-left: -2px; -} - -.Networking-searchBarContainer{ - height: 30px; - display: flex; - margin-top:-5px; - margin-left: 5px; -} - -.Networking-dropDown{ - left:-2px!important; - z-index: 1101; -} - -.Networking-searchButton{ - padding: 4px 10px; -} - -.Networking-searchButton i{ - color:@default-icon; -} - - -.Networking-dropdownPanelTitle{ - color: @default-stdout-txt; - padding-left:15px; - min-height: 30px; - font-size: 14px; - font-weight: bold; - display: flex; - align-items: center; -} - -.Networking-keyContainer{ - display: inline-block; - position: relative; -} - -.Networking-keyDropDownPanel{ - width: 180px; - padding: 10px 0px 10px 0px; - border: 1px solid @btn-bord; - background-color: white; - position: absolute; - right:0px; - z-index: 100; -} - -.Networking-keyPanelOption{ - color: @default-stdout-txt; - padding-left:15px; - min-height: 30px; - font-size: 12px; - display:flex; - align-items: center; -} - -.Networking-keySymbol{ - background-color: @default-icon; - color: white; - border-radius: 50%; - width: 20px; - height: 20px; - font-size: 14px; - display: flex; - justify-content: center; - align-items: center; -} - -.Networking-keySymbolLabel{ - font-size: 12px; - padding-left: 15px; - color: @default-stdout-txt -} - -.Networking-toolboxPanelToolbarIcon--selected{ - border-radius: 5px; -} diff --git a/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js b/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js deleted file mode 100644 index 820ed7e37da3..000000000000 --- a/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js +++ /dev/null @@ -1,122 +0,0 @@ -/* eslint-disable */ -function NetworkingController (models, $state, $scope, strings) { - const vm = this || {}; - - const { - inventory - } = models; - - vm.strings = strings; - vm.panelTitle = `${strings.get('state.BREADCRUMB_LABEL')} | ${inventory.name}`; - vm.hostDetail = {}; - vm.canEdit = models.canEdit; - vm.rightPanelIsExpanded = false; - vm.leftPanelIsExpanded = true; - vm.keyPanelExpanded = false; - vm.groups = []; - $scope.devices = []; - vm.close = () => { - $scope.$broadcast('awxNet-closeNetworkUI'); - $state.go('inventories'); - }; - - vm.key = () => { - vm.keyPanelExpanded = !vm.keyPanelExpanded; - }; - - vm.hideToolbox = () => { - vm.leftPanelIsExpanded = !vm.leftPanelIsExpanded; - $scope.$broadcast('awxNet-hideToolbox', vm.leftPanelIsExpanded); - }; - - $scope.$on('awxNet-instatiateSelect', (e, devices) => { - for(var i = 0; i < devices.length; i++){ - let device = devices[i]; - $scope.devices.push({ - value: device.id, - text: device.name, - label: device.name, - id: device.id, - type: device.type - }); - } - - $("#networking-search").select2({ - width:'400px', - containerCssClass: 'Form-dropDown', - placeholder: 'SEARCH' - }); - $("#networking-actionsDropdown").select2({ - width:'400px', - containerCssClass: 'Form-dropDown', - minimumResultsForSearch: -1, - placeholder: 'ACTIONS' - }); - }); - - $scope.$on('awxNet-addSearchOption', (e, device) => { - $scope.devices.push({ - value: device.id, - text: device.name, - label: device.name, - id: device.id, - type: device.type - }); - }); - - $scope.$on('awxNet-editSearchOption', (e, device) => { - for(var i = 0; i < $scope.devices.length; i++){ - if(device.id === $scope.devices[i].id){ - $scope.devices[i].text = device.name; - $scope.devices[i].label = device.name; - } - } - }); - - $scope.$on('awxNet-removeSearchOption', (e, device) => { - for (var i = 0; i < $scope.devices.length; i++) { - if ($scope.devices[i].id === device.id) { - $scope.devices.splice(i, 1); - } - } - }); - - //Handlers for actions drop down - $('#networking-actionsDropdown').on('select2:select', (e) => { - $scope.$broadcast('awxNet-toolbarButtonEvent', e.params.data.title); - }); - - $('#networking-actionsDropdown').on('select2:open', () => { - $('.select2-dropdown').addClass('Networking-dropDown'); - }); - - // Handlers for search dropdown - $('#networking-search').on('select2:select', () => { - $scope.$broadcast('awxNet-search', $scope.device); - }); - - $('#networking-search').on('select2:open', () => { - $('.select2-dropdown').addClass('Networking-dropDown'); - $scope.$broadcast('awxNet-SearchDropdown'); - }); - - $('#networking-search').on('select2:close', () => { - setTimeout(function() { - $('.select2-container-active').removeClass('select2-container-active'); - $(':focus').blur(); - }, 1); - $scope.$broadcast('awxNet-SearchDropdownClose'); - }); - -} - -NetworkingController.$inject = [ - 'resolvedModels', - '$state', - '$scope', - 'NetworkingStrings', - 'CreateSelect2' -]; - -export default NetworkingController; -/* eslint-disable */ diff --git a/awx/ui/client/src/network-ui/network-nav/network.nav.strings.js b/awx/ui/client/src/network-ui/network-nav/network.nav.strings.js deleted file mode 100644 index 4aa4efca5eae..000000000000 --- a/awx/ui/client/src/network-ui/network-nav/network.nav.strings.js +++ /dev/null @@ -1,19 +0,0 @@ -function NetworkingStrings (BaseString) { - BaseString.call(this, 'networking'); - - const { t } = this; - const ns = this.networking; - - ns.state = { - BREADCRUMB_LABEL: t.s('INVENTORIES'), - }; - - ns.actions = { - EXPAND_PANEL: t.s('Expand Panel'), - COLLAPSE_PANEL: t.s('Collapse Panel') - }; -} - -NetworkingStrings.$inject = ['BaseStringService']; - -export default NetworkingStrings; diff --git a/awx/ui/client/src/network-ui/network-nav/network.nav.view.html b/awx/ui/client/src/network-ui/network-nav/network.nav.view.html deleted file mode 100644 index 1e29d9a083b1..000000000000 --- a/awx/ui/client/src/network-ui/network-nav/network.nav.view.html +++ /dev/null @@ -1,99 +0,0 @@ -
-
-
-
{{vm.panelTitle}}
-
-
- -
-
-
-
-
-
- -
-
-
-
- -
-
- -
-
- KEY -
-
-
d
-
DEBUG MODE
-
-
-
p
-
HIDE CURSOR
-
-
-
b
-
HIDE BUTTONS
-
-
-
i
-
HIDE INTERFACES
-
-
-
0
-
RESET ZOOM
-
-
-
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
- diff --git a/awx/ui/client/src/network-ui/network.ui.app.js b/awx/ui/client/src/network-ui/network.ui.app.js deleted file mode 100644 index 7fb414950d50..000000000000 --- a/awx/ui/client/src/network-ui/network.ui.app.js +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -import atFeaturesNetworking from './network-nav/main'; -import networkDetailsDirective from './network-details/main'; -import networkZoomWidget from './zoom-widget/main'; - -//console.log = function () { }; -var NetworkUIController = require('./network.ui.controller.js'); -var cursor = require('./cursor.directive.js'); -var router = require('./router.directive.js'); -var switchd = require('./switch.directive.js'); -var host = require('./host.directive.js'); -var link = require('./link.directive.js'); -var contextMenu = require('./context.menu.directive.js'); -var contextMenuButton = require('./context.menu.button.directive.js'); -var defaultd = require('./default.directive.js'); -var quadrants = require('./quadrants.directive.js'); -var inventoryToolbox = require('./inventory.toolbox.directive.js'); -var debug = require('./debug.directive.js'); -var test_results = require('./test_results.directive.js'); -var awxNetworkUI = require('./network.ui.directive.js'); - -export default - angular.module('networkUI', [ - 'monospaced.mousewheel', - atFeaturesNetworking, - networkDetailsDirective.name, - networkZoomWidget.name - ]) - .controller('NetworkUIController', NetworkUIController.NetworkUIController) - .directive('awxNetCursor', cursor.cursor) - .directive('awxNetDebug', debug.debug) - .directive('awxNetRouter', router.router) - .directive('awxNetSwitch', switchd.switchd) - .directive('awxNetHost', host.host) - .directive('awxNetLink', link.link) - .directive('awxNetContextMenu', contextMenu.contextMenu) - .directive('awxNetContextMenuButton', contextMenuButton.contextMenuButton) - .directive('awxNetDefault', defaultd.defaultd) - .directive('awxNetQuadrants', quadrants.quadrants) - .directive('awxNetInventoryToolbox', inventoryToolbox.inventoryToolbox) - .directive('awxNetTestResults', test_results.test_results) - .directive('awxNetworkUi', awxNetworkUI.awxNetworkUI); diff --git a/awx/ui/client/src/network-ui/network.ui.controller.js b/awx/ui/client/src/network-ui/network.ui.controller.js deleted file mode 100644 index 7f324988c7c2..000000000000 --- a/awx/ui/client/src/network-ui/network.ui.controller.js +++ /dev/null @@ -1,1468 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var fsm = require('./fsm.js'); -var mode_fsm = require('./mode.fsm.js'); -var hotkeys = require('./hotkeys.fsm.js'); -var toolbox_fsm = require('./toolbox.fsm.js'); -var view = require('./view.fsm.js'); -var move = require('./move.fsm.js'); -var move_readonly = require('./move.readonly.fsm.js'); -var buttons = require('./buttons.fsm.js'); -var time = require('./time.fsm.js'); -var test_fsm = require('./test.fsm.js'); -var util = require('./util.js'); -var models = require('./models.js'); -var messages = require('./messages.js'); -var animations = require('./animations.js'); -var keybindings = require('./keybindings.fsm.js'); -var details_panel_fsm = require('./details.panel.fsm.js'); -var svg_crowbar = require('./vendor/svg-crowbar.js'); -var ReconnectingWebSocket = require('reconnectingwebsocket'); - -var NetworkUIController = function($scope, - $document, - $location, - $window, - $http, - $q, - $state, - $log, - ProcessErrors, - ConfigService, - rbacUiControlService) { - - window.scope = $scope; - - $scope.http = $http; - - $scope.api_token = ''; - $scope.disconnected = false; - $scope.tests_enabled = false; - - $scope.topology_id = 0; - // Create a web socket to connect to the backend server - - $scope.inventory_id = $state.params.inventory_id; - - var protocol = null; - - if ($location.protocol() === 'http') { - protocol = 'ws'; - } else if ($location.protocol() === 'https') { - protocol = 'wss'; - } - - $scope.initial_messages = []; - if (!$scope.disconnected) { - $scope.control_socket = new ReconnectingWebSocket(protocol + "://" + window.location.host + "/network_ui/topology/?inventory_id=" + $scope.inventory_id, - null, - {debug: false, reconnectInterval: 300}); - if ($scope.tests_enabled) { - $scope.test_socket = new ReconnectingWebSocket(protocol + "://" + window.location.host + "/network_ui/test?inventory_id=" + $scope.inventory_id, - null, - {debug: false, reconnectInterval: 300}); - } else { - $scope.test_socket = { - on_message: util.noop, - send: util.noop - }; - } - - } else { - $scope.control_socket = { - on_message: util.noop - }; - } - $scope.my_location = $location.protocol() + "://" + $location.host() + ':' + $location.port(); - $scope.client_id = 0; - $scope.test_client_id = 0; - $scope.onMouseDownResult = ""; - $scope.onMouseUpResult = ""; - $scope.onMouseEnterResult = ""; - $scope.onMouseLeaveResult = ""; - $scope.onMouseMoveResult = ""; - $scope.onMouseMoveResult = ""; - $scope.current_scale = 1.0; - $scope.current_mode = null; - $scope.panX = 0; - $scope.panY = 0; - $scope.mouseX = 0; - $scope.mouseY = 0; - $scope.scaledX = 0; - $scope.scaledY = 0; - $scope.pressedX = 0; - $scope.pressedY = 0; - $scope.pressedScaledX = 0; - $scope.pressedScaledY = 0; - $scope.lastPanX = 0; - $scope.lastPanY = 0; - $scope.selected_devices = []; - $scope.selected_links = []; - $scope.selected_interfaces = []; - $scope.selected_items = []; - $scope.new_link = null; - $scope.new_stream = null; - $scope.last_key = ""; - $scope.last_key_code = null; - $scope.last_event = null; - $scope.cursor = {'x':100, 'y': 100, 'hidden': true}; - - $scope.debug = {'hidden': true}; - $scope.hide_buttons = false; - $scope.hide_menus = false; - $scope.hide_links = false; - $scope.hide_interfaces = false; - $scope.graph = {'width': window.innerWidth, - 'right_column': 300, - 'height': window.innerHeight}; - $scope.MAX_ZOOM = 5; - $scope.MIN_ZOOM = 0.1; - $scope.device_id_seq = util.natural_numbers(0); - $scope.link_id_seq = util.natural_numbers(0); - $scope.message_id_seq = util.natural_numbers(0); - $scope.test_result_id_seq = util.natural_numbers(0); - $scope.animation_id_seq = util.natural_numbers(0); - $scope.overall_toolbox_collapsed = false; - $scope.time_pointer = -1; - $scope.frame = 0; - $scope.recording = false; - $scope.replay = false; - $scope.devices = []; - $scope.devices_by_name = {}; - $scope.links = []; - $scope.links_in_vars_by_device = {}; - $scope.tests = []; - $scope.current_tests = []; - $scope.current_test = null; - $scope.template_building = false; - $scope.version = null; - $scope.test_events = []; - $scope.test_results = []; - $scope.test_errors = []; - $scope.animations = []; - $scope.sequences = {}; - $scope.view_port = {'x': 0, - 'y': 0, - 'width': 0, - 'height': 0, - }; - $scope.trace_id_seq = util.natural_numbers(0); - $scope.trace_order_seq = util.natural_numbers(0); - $scope.trace_id = $scope.trace_id_seq(); - $scope.jump = {from_x: 0, - from_y: 0, - to_x: 0, - to_y: 0}; - $scope.canEdit = $scope.$parent.$resolve.resolvedModels.canEdit; - $scope.send_trace_message = function (message) { - if (!$scope.recording) { - return; - } - message.sender = $scope.test_client_id; - message.trace_id = $scope.trace_id; - message.message_id = $scope.message_id_seq(); - var data = messages.serialize(message); - if (!$scope.disconnected) { - try { - $scope.test_socket.send(data); - } - catch(err) { - $scope.initial_messages.push(message); - } - } - }; - - $scope.onKeyDown = function ($event) { - if ($scope.recording) { - $scope.send_test_message(new messages.KeyEvent($scope.test_client_id, - $event.key, - $event.keyCode, - $event.type, - $event.altKey, - $event.shiftKey, - $event.ctrlKey, - $event.metaKey, - $scope.trace_id)); - } - $scope.last_event = $event; - $scope.last_key = $event.key; - $scope.last_key_code = $event.keyCode; - $scope.first_channel.send('KeyDown', $event); - $scope.$apply(); - $event.preventDefault(); - }; - - //Define the FSMs - $scope.hotkeys_controller = new fsm.FSMController($scope, "hotkeys_fsm", hotkeys.Start, $scope); - $scope.keybindings_controller = new fsm.FSMController($scope, "keybindings_fsm", keybindings.Start, $scope); - $scope.view_controller = new fsm.FSMController($scope, "view_fsm", view.Start, $scope); - $scope.move_controller = new fsm.FSMController($scope, "move_fsm", move.Start, $scope); - $scope.move_readonly_controller = new fsm.FSMController($scope, "move_readonly_fsm", move_readonly.Start, $scope); - $scope.details_panel_controller = new fsm.FSMController($scope, "details_panel_fsm", details_panel_fsm.Start, $scope); - $scope.buttons_controller = new fsm.FSMController($scope, "buttons_fsm", buttons.Start, $scope); - $scope.time_controller = new fsm.FSMController($scope, "time_fsm", time.Start, $scope); - $scope.test_controller = new fsm.FSMController($scope, "test_fsm", test_fsm.Start, $scope); - - $scope.inventory_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); - - var toolboxTopMargin = $('.Networking-top').height(); - var toolboxTitleMargin = toolboxTopMargin + 35; - var toolboxHeight = $scope.graph.height - $('.Networking-top').height(); - - $scope.update_links_in_vars_by_device = function (device_name, variables) { - - var j = 0; - var link = null; - - if (variables.ansible_topology !== undefined) { - if (variables.ansible_topology.links !== undefined) { - for (j=0; j < variables.ansible_topology.links.length; j++) { - link = variables.ansible_topology.links[j]; - if (link.remote_device_name !== undefined && - link.remote_interface_name !== undefined && - link.name !== undefined) { - if ($scope.links_in_vars_by_device[device_name] === undefined) { - $scope.links_in_vars_by_device[device_name] = []; - } - if ($scope.links_in_vars_by_device[link.remote_device_name] === undefined) { - $scope.links_in_vars_by_device[link.remote_device_name] = []; - } - $scope.links_in_vars_by_device[device_name].push({ - from_interface: link.name, - to_interface: link.remote_interface_name, - from_device: device_name, - to_device: link.remote_device_name - }); - $scope.links_in_vars_by_device[link.remote_device_name].push({ - from_interface: link.remote_interface_name, - to_interface: link.name, - from_device: link.remote_device_name, - to_device: device_name - }); - } - } - } - } - }; - - $scope.for_each_page = function(url, callback, limit) { - - function rec(url, rec_limit) { - if (rec_limit <= 0) { - return; - } - $http.get(url) - .then(function(response) { - callback(response.data.results); - if (response.data.next) { - rec(response.data.next, rec_limit-1); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get host data: ' + status }); - }); - } - rec(url, limit); - }; - - //Inventory Toolbox Setup - $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 0, toolboxTopMargin, 200, toolboxHeight); - if (!$scope.disconnected) { - $scope.for_each_page('/api/v2/inventories/' + $scope.inventory_id + '/hosts/', - function(all_results) { - let hosts = all_results; - $log.debug(hosts.length); - for(var i = 0; i= 0; i--) { - if (devices[i].is_selected($scope.scaledX, $scope.scaledY)) { - devices[i].selected = true; - $scope.send_control_message(new messages.DeviceSelected($scope.client_id, devices[i].id)); - last_selected_device = devices[i]; - if ($scope.selected_items.indexOf($scope.devices[i]) === -1) { - $scope.selected_items.push($scope.devices[i]); - } - if ($scope.selected_devices.indexOf(devices[i]) === -1) { - $scope.selected_devices.push(devices[i]); - } - if (!multiple_selection) { - break; - } - } - } - - // Do not select interfaces if a device was selected - if (last_selected_device === null && !$scope.hide_interfaces) { - for (i = devices.length - 1; i >= 0; i--) { - for (j = devices[i].interfaces.length - 1; j >= 0; j--) { - if (devices[i].interfaces[j].is_selected($scope.scaledX, $scope.scaledY)) { - devices[i].interfaces[j].selected = true; - last_selected_interface = devices[i].interfaces[j]; - if ($scope.selected_interfaces.indexOf($scope.devices[i].interfaces[j]) === -1) { - $scope.selected_interfaces.push($scope.devices[i].interfaces[j]); - } - if ($scope.selected_items.indexOf($scope.devices[i].interfaces[j]) === -1) { - $scope.selected_items.push($scope.devices[i].interfaces[j]); - } - if (!multiple_selection) { - break; - } - } - } - } - } - - // Do not select links if a device was selected - if (last_selected_device === null && last_selected_interface === null) { - for (i = $scope.links.length - 1; i >= 0; i--) { - if ($scope.links[i].is_selected($scope.scaledX, $scope.scaledY)) { - $scope.links[i].selected = true; - $scope.send_control_message(new messages.LinkSelected($scope.client_id, $scope.links[i].id)); - last_selected_link = $scope.links[i]; - if ($scope.selected_items.indexOf($scope.links[i]) === -1) { - $scope.selected_items.push($scope.links[i]); - } - if ($scope.selected_links.indexOf($scope.links[i]) === -1) { - $scope.selected_links.push($scope.links[i]); - if (!multiple_selection) { - break; - } - } - } - } - } - - return {last_selected_device: last_selected_device, - last_selected_link: last_selected_link, - last_selected_interface: last_selected_interface, - }; - }; - - // Event Handlers - - $scope.normalize_mouse_event = function ($event) { - if ($event.pageX !== undefined) { - $event.x = $event.pageX; - } - if ($event.pageY !== undefined) { - $event.y = $event.pageY; - } - if ($event.originalEvent !== undefined) { - var originalEvent = $event.originalEvent; - if (originalEvent.wheelDelta !== undefined) { - $event.delta = $event.originalEvent.wheelDelta; - } - if (originalEvent.wheelDeltaX !== undefined) { - $event.deltaX = $event.originalEvent.wheelDeltaX; - } - if (originalEvent.wheelDeltaY !== undefined) { - $event.deltaY = $event.originalEvent.wheelDeltaY; - } - } - }; - - $scope.onMouseDown = function ($event) { - $scope.normalize_mouse_event($event); - if ($scope.recording) { - $scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id)); - } - $scope.last_event = $event; - $scope.first_channel.send('MouseDown', $event); - $scope.onMouseDownResult = getMouseEventResult($event); - $event.preventDefault(); - }; - - $scope.onMouseUp = function ($event) { - $scope.normalize_mouse_event($event); - if ($scope.recording) { - $scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id)); - } - $scope.last_event = $event; - $scope.first_channel.send('MouseUp', $event); - $scope.onMouseUpResult = getMouseEventResult($event); - $event.preventDefault(); - }; - - $scope.onMouseLeave = function ($event) { - $scope.normalize_mouse_event($event); - if ($scope.recording) { - $scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id)); - } - $scope.onMouseLeaveResult = getMouseEventResult($event); - $event.preventDefault(); - }; - - $scope.onMouseMove = function ($event) { - $scope.normalize_mouse_event($event); - if ($scope.recording) { - $scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id)); - } - //var coords = getCrossBrowserElementCoords($event); - $scope.cursor.x = $event.x; - $scope.cursor.y = $event.y; - $scope.mouseX = $event.x; - $scope.mouseY = $event.y; - $scope.updateScaledXY(); - $scope.first_channel.send('MouseMove', $event); - $scope.onMouseMoveResult = getMouseEventResult($event); - $event.preventDefault(); - }; - - $scope.onMouseOver = function ($event) { - $scope.normalize_mouse_event($event); - if ($scope.recording) { - $scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id)); - } - $scope.onMouseOverResult = getMouseEventResult($event); - $event.preventDefault(); - }; - - $scope.onMouseEnter = $scope.onMouseOver; - - $scope.onMouseWheel = function ($event) { - $scope.normalize_mouse_event($event); - var delta = $event.delta; - var deltaX = $event.deltaX; - var deltaY = $event.deltaY; - if ($scope.recording) { - $scope.send_test_message(new messages.MouseWheelEvent($scope.test_client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey, $scope.trace_id)); - } - $scope.last_event = $event; - $scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]); - $event.preventDefault(); - }; - - // Conext Menu Button Handlers - $scope.removeContextMenu = function(){ - let context_menu = $scope.context_menus[0]; - context_menu.enabled = false; - context_menu.x = -100000; - context_menu.y = -100000; - context_menu.buttons.forEach(function(button){ - button.enabled = false; - button.x = -100000; - button.y = -100000; - }); - }; - - $scope.closeDetailsPanel = function () { - $scope.first_channel.send('DetailsPanelClose', {}); - }; - - $scope.$on('awxNet-closeDetailsPanel', $scope.closeDetailsPanel); - - $scope.onDetailsContextButton = function () { - function emitCallback(item, canAdd){ - $scope.first_channel.send('DetailsPanel', {}); - $scope.removeContextMenu(); - $scope.update_toolbox_heights(); - $scope.$emit('awxNet-showDetails', item, canAdd); - } - - // show details for devices - if ($scope.selected_devices.length === 1 && $scope.selected_devices[0].host_id === 0){ - // following block is intended for devices added in the network UI but not in Tower - emitCallback($scope.selected_devices[0]); - } - - // following block is intended for devices that are saved in the API - if ($scope.selected_devices.length === 1 && $scope.selected_devices[0].host_id !== 0){ - let host_id = $scope.selected_devices[0].host_id; - let url = `/api/v2/hosts/${host_id}/`; - let hostData = $http.get(url) - .then(function(response) { - let host = response.data; - host.host_id = host.id; - return host; - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get host data: ' + status }); - }); - let canAdd = rbacUiControlService.canAdd('hosts') - .then(function(res) { - return res.canAdd; - }) - .catch(function() { - return false; - }); - Promise.all([hostData, canAdd]).then((values) => { - let item = values[0]; - let canAdd = values[1]; - emitCallback(item, canAdd); - }); - } - - // show details for interfaces - else if($scope.selected_interfaces.length === 1){ - emitCallback($scope.selected_interfaces[0]); - } - - // show details for links - else if($scope.selected_links.length === 1){ - emitCallback($scope.selected_links[0]); - } - - }; - - $scope.onDeviceDestroy = function(data) { - $scope.destroy_device(data); - }; - - $scope.destroy_device = function(data) { - - // Delete the device and any links connecting to the device. - var i = 0; - var j = 0; - var dindex = -1; - var lindex = -1; - var devices = $scope.devices.slice(); - var all_links = $scope.links.slice(); - for (i = 0; i < devices.length; i++) { - if (devices[i].id === data.id) { - dindex = $scope.devices.indexOf(devices[i]); - if (dindex !== -1) { - $scope.devices.splice(dindex, 1); - } - lindex = -1; - for (j = 0; j < all_links.length; j++) { - if (all_links[j].to_device === devices[i] || - all_links[j].from_device === devices[i]) { - lindex = $scope.links.indexOf(all_links[j]); - if (lindex !== -1) { - $scope.links.splice(lindex, 1); - } - } - } - } - } - }; - - $scope.deleteDevice = function(){ - var i = 0; - var j = 0; - var index = -1; - var devices = $scope.selected_devices; - var all_links = $scope.links.slice(); - $scope.selected_devices = []; - $scope.selected_links = []; - $scope.move_controller.changeState(move.Ready); - for (i = 0; i < devices.length; i++) { - index = $scope.devices.indexOf(devices[i]); - if (index !== -1) { - $scope.devices.splice(index, 1); - $scope.devices_by_name[devices[i].name] = undefined; - $scope.$emit('awxNet-removeSearchOption', devices[i]); - devices[i].x = 0; - devices[i].y = 0; - devices[i].selected = false; - devices[i].remote_selected = false; - devices[i].interfaces = []; - devices[i].interfaces_by_name = []; - $scope.inventory_toolbox.items.push(devices[i]); - $scope.send_control_message(new messages.DeviceDestroy($scope.client_id, - devices[i].id, - devices[i].x, - devices[i].y, - devices[i].name, - devices[i].type, - devices[i].host_id)); - } - for (j = 0; j < all_links.length; j++) { - if (all_links[j].to_device === devices[i] || - all_links[j].from_device === devices[i]) { - index = $scope.links.indexOf(all_links[j]); - if (index !== -1) { - $scope.links.splice(index, 1); - $scope.send_control_message(new messages.LinkDestroy($scope.client_id, - all_links[j].id, - all_links[j].from_device.id, - all_links[j].to_device.id, - all_links[j].from_interface.id, - all_links[j].to_interface.id, - all_links[j].name)); - - } - } - } - } - }; - - $scope.onDeleteContextMenu = function(){ - $scope.removeContextMenu(); - if($scope.selected_devices.length === 1){ - $scope.deleteDevice(); - } - }; - - $scope.$on('awxNet-hideToolbox', () => { - $scope.first_channel.send("ToggleToolbox", {}); - $scope.overall_toolbox_collapsed = !$scope.overall_toolbox_collapsed; - }); - - $scope.$on('awxNet-toolbarButtonEvent', function(e, functionName){ - $scope[`on${functionName}Button`](); - }); - - $scope.$on('awxNet-SearchDropdown', function(){ - $scope.first_channel.send('SearchDropdown', {}); - }); - - $scope.$on('awxNet-SearchDropdownClose', function(){ - $scope.first_channel.send('SearchDropdownClose', {}); - }); - - $scope.$on('awxNet-search', function(e, device){ - - var searched; - for(var i = 0; i < $scope.devices.length; i++){ - if(Number(device.id) === $scope.devices[i].id){ - searched = $scope.devices[i]; - } - } - searched.selected = true; - $scope.selected_devices.push(searched); - $scope.jump_to_animation(searched.x, searched.y, 1.0); - }); - - $scope.jump_to_animation = function(jump_to_x, jump_to_y, jump_to_scale, updateZoom) { - $scope.cancel_animations(); - var v_center = $scope.to_virtual_coordinates($scope.graph.width/2, $scope.graph.height/2); - $scope.jump.from_x = v_center.x; - $scope.jump.from_y = v_center.y; - $scope.jump.to_x = jump_to_x; - $scope.jump.to_y = jump_to_y; - var distance = util.distance(v_center.x, v_center.y, jump_to_x, jump_to_y); - var num_frames = 30 * Math.floor((1 + 4 * distance / (distance + 3000))); - var scale_animation = new models.Animation($scope.animation_id_seq(), - num_frames, - { - c: -0.1, - distance: distance, - end_height: (1.0/jump_to_scale) - 1, - current_scale: $scope.current_scale, - scope: $scope, - updateZoomBoolean: updateZoom - }, - $scope, - $scope, - animations.scale_animation); - $scope.animations.push(scale_animation); - var pan_animation = new models.Animation($scope.animation_id_seq(), - num_frames, - { - x2: jump_to_x, - y2: jump_to_y, - x1: v_center.x, - y1: v_center.y, - scope: $scope - }, - $scope, - $scope, - animations.pan_animation); - $scope.animations.push(pan_animation); - }; - - $scope.$on('awxNet-zoom', (e, zoomPercent) => { - let v_center = $scope.to_virtual_coordinates($scope.graph.width/2, $scope.graph.height/2); - let scale = Math.pow(10, (zoomPercent - 120) / 120); - $scope.jump_to_animation(v_center.x, v_center.y, scale, false); - }); - - $scope.onRecordButton = function () { - $scope.recording = ! $scope.recording; - if ($scope.recording) { - $scope.trace_id = $scope.trace_id_seq(); - $scope.send_test_message(new messages.MultipleMessage($scope.test_client_id, - [new messages.StartRecording($scope.test_client_id, $scope.trace_id), - new messages.ViewPort($scope.test_client_id, - $scope.current_scale, - $scope.panX, - $scope.panY, - $scope.graph.width, - $scope.graph.height, - $scope.trace_id), - new messages.Snapshot($scope.test_client_id, - $scope.devices, - $scope.links, - $scope.inventory_toolbox.items, - 0, - $scope.trace_id)])); - } else { - $scope.send_test_message(new messages.MultipleMessage($scope.test_client_id, - [new messages.Snapshot($scope.test_client_id, - $scope.devices, - $scope.links, - $scope.inventory_toolbox.items, - 1, - $scope.trace_id), - new messages.StopRecording($scope.test_client_id, $scope.trace_id)])); - } - }; - - $scope.onExportButton = function () { - $scope.cursor.hidden = true; - $scope.debug.hidden = true; - $scope.hide_buttons = true; - $scope.hide_menus = true; - setTimeout(function () { - svg_crowbar.svg_crowbar(); - $scope.cursor.hidden = false; - $scope.hide_buttons = false; - $scope.hide_menus = false; - $scope.$apply(); - }, 1000); - }; - - $scope.onExportYamlButton = function () { - $window.open('/network_ui/topology.yaml?topology_id=' + $scope.topology_id , '_blank'); - }; - - // Context Menu Buttons - const contextMenuButtonHeight = 26; - let contextMenuHeight = 64; - $scope.context_menu_buttons = [ - new models.ContextMenuButton("Details", 236, 231, 160, contextMenuButtonHeight, $scope.onDetailsContextButton, $scope), - new models.ContextMenuButton("Remove", 256, 231, 160, contextMenuButtonHeight, $scope.onDeleteContextMenu, $scope) - ]; - if(!$scope.canEdit){ - $scope.context_menu_buttons.pop(); - contextMenuHeight = $scope.context_menu_buttons.length * contextMenuButtonHeight + 12; - } - // Context Menus - $scope.context_menus = [ - new models.ContextMenu('HOST', 210, 200, 160, contextMenuHeight, $scope.contextMenuCallback, false, $scope.context_menu_buttons, $scope) - ]; - - $scope.onDownloadTraceButton = function () { - window.open("/network_ui_test/download_trace?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.test_client_id); - }; - - $scope.onDownloadRecordingButton = function () { - window.open("/network_ui_test/download_recording?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.test_client_id); - }; - - $scope.onUploadTestButton = function () { - window.open("/network_ui_test/upload_test", "_top"); - }; - - $scope.onRunTestsButton = function () { - - $scope.test_results = []; - $scope.current_tests = $scope.tests.slice(); - $scope.test_channel.send("EnableTest", new messages.EnableTest()); - }; - - $scope.all_buttons = $scope.context_menu_buttons; - - $scope.onDeviceCreate = function(data) { - $scope.create_device(data); - }; - - $scope.create_device = function(data) { - $log.debug(data); - var device = new models.Device(data.id, - data.name, - data.x, - data.y, - data.type, - data.host_id); - $scope.device_id_seq = util.natural_numbers(data.id); - $scope.devices.push(device); - $scope.devices_by_name[device.name] = device; - }; - - $scope.onInterfaceCreate = function(data) { - $scope.create_interface(data); - }; - - $scope.create_interface = function(data) { - var i = 0; - var new_interface = new models.Interface(data.id, data.name); - for (i = 0; i < $scope.devices.length; i++){ - if ($scope.devices[i].id === data.device_id) { - $scope.devices[i].interface_seq = util.natural_numbers(data.id); - new_interface.device = $scope.devices[i]; - $scope.devices[i].interfaces.push(new_interface); - } - } - }; - - $scope.onLinkCreate = function(data) { - $log.debug(data); - $scope.create_link(data); - }; - - $scope.create_link = function(data) { - var i = 0; - var j = 0; - var new_link = new models.Link(null, null, null, null); - new_link.id = data.id; - $scope.link_id_seq = util.natural_numbers(data.id); - for (i = 0; i < $scope.devices.length; i++){ - if ($scope.devices[i].id === data.from_device_id) { - new_link.from_device = $scope.devices[i]; - for (j = 0; j < $scope.devices[i].interfaces.length; j++){ - if ($scope.devices[i].interfaces[j].id === data.from_interface_id) { - new_link.from_interface = $scope.devices[i].interfaces[j]; - $scope.devices[i].interfaces[j].link = new_link; - } - } - } - } - for (i = 0; i < $scope.devices.length; i++){ - if ($scope.devices[i].id === data.to_device_id) { - new_link.to_device = $scope.devices[i]; - for (j = 0; j < $scope.devices[i].interfaces.length; j++){ - if ($scope.devices[i].interfaces[j].id === data.to_interface_id) { - new_link.to_interface = $scope.devices[i].interfaces[j]; - $scope.devices[i].interfaces[j].link = new_link; - } - } - } - } - $log.debug(new_link); - if (new_link.from_interface !== null && new_link.to_interface !== null) { - new_link.from_interface.dot(); - new_link.to_interface.dot(); - } - if (new_link.from_device !== null && new_link.to_device !== null) { - $scope.links.push(new_link); - } - }; - - $scope.onLinkDestroy = function(data) { - $scope.destroy_link(data); - }; - - $scope.destroy_link = function(data) { - var i = 0; - var link = null; - var index = -1; - for (i = 0; i < $scope.links.length; i++) { - link = $scope.links[i]; - if (link.id === data.id && - link.from_device.id === data.from_device_id && - link.to_device.id === data.to_device_id && - link.to_interface.id === data.to_interface_id && - link.from_interface.id === data.from_interface_id) { - link.from_interface.link = null; - link.to_interface.link = null; - index = $scope.links.indexOf(link); - $scope.links.splice(index, 1); - } - } - }; - - $scope.onDeviceMove = function(data) { - $scope.move_device(data); - }; - - $scope.move_device = function(data) { - var i = 0; - var j = 0; - for (i = 0; i < $scope.devices.length; i++) { - if ($scope.devices[i].id === data.id) { - $scope.devices[i].x = data.x; - $scope.devices[i].y = data.y; - for (j = 0; j < $scope.devices[i].interfaces.length; j ++) { - $scope.devices[i].interfaces[j].dot(); - if ($scope.devices[i].interfaces[j].link !== null) { - $scope.devices[i].interfaces[j].link.to_interface.dot(); - $scope.devices[i].interfaces[j].link.from_interface.dot(); - } - } - break; - } - } - }; - - $scope.onClientId = function(data) { - $scope.client_id = data; - }; - - $scope.onTopology = function(data) { - $scope.topology_id = data.topology_id; - $scope.panX = data.panX; - $scope.panY = data.panX; - $scope.current_scale = data.scale; - $scope.$emit('awxNet-UpdateZoomWidget', $scope.current_scale, true); - $scope.link_id_seq = util.natural_numbers(data.link_id_seq); - $scope.device_id_seq = util.natural_numbers(data.device_id_seq); - }; - - $scope.onDeviceSelected = function(data) { - var i = 0; - for (i = 0; i < $scope.devices.length; i++) { - if ($scope.devices[i].id === data.id) { - $scope.devices[i].remote_selected = true; - } - } - }; - - $scope.onDeviceUnSelected = function(data) { - var i = 0; - for (i = 0; i < $scope.devices.length; i++) { - if ($scope.devices[i].id === data.id) { - $scope.devices[i].remote_selected = false; - } - } - }; - - $scope.onSnapshot = function (data) { - - //Erase the existing state - $scope.devices = []; - $scope.links = []; - $scope.devices_by_name = {}; - - var device_map = {}; - var device_interface_map = {}; - var i = 0; - var j = 0; - var device = null; - var intf = null; - var new_device = null; - var new_intf = null; - var max_device_id = null; - var max_link_id = null; - var min_x = null; - var min_y = null; - var max_x = null; - var max_y = null; - var new_link = null; - - //Build the devices - for (i = 0; i < data.devices.length; i++) { - device = data.devices[i]; - if (max_device_id === null || device.id > max_device_id) { - max_device_id = device.id; - } - if (min_x === null || device.x < min_x) { - min_x = device.x; - } - if (min_y === null || device.y < min_y) { - min_y = device.y; - } - if (max_x === null || device.x > max_x) { - max_x = device.x; - } - if (max_y === null || device.y > max_y) { - max_y = device.y; - } - if (device.device_type === undefined) { - device.device_type = device.type; - } - new_device = new models.Device(device.id, - device.name, - device.x, - device.y, - device.device_type, - device.host_id); - if (device.variables !== undefined) { - new_device.variables = device.variables; - } - - for (j=0; j < $scope.inventory_toolbox.items.length; j++) { - if($scope.inventory_toolbox.items[j].name === device.name) { - $scope.inventory_toolbox.items.splice(j, 1); - break; - } - } - new_device.interface_seq = util.natural_numbers(device.interface_id_seq); - new_device.process_id_seq = util.natural_numbers(device.process_id_seq); - $scope.devices.push(new_device); - $scope.devices_by_name[new_device.name] = new_device; - device_map[device.id] = new_device; - device_interface_map[device.id] = {}; - for (j = 0; j < device.interfaces.length; j++) { - intf = device.interfaces[j]; - new_intf = (new models.Interface(intf.id, - intf.name)); - new_intf.device = new_device; - device_interface_map[device.id][intf.id] = new_intf; - new_device.interfaces.push(new_intf); - new_device.interfaces_by_name[new_intf.name] = new_intf; - } - } - - //Build the links - var link = null; - for (i = 0; i < data.links.length; i++) { - link = data.links[i]; - if (max_link_id === null || link.id > max_link_id) { - max_link_id = link.id; - } - new_link = new models.Link(link.id, - device_map[link.from_device_id], - device_map[link.to_device_id], - device_interface_map[link.from_device_id][link.from_interface_id], - device_interface_map[link.to_device_id][link.to_interface_id]); - new_link.name = link.name; - $scope.links.push(new_link); - device_interface_map[link.from_device_id][link.from_interface_id].link = new_link; - device_interface_map[link.to_device_id][link.to_interface_id].link = new_link; - } - - var diff_x; - var diff_y; - - // Calculate the new scale to show the entire diagram - if (min_x !== null && min_y !== null && max_x !== null && max_y !== null) { - diff_x = max_x - min_x; - diff_y = max_y - min_y; - - $scope.current_scale = Math.min(2, Math.max(0.10, Math.min((window.innerWidth-200)/diff_x, (window.innerHeight-300)/diff_y))); - $scope.$emit('awxNet-UpdateZoomWidget', $scope.current_scale, true); - $scope.updateScaledXY(); - $scope.updatePanAndScale(); - } - // Calculate the new panX and panY to show the entire diagram - if (min_x !== null && min_y !== null) { - diff_x = max_x - min_x; - diff_y = max_y - min_y; - $scope.panX = $scope.current_scale * (-min_x - diff_x/2) + window.innerWidth/2; - $scope.panY = $scope.current_scale * (-min_y - diff_y/2) + window.innerHeight/2; - $scope.updateScaledXY(); - $scope.updatePanAndScale(); - } - - //Update the device_id_seq to be greater than all device ids to prevent duplicate ids. - if (max_device_id !== null) { - $scope.device_id_seq = util.natural_numbers(max_device_id); - } - // - //Update the link_id_seq to be greater than all link ids to prevent duplicate ids. - if (max_link_id !== null) { - $scope.link_id_seq = util.natural_numbers(max_link_id); - } - - $log.debug(['data.inventory_toolbox', data.inventory_toolbox]); - if (data.inventory_toolbox !== undefined) { - $scope.inventory_toolbox.items = []; - for (i = 0; i < data.inventory_toolbox.length; i++) { - device = data.inventory_toolbox[i]; - $log.debug(device); - if (device.device_type === undefined) { - device.device_type = device.type; - } - new_device = new models.Device(device.id, - device.name, - device.x, - device.y, - device.device_type, - device.host_id); - if (device.variables !== undefined) { - new_device.variables = device.variables; - } - $scope.inventory_toolbox.items.push(new_device); - } - $log.debug($scope.inventory_toolbox.items); - } - - $scope.updateInterfaceDots(); - $scope.$emit('awxNet-instatiateSelect', $scope.devices); - }; - - $scope.updateInterfaceDots = function() { - var i = 0; - var j = 0; - var devices = $scope.devices; - for (i = devices.length - 1; i >= 0; i--) { - for (j = devices[i].interfaces.length - 1; j >= 0; j--) { - devices[i].interfaces[j].dot(); - } - } - }; - - $scope.control_socket.onmessage = function(message) { - $scope.first_channel.send('Message', message); - $scope.$apply(); - }; - - $scope.control_socket.onopen = function() { - //ignore - }; - - $scope.test_socket.onmessage = function(message) { - $scope.test_channel.send('Message', message); - $scope.$apply(); - }; - - $scope.test_socket.onopen = function() { - //ignore - }; - - // Call onopen directly if $scope.control_socket is already open - if ($scope.control_socket.readyState === WebSocket.OPEN) { - $scope.control_socket.onopen(); - } - // Call onopen directly if $scope.test_socket is already open - if ($scope.test_socket.readyState === WebSocket.OPEN) { - $scope.test_socket.onopen(); - } - - $scope.send_test_message = function (message) { - var i = 0; - message.sender = $scope.test_client_id; - message.message_id = $scope.message_id_seq(); - if (message.constructor.name === "MultipleMessage") { - for (i=0; i < message.messages.length; i++) { - message.messages[i].message_id = $scope.message_id_seq(); - } - } - var data = messages.serialize(message); - if (!$scope.disconnected) { - $scope.test_socket.send(data); - } - }; - - $scope.send_control_message = function (message) { - var i = 0; - message.sender = $scope.client_id; - message.message_id = $scope.message_id_seq(); - if (message.constructor.name === "MultipleMessage") { - for (i=0; i < message.messages.length; i++) { - message.messages[i].message_id = $scope.message_id_seq(); - } - } - var data = messages.serialize(message); - if (!$scope.disconnected) { - $scope.control_socket.send(data); - } - }; - - $scope.$on('awxNet-closeNetworkUI', function(){ - $scope.control_socket.close(); - if ($scope.tests_enabled) { - $scope.test_socket.close(); - } - }); - - // End web socket - // - - angular.element($window).bind('resize', function(){ - - $scope.graph.width = $window.innerWidth; - $scope.graph.right_column = 300; - $scope.graph.height = $window.innerHeight; - - $scope.update_size(); - - // manuall $digest required as resize event - // is outside of angular - $scope.$digest(); - }); - - //60fps ~ 17ms delay - setInterval( function () { - $scope.frame = Math.floor(window.performance.now()); - $scope.$apply(); - }, 17); - - $log.debug("Network UI started"); - - $scope.$on('$destroy', function () { - $log.debug("Network UI stopping"); - $scope.first_channel.send('UnbindDocument', {}); - }); - - $scope.update_toolbox_heights = function(){ - var toolboxTopMargin = $('.Networking-top').height(); - var toolboxTitleMargin = toolboxTopMargin + 35; - var toolboxHeight = $scope.graph.height - toolboxTopMargin; - - let toolboxes = ['inventory_toolbox']; - toolboxes.forEach((toolbox) => { - $scope[toolbox].y = toolboxTopMargin; - $scope[toolbox].height = toolboxHeight; - $scope[toolbox].title_coordinates.y = toolboxTitleMargin; - }); - - $('.Networking-detailPanel').height(toolboxHeight); - $('.Networking-detailPanel').css('top', toolboxTopMargin); - }; - - $scope.update_size = function () { - $scope.update_toolbox_heights(); - }; - - setInterval( function () { - var test_event = null; - if ($scope.test_events.length > 0) { - test_event = $scope.test_events.shift(); - test_event.sender = 0; - try { - $scope.first_channel.send(test_event.msg_type, test_event); - } catch (err) { - $log.debug(["Test Error:", $scope.current_test, err]); - $scope.test_errors.push(err); - } - } - $scope.$apply(); - }, 10); - - ConfigService - .getConfig() - .then(function(config){ - $scope.version = config.version; - }); - - $scope.reset_coverage = function() { - var i = null; - var coverage = null; - var f = null; - if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) { - for (f in window.__coverage__) { - coverage = window.__coverage__[f]; - for (i in coverage.b) { - coverage.b[i] = [0, 0]; - } - for (i in coverage.f) { - coverage.f[i] = 0; - } - for (i in coverage.s) { - coverage.s[i] = 0; - } - } - } - }; - - $scope.reset_flags = function () { - $scope.debug = {'hidden': true}; - $scope.hide_buttons = false; - $scope.hide_links = false; - $scope.hide_interfaces = false; - }; - - - $scope.reset_fsm_state = function () { - $scope.hotkeys_controller.state = hotkeys.Start; - $scope.hotkeys_controller.state.start($scope.hotkeys_controller); - $scope.keybindings_controller.state = keybindings.Start; - $scope.keybindings_controller.state.start($scope.keybindings_controller); - $scope.view_controller.state = view.Start; - $scope.view_controller.state.start($scope.view_controller); - $scope.move_controller.state = move.Start; - $scope.move_controller.state.start($scope.move_controller); - $scope.move_readonly_controller.state = move_readonly.Start; - $scope.move_readonly_controller.state.start($scope.move_readonly_controller); - $scope.details_panel_controller.state = details_panel_fsm.Start; - $scope.details_panel_controller.state.start($scope.details_panel_controller); - $scope.time_controller.state = time.Start; - $scope.time_controller.state.start($scope.time_controller); - $scope.inventory_toolbox_controller.state = toolbox_fsm.Start; - $scope.inventory_toolbox_controller.state.start($scope.inventory_toolbox_controller); - $scope.mode_controller.state = mode_fsm.Start; - $scope.mode_controller.state.start($scope.mode_controller); - }; - - $scope.reset_toolboxes = function () { - $scope.inventory_toolbox.items = []; - $scope.inventory_toolbox.scroll_offset = 0; - }; - - $scope.cancel_animations = function () { - - var i = 0; - for (i = 0; i < $scope.animations.length; i++) { - this.animations[i].fsm.handle_message('AnimationCancelled'); - } - $scope.animations = []; - }; - $log.debug("Network UI loaded"); -}; - -exports.NetworkUIController = NetworkUIController; diff --git a/awx/ui/client/src/network-ui/network.ui.directive.js b/awx/ui/client/src/network-ui/network.ui.directive.js deleted file mode 100644 index af53c596774a..000000000000 --- a/awx/ui/client/src/network-ui/network.ui.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/network_ui.partial.svg'); - -function awxNetworkUI () { - return { restrict: 'E', templateUrl}; -} -exports.awxNetworkUI = awxNetworkUI; diff --git a/awx/ui/client/src/network-ui/network_ui.partial.svg b/awx/ui/client/src/network-ui/network_ui.partial.svg deleted file mode 100644 index afb740b3d5b8..000000000000 --- a/awx/ui/client/src/network-ui/network_ui.partial.svg +++ /dev/null @@ -1,81 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/awx/ui/client/src/network-ui/quadrants.directive.js b/awx/ui/client/src/network-ui/quadrants.directive.js deleted file mode 100644 index 85874c9f21be..000000000000 --- a/awx/ui/client/src/network-ui/quadrants.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/quadrants.partial.svg'); - -function quadrants () { - return { restrict: 'A', templateUrl}; -} -exports.quadrants = quadrants; diff --git a/awx/ui/client/src/network-ui/quadrants.partial.svg b/awx/ui/client/src/network-ui/quadrants.partial.svg deleted file mode 100644 index 142b733d4237..000000000000 --- a/awx/ui/client/src/network-ui/quadrants.partial.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - diff --git a/awx/ui/client/src/network-ui/router.directive.js b/awx/ui/client/src/network-ui/router.directive.js deleted file mode 100644 index 22059d930d1c..000000000000 --- a/awx/ui/client/src/network-ui/router.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/router.partial.svg'); - -function router () { - return { restrict: 'A', templateUrl}; -} -exports.router = router; diff --git a/awx/ui/client/src/network-ui/router.partial.svg b/awx/ui/client/src/network-ui/router.partial.svg deleted file mode 100644 index 99a2606926ff..000000000000 --- a/awx/ui/client/src/network-ui/router.partial.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - - diff --git a/awx/ui/client/src/network-ui/style.less b/awx/ui/client/src/network-ui/style.less deleted file mode 100644 index 8ea255e2792f..000000000000 --- a/awx/ui/client/src/network-ui/style.less +++ /dev/null @@ -1,692 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -@import 'network-nav/network.nav.block.less'; -@import 'network-details/details.block.less'; -@import 'zoom-widget/zoom.block.less'; - -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 400; - src: url(/static/assets/OpenSans-Regular.ttf); -} - -@font-face { - font-family: 'Open Sans'; - font-style: bold; - font-weight: 600; - src: url(/static/assets/OpenSans-Bold.ttf); -} - -@selected-red: #c9232c; -@selected-mango: #ff5850; -@selected-blue: #5bbddf; -@light-background: #ffffff; -@light-widget-detail: #ffffff; -@dark-widget-detail: #707070; -@widget-body: #D7D7D7; -@link: #D7D7D7; -@group: #707070; -@debug-copynot: rgb(77,200,242); -@button-body: #ffffff; -@button-text: #707070; -@button-outline: #b7b7b7; -@button-body-hover: #f2f2f2; -@button-body-pressed: #848992; -@button-text-pressed: #ffffff; -@green: #5CB85C; -@red: #D9534F; -@blue: #337AB7; -@light-toolbox-background: #f6f6f6; -@icon-background-hover:@blue; -@context-menu-text: #333; - -.NetworkUI { - background-color: @light-toolbox-background; - z-index: 1100; -} - -.NetworkUI__text { - fill: @button-text; - font-family: 'Open Sans'; -} - -.NetworkUI__debug-text { - fill: @debug-copynot; - font-family: 'Open Sans'; -} - -.NetworkUI--debug { - fill-opacity: 0; - stroke: @debug-copynot; - stroke-width: 1; -} - -.NetworkUI--construction { - fill-opacity: 0; - stroke: @debug-copynot; - stroke-width: 1; -} - - -.NetworkUI__link--selected { - stroke: @selected-blue; - stroke-width: 6; -} - -.NetworkUI__link--remote-selected { - stroke: @selected-mango; - stroke-width: 6; -} - -.NetworkUI__link--selected-conflict { - stroke: @selected-red; - stroke-width: 6; -} - - -.NetworkUI__link { - stroke: @link; - stroke-width: 2; -} - -.NetworkUI__link--link-pass { - stroke: @green; - stroke-width: 2; -} - -.NetworkUI__link--link-fail { - stroke: @red; - stroke-width: 2; -} - -.NetworkUI__link--debug { - stroke: @debug-copynot; - stroke-width: 1; -} - -.NetworkUI__cursor { - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__debug-cursor { - stroke: @debug-copynot; - stroke-width: 4; -} - -.NetworkUI--hidden { - display: none; -} - -.NetworkUI__router { - fill: @blue; -} - -.NetworkUI__router--background{ - fill: @light-background; -} - -.NetworkUI__router--selected { - stroke: @selected-blue; - stroke-width: 10; - fill:@light-background; -} - -.NetworkUI__router--remote-selected { - stroke: @selected-mango; - stroke-width: 10; - fill: @light-background -} - -.NetworkUI__router--selected-conflict { - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__router-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__router-text--selected { - font-family: 'Open Sans'; -} - - -.NetworkUI__switch { - fill: @blue; -} - -.NetworkUI__switch--background{ - fill: @light-background; -} - -.NetworkUI__switch--selected { - stroke: @selected-blue; - stroke-width: 10; - fill:@light-background; -} - -.NetworkUI__switch--remote-selected { - stroke: @selected-mango; - stroke-width: 10; - fill: @light-background -} - -.NetworkUI__switch--selected-conflict { - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__switch line { - stroke: @light-widget-detail; - stroke-width: 20; -} - -.NetworkUI__switch polygon { - fill: @light-widget-detail; - stroke: none; -} - -.NetworkUI__switch-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__switch-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__rack { - fill: @blue; -} - -.NetworkUI__rack--background { - fill: @light-background; -} - -.NetworkUI__rack--selected { - fill: @light-background; - stroke: @selected-blue; - stroke-width: 10; -} - -.NetworkUI__rack--remote-selected { - fill: @light-background; - stroke: @selected-mango; - stroke-width: 10; -} - -.NetworkUI__rack--selected-conflict { - fill: @selected-red; - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__rack line { - stroke: @light-widget-detail; - stroke-width: 20; -} - -.NetworkUI__rack circle { - fill: @light-widget-detail; - stroke: none; -} - - -.NetworkUI__rack-text { - fill: @button-text; - font-family: 'Open Sans'; -} - -.NetworkUI__rack-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__site { - fill: @blue; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__site--fill0{ - fill:@blue; -} - -.NetworkUI__site--fill1{ - fill:none; - stroke:@light-background; - stroke-width:2; - stroke-miterlimit:10; -} - -.NetworkUI__site--fill2{ - fill:@light-background; -} - -.NetworkUI__site--network { - fill: @dark-widget-detail; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__site--background { - fill: @light-background; -} - -.NetworkUI__site--selected { - fill: @light-background; - stroke: @selected-blue; - stroke-width: 10; -} - -.NetworkUI__site--remote-selected { - fill: @light-background; - stroke: @selected-mango; - stroke-width: 10; -} - -.NetworkUI__site--selected-conflict { - fill: @selected-red; - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__site line { - stroke: @dark-widget-detail; - stroke-width: 10; -} - -.NetworkUI__site circle { - fill: @light-widget-detail; - stroke: none; -} - - -.NetworkUI__site-text { - fill: @button-text; - font-family: 'Open Sans'; -} - -.NetworkUI__site-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__button { - fill: @button-body; - stroke: @button-outline; - stroke-width: 1; -} - -.NetworkUI__button-text { - fill: @button-text; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__button--button-pressed { - fill: @button-body-pressed; - stroke: @button-outline; - stroke-width: 1; -} - -.NetworkUI__button-text--button-pressed { - fill: @button-text-pressed; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__button--button-hover { - fill: @button-body-hover; - stroke: @button-outline; - stroke-width: 1; -} - -.NetworkUI__button-text--button-hover { - fill: @button-text; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__host { - fill: @blue; -} - -.NetworkUI__host--background { - fill: @light-background; -} - -.NetworkUI__host--selected { - fill: @light-background; - stroke: @selected-blue; - stroke-width: 10; -} - -.NetworkUI__host--remote-selected { - fill: @light-background; - stroke: @selected-mango; - stroke-width: 10; -} - -.NetworkUI__host--selected-conflict { - fill: @selected-red; - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__host line { - stroke: @light-widget-detail; - stroke-width: 20; -} - -.NetworkUI__host circle { - fill: @light-widget-detail; - stroke: none; -} - - -.NetworkUI__host-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__host-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__device { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__device-background { - fill: @light-background; - stroke: @light-background; - stroke-width: 2; -} - -.NetworkUI__device--selected { - fill: @selected-blue; - stroke: @selected-blue; - stroke-width: 10; -} - -.NetworkUI__device--remote-selected { - fill: @light-background; - stroke: @selected-mango; - stroke-width: 10; -} - -.NetworkUI__device--selected-conflict { - fill: @selected-red; - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__device line { - stroke: @light-widget-detail; - stroke-width: 20; -} - - -.NetworkUI__device-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__device-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__status { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__status--pass { - fill: @green; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__status--fail { - fill: @red; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__status-path { - fill: none; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__circle-debug { - fill: @debug-copynot; -} - - -.NetworkUI__interface { - fill: @button-outline; -} - -.NetworkUI__interface--selected { - fill: @selected-blue; -} - -.NetworkUI__interface-text { - fill: @button-text; - font-size: 8px; - font-family: 'Open Sans'; -} - - -.NetworkUI__interface-text--selected { - font-size: 8px; - font-family: 'Open Sans'; -} - -.NetworkUI__link-text { - fill: @button-text; - font-size: 8px; - font-family: 'Open Sans'; -} - -.NetworkUI__group--selected { - stroke: @selected-blue; - stroke-width: 6; - fill: none; -} - -.NetworkUI__group--remote-selected { - stroke: @selected-mango; - stroke-width: 6; - fill: none; -} - -.NetworkUI__group--selected-conflict { - stroke: @selected-red; - stroke-width: 6; - fill: none; -} - -.NetworkUI__group { - stroke: @group; - stroke-width: 2; - fill: none; -} - -.NetworkUI__group--debug { - stroke: @debug-copynot; - stroke-width: 1; - fill: none; -} - -.NetworkUI__group-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__group-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__location-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__toolbox { - stroke: none; - fill: @light-background; -} - -.NetworkUI__toolbox-collapsed{ - fill: @light-background; - stroke: @button-outline; - stroke-width: 1; - rx: 0; - stroke-dasharray: calc(~"100vh - 80px"); - stroke-dashoffset: -45; -} - -.NetworkUI__toolbox-bezel { - stroke: @button-outline; - stroke-width: 1; - fill: none; - rx: 0; - stroke-dasharray: calc(~"100vh - 80px"); - stroke-dashoffset: -200; -} - -.NetworkUI__process { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__process-background { - fill: @light-background; - stroke: @light-background; - stroke-width: 2; -} - -.NetworkUI__process--selected { - fill: @selected-blue; - stroke: @selected-blue; - stroke-width: 10; -} - -.NetworkUI__process--remote-selected { - fill: @selected-mango; - stroke: @selected-mango; - stroke-width: 10; -} - -.NetworkUI__process--selected-conflict { - fill: @selected-red; - stroke: @selected-red; - stroke-width: 10; -} - -.NetworkUI__process path { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; -} - -.NetworkUI__process-text { - fill: @button-text; - font-family: 'Open Sans'; -} - - -.NetworkUI__process-text--selected { - font-family: 'Open Sans'; -} - -.NetworkUI__stream { - fill: none; - stroke: @dark-widget-detail; -} - -.NetworkUI__stream-arrow { - fill: @dark-widget-detail; - stroke: @dark-widget-detail; -} - -.NetworkUI__stream--selected { - fill: none; - stroke: @selected-blue; - stroke-width: 6; -} -.NetworkUI__stream-arrow--selected { - fill: @selected-blue; - stroke: @selected-blue; -} - -.NetworkUI__stream-text { - fill: @button-text; - font-size: 8px; - font-family: 'Open Sans'; -} - -.NetworkUI__toolbox--title{ - fill: @dark-widget-detail; - text-transform: uppercase; - font-size: 14px; - font-weight: bold; -} - -.NetworkUI__contextMenu{ - fill: @light-background; - stroke: @button-outline; - stroke-width: 1; - -} - -.NetworkUI__contextMenuButton{ - fill: @light-background; -} - -.NetworkUI__contextMenuButtonText{ - fill: @context-menu-text; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__contextMenuButtonText-hover{ - fill: @context-menu-text; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__contextMenuButton-hover, -.NetworkUI__contextMenuButton-pressed{ - fill:@button-body-hover; -} - -.NetworkUI__contextMenuRemoveButtonText{ - fill: @red; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__contextMenuRemoveButtonText-hover{ - fill: @red; - font-family: 'Open Sans'; - font-size: 14px; -} - -.NetworkUI__test_results { - fill: @light-background; - stroke: @dark-widget-detail; -} diff --git a/awx/ui/client/src/network-ui/switch.directive.js b/awx/ui/client/src/network-ui/switch.directive.js deleted file mode 100644 index a9fbb48a8dc5..000000000000 --- a/awx/ui/client/src/network-ui/switch.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/switch.partial.svg'); - -function switchd () { - return { restrict: 'A', templateUrl}; -} -exports.switchd = switchd; diff --git a/awx/ui/client/src/network-ui/switch.partial.svg b/awx/ui/client/src/network-ui/switch.partial.svg deleted file mode 100644 index 65692d8101b1..000000000000 --- a/awx/ui/client/src/network-ui/switch.partial.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - - diff --git a/awx/ui/client/src/network-ui/templates/fsm.jst b/awx/ui/client/src/network-ui/templates/fsm.jst deleted file mode 100644 index afe75f5cd8c9..000000000000 --- a/awx/ui/client/src/network-ui/templates/fsm.jst +++ /dev/null @@ -1,26 +0,0 @@ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - -{%for state in states%} -function _{{state.label}} () { - this.name = '{{state.label}}'; -} -inherits(_{{state.label}}, _State); -var {{state.label}} = new _{{state.label}}(); -exports.{{state.label}} = {{state.label}}; -{%endfor%} - -{%for state in states%} -{%for fn, transitions in state.functions%} -_{{state.label}}.prototype.{{fn}} = function (controller) { -{%for tn in transitions %} - controller.changeState({{tn.to_state}}); -{%endfor%} -}; -_{{state.label}}.prototype.{{fn}}.transitions = [{%for t in transitions%}'{{t.to_state}}'{% if not loop.last%}, {%endif%}{%endfor%}]; -{%endfor%} -{%endfor%} diff --git a/awx/ui/client/src/network-ui/test.fsm.js b/awx/ui/client/src/network-ui/test.fsm.js deleted file mode 100644 index 4867e92f5913..000000000000 --- a/awx/ui/client/src/network-ui/test.fsm.js +++ /dev/null @@ -1,186 +0,0 @@ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); -var messages = require('./messages.js'); -var models = require('./models.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Disabled () { - this.name = 'Disabled'; -} -inherits(_Disabled, _State); -var Disabled = new _Disabled(); -exports.Disabled = Disabled; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Running () { - this.name = 'Running'; -} -inherits(_Running, _State); -var Running = new _Running(); -exports.Running = Running; - -function _Loading () { - this.name = 'Loading'; -} -inherits(_Loading, _State); -var Loading = new _Loading(); -exports.Loading = Loading; - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Reporting () { - this.name = 'Reporting'; -} -inherits(_Reporting, _State); -var Reporting = new _Reporting(); -exports.Reporting = Reporting; - - -_State.prototype.onMessage = function(controller, msg_type, message) { - - var type_data = JSON.parse(message.data); - var type = type_data[0]; - var data = type_data[1]; - - controller.handle_message(type, data); -}; - -_State.prototype.onid = function(controller, msg_type, message) { - controller.scope.test_client_id = message; -}; - -_State.prototype.onTestCase = function(controller, msg_type, message) { - if ('runnable' in message[1]) { - if (!message[1].runnable) { - return; - } - } - controller.scope.tests.push(new models.Test(message[0], - message[1].event_trace, - [], - message[1].snapshots[0], - message[1].snapshots[1])); -}; - -_Disabled.prototype.onEnableTest = function (controller) { - - controller.changeState(Ready); -}; -_Disabled.prototype.onEnableTest.transitions = ['Ready']; - - - -_Start.prototype.start = function (controller) { - - controller.changeState(Disabled); - -}; -_Start.prototype.start.transitions = ['Disabled']; - - - -_Running.prototype.onTestCompleted = function (controller) { - - controller.changeState(Reporting); -}; -_Running.prototype.onTestCompleted.transitions = ['Reporting']; - -_Reporting.prototype.start = function (controller) { - - var test_result = null; - controller.scope.replay = false; - controller.scope.disconnected = false; - controller.scope.recording = false; - controller.scope.cursor.hidden = true; - var result = "passed"; - if (controller.scope.test_errors.length > 0) { - result = "errored"; - } - test_result = new models.TestResult(controller.scope.test_result_id_seq(), - controller.scope.current_test.name, - result, - new Date().toISOString(), - controller.scope.version); - controller.scope.test_results.push(test_result); - console.log(["Reporting test", test_result.name, test_result.id]); - controller.scope.send_test_message(new messages.TestResult(controller.scope.client_id, - test_result.id, - test_result.name, - test_result.result, - test_result.date, - test_result.code_under_test)); - if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) { - console.log(["Reporting coverage", test_result.name, test_result.id]); - controller.scope.send_test_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, test_result.id)); - } - controller.changeState(Loading); -}; -_Reporting.prototype.start.transitions = ['Loading']; - - -_Loading.prototype.start = function (controller) { - - if (controller.scope.current_tests.length === 0) { - controller.changeState(Disabled); - } else { - console.log("Starting test"); - controller.scope.reset_coverage(); - controller.scope.current_test = controller.scope.current_tests.shift(); - controller.scope.reset_toolboxes(); - controller.scope.onSnapshot(controller.scope.current_test.pre_test_snapshot); - controller.scope.replay = true; - controller.scope.disconnected = true; - controller.scope.test_errors = []; - controller.scope.test_events = controller.scope.current_test.event_trace.slice(); - controller.scope.test_events.push(new messages.TestCompleted()); - controller.scope.reset_flags(); - controller.scope.reset_fsm_state(); - controller.scope.cancel_animations(); - controller.scope.cursor.hidden = false; - controller.changeState(Running); - } -}; -_Loading.prototype.start.transitions = ['Running']; - - - -_Ready.prototype.onDisableTest = function (controller) { - - controller.changeState(Disabled); -}; -_Ready.prototype.onDisableTest.transitions = ['Disabled']; - -_Ready.prototype.start = function (controller) { - - var load_id = controller.scope.test_result_id_seq(); - - console.log(["Reporting Load", load_id]); - controller.scope.send_test_message(new messages.TestResult(controller.scope.client_id, - load_id, - "Load", - "passed", - new Date().toISOString(), - controller.scope.version)); - if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) { - console.log(["Reporting Load Coverage", load_id]); - controller.scope.send_test_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, load_id)); - } - - controller.changeState(Loading); -}; -_Ready.prototype.start.transitions = ['Loading']; diff --git a/awx/ui/client/src/network-ui/test_results.directive.js b/awx/ui/client/src/network-ui/test_results.directive.js deleted file mode 100644 index 9430ad40566c..000000000000 --- a/awx/ui/client/src/network-ui/test_results.directive.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2018 Red Hat, Inc. */ - -const templateUrl = require('~network-ui/test_results.partial.svg'); - -function test_results () { - return { restrict: 'A', templateUrl}; -} -exports.test_results = test_results; diff --git a/awx/ui/client/src/network-ui/test_results.partial.svg b/awx/ui/client/src/network-ui/test_results.partial.svg deleted file mode 100644 index bc0c422a461a..000000000000 --- a/awx/ui/client/src/network-ui/test_results.partial.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -Test Results {{version}} - - -{{result.name}} - {{result.result}} - - - - - diff --git a/awx/ui/client/src/network-ui/time.fsm.js b/awx/ui/client/src/network-ui/time.fsm.js deleted file mode 100644 index cd425df2ae97..000000000000 --- a/awx/ui/client/src/network-ui/time.fsm.js +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); -var util = require('./util.js'); - -function _State () { -} -inherits(_State, fsm._State); - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Present () { - this.name = 'Present'; -} -inherits(_Present, _State); -var Present = new _Present(); -exports.Present = Present; - -_Start.prototype.start = function (controller) { - - controller.changeState(Present); - -}; -_Start.prototype.start.transitions = ['Present']; - -_Present.prototype.onMessage = function(controller, msg_type, message) { - - var type_data = JSON.parse(message.data); - var type = type_data[0]; - var data = type_data[1]; - - controller.handle_message(type, data); -}; - -_Present.prototype.onMultipleMessage = function(controller, msg_type, message) { - - var i = 0; - if (message.sender !== controller.scope.client_id) { - for (i = 0; i< message.messages.length; i++) { - controller.handle_message(message.messages[i].msg_type, message.messages[i]); - } - } -}; - -_Present.prototype.onDeviceCreate = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onDeviceCreate(message); - } -}; -_Present.prototype.onInterfaceCreate = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onInterfaceCreate(message); - } -}; -_Present.prototype.onLinkCreate = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onLinkCreate(message); - } -}; -_Present.prototype.onDeviceMove = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onDeviceMove(message); - } -}; -_Present.prototype.onDeviceDestroy = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onDeviceDestroy(message); - } -}; -_Present.prototype.onLinkDestroy = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onLinkDestroy(message); - } -}; -_Present.prototype.onDeviceSelected = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onDeviceSelected(message); - } -}; -_Present.prototype.onDeviceUnSelected = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onDeviceUnSelected(message); - } -}; -_Present.prototype.onSnapshot = function(controller, msg_type, message) { - if (message.sender !== controller.scope.client_id) { - controller.scope.onSnapshot(message); - } -}; -_Present.prototype.onid = function(controller, msg_type, message) { - controller.scope.onClientId(message); -}; -_Present.prototype.onTopology = function(controller, msg_type, message) { - controller.scope.onTopology(message); -}; -_Present.prototype.onViewPort = function(controller, msg_type, message) { - if (message.sender === controller.scope.client_id) { - return; - } - controller.scope.current_scale = message.scale; - controller.scope.panX = message.panX; - controller.scope.panY = message.panY; - if (message.graph_width !== undefined) { - controller.scope.graph.width = message.graph_width; - } - if (message.graph_height !== undefined) { - controller.scope.graph.height = message.graph_height; - } - controller.scope.update_toolbox_heights(); - controller.scope.updateScaledXY(); - controller.scope.updatePanAndScale(); -}; -_Present.prototype.onMouseEvent = function(controller, msg_type, message) { - if (!controller.scope.replay) { - return; - } - if (message.sender === controller.scope.client_id) { - return; - } - message.preventDefault = util.noop; - if (message.type === "mousemove") { - controller.scope.onMouseMove(message); - } - if (message.type === "mouseup") { - controller.scope.onMouseUp(message); - } - if (message.type === "mousedown") { - controller.scope.onMouseDown(message); - } - if (message.type === "mouseover") { - controller.scope.onMouseOver(message); - } -}; -_Present.prototype.onMouseWheelEvent = function(controller, msg_type, message) { - if (!controller.scope.replay) { - return; - } - if (message.sender === controller.scope.client_id) { - return; - } - message.preventDefault = util.noop; - message.stopPropagation = util.noop; - controller.scope.onMouseWheel(message, message.delta, message.deltaX, message.deltaY); -}; - _Present.prototype.onKeyEvent = function(controller, msg_type, message) { - if (!controller.scope.replay) { - return; - } - if (message.sender === controller.scope.client_id) { - return; - } - message.preventDefault = util.noop; - if (message.type === "keydown") { - controller.scope.onKeyDown(message); - } -}; - -_Present.prototype.onRecordButton = function(controller) { - controller.scope.onRecordButton(); -}; - -_Present.prototype.onExportButton = function(controller) { - controller.scope.onExportButton(); -}; - -_Present.prototype.onExportYamlButton = function(controller) { - controller.scope.onExportYamlButton(); -}; - -_Present.prototype.onDownloadTraceButton = function(controller) { - controller.scope.onDownloadTraceButton(); -}; - -_Present.prototype.onDownloadRecordingButton = function(controller) { - controller.scope.onDownloadRecordingButton(); -}; - -_Present.prototype.onNoop = function() { - -}; - -_Present.prototype.onTestCompleted = function(controller, msg_type, message) { - - controller.scope.test_channel.send(msg_type, message); -}; - - -_Present.prototype.onError = function(controller, msg_type, message) { - throw new Error("ServerError: " + message); -}; diff --git a/awx/ui/client/src/network-ui/toolbox.fsm.js b/awx/ui/client/src/network-ui/toolbox.fsm.js deleted file mode 100644 index 562c38b167d1..000000000000 --- a/awx/ui/client/src/network-ui/toolbox.fsm.js +++ /dev/null @@ -1,343 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - - -function _Dropping () { - this.name = 'Dropping'; -} -inherits(_Dropping, _State); -var Dropping = new _Dropping(); -exports.Dropping = Dropping; - -function _Selecting () { - this.name = 'Selecting'; -} -inherits(_Selecting, _State); -var Selecting = new _Selecting(); -exports.Selecting = Selecting; - -function _Selected () { - this.name = 'Selected'; -} -inherits(_Selected, _State); -var Selected = new _Selected(); -exports.Selected = Selected; - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Scrolling () { - this.name = 'Scrolling'; -} -inherits(_Scrolling, _State); -var Scrolling = new _Scrolling(); -exports.Scrolling = Scrolling; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Move () { - this.name = 'Move'; -} -inherits(_Move, _State); -var Move = new _Move(); -exports.Move = Move; - -function _OffScreen () { - this.name = 'OffScreen'; -} -inherits(_OffScreen, _State); -var OffScreen = new _OffScreen(); -exports.OffScreen = OffScreen; - -function _OffScreen2 () { - this.name = 'OffScreen2'; -} -inherits(_OffScreen2, _State); -var OffScreen2 = new _OffScreen2(); -exports.OffScreen2 = OffScreen2; - -function _Disabled () { - this.name = 'Disabled'; -} -inherits(_Disabled, _State); -var Disabled = new _Disabled(); -exports.Disabled = Disabled; - - -_Dropping.prototype.start = function (controller) { - - - var i = 0; - var toolbox = controller.toolbox; - for(i = 0; i < toolbox.items.length; i++) { - toolbox.items[i].selected = false; - } - - controller.dropped_action(toolbox.selected_item); - - if (controller.remove_on_drop && !toolbox.selected_item.template) { - var dindex = toolbox.items.indexOf(toolbox.selected_item); - if (dindex !== -1) { - toolbox.items.splice(dindex, 1); - } - } - - toolbox.selected_item = null; - controller.changeState(Ready); -}; -_Dropping.prototype.start.transitions = ['Ready']; - - - -_Selected.prototype.onMouseMove = function (controller) { - - controller.changeState(Move); - -}; -_Selected.prototype.onMouseMove.transitions = ['Move']; - -_Selected.prototype.onMouseUp = function (controller) { - - var i = 0; - var toolbox = controller.toolbox; - for(i = 0; i < toolbox.items.length; i++) { - toolbox.items[i].selected = false; - } - toolbox.selected_item = null; - controller.changeState(Ready); -}; -_Selected.prototype.onMouseUp.transitions = ['Ready']; - - -_Selecting.prototype.onMouseDown = function (controller) { - - var i = 0; - - var toolbox = controller.toolbox; - var scope = controller.scope; - var selected_item = Math.floor((controller.scope.mouseY - toolbox.y - toolbox.scroll_offset) / toolbox.spacing); - - for(i = 0; i < toolbox.items.length; i++) { - toolbox.items[i].selected = false; - } - if (selected_item >= 0 && selected_item < toolbox.items.length) { - toolbox.items[selected_item].selected = true; - toolbox.selected_item = toolbox.items[selected_item]; - scope.pressedX = scope.mouseX; - scope.pressedY = scope.mouseY; - scope.pressedScaledX = scope.scaledX; - scope.pressedScaledY = scope.scaledY; - toolbox.selected_item.x = toolbox.x + toolbox.width/2; - toolbox.selected_item.y = selected_item * toolbox.spacing + toolbox.y + toolbox.scroll_offset + toolbox.spacing/2; - controller.scope.clear_selections(); - controller.scope.first_channel.send("UnselectAll", {}); - controller.changeState(Selected); - } else { - toolbox.selected_item = null; - controller.changeState(Ready); - } - -}; -_Selecting.prototype.onMouseDown.transitions = ['Selected', 'Ready']; - -_Ready.prototype.onEnable = function () { - -}; - -_Ready.prototype.onMouseDown = function (controller, msg_type, $event) { - - if(controller.toolbox.enabled && - controller.scope.mouseX > controller.toolbox.x && - controller.scope.mouseY > controller.toolbox.y && - controller.scope.mouseX < controller.toolbox.x + controller.toolbox.width && - controller.scope.mouseY < controller.toolbox.y + controller.toolbox.height) { - - controller.changeState(Selecting); - controller.handle_message(msg_type, $event); - - } else { - controller.delegate_channel.send(msg_type, $event); - } -}; -_Ready.prototype.onMouseDown.transitions = ['Selecting']; - -_Ready.prototype.onMouseWheel = function (controller, msg_type, $event) { - - if(controller.toolbox.enabled && - controller.scope.mouseX > controller.toolbox.x && - controller.scope.mouseY > controller.toolbox.y && - controller.scope.mouseX < controller.toolbox.x + controller.toolbox.width && - controller.scope.mouseY < controller.toolbox.y + controller.toolbox.height) { - - controller.changeState(Scrolling); - controller.handle_message(msg_type, $event); - - } else { - controller.delegate_channel.send(msg_type, $event); - } -}; -_Ready.prototype.onMouseWheel.transitions = ['Scrolling']; - -_Ready.prototype.onToggleToolbox = function (controller, msg_type, message) { - - controller.changeState(OffScreen); - controller.delegate_channel.send(msg_type, message); - -}; -_Ready.prototype.onToggleToolbox.transitions = ['OffScreen']; - -_Ready.prototype.onDisable = function (controller) { - - controller.changeState(Disabled); - -}; -_Ready.prototype.onDisable.transitions = ['Disabled']; - -_Scrolling.prototype.onMouseWheel = function (controller, msg_type, $event) { - - var delta = $event[1]; - controller.toolbox.scroll_offset += -1 * delta; - controller.toolbox.scroll_offset = Math.min(controller.toolbox.scroll_offset, 0); - controller.toolbox.scroll_offset = Math.max(controller.toolbox.scroll_offset, - -1 * controller.toolbox.spacing * (controller.toolbox.items.length + 1) + controller.toolbox.height); - - - controller.changeState(Ready); - -}; -_Scrolling.prototype.onMouseWheel.transitions = ['Ready']; - - - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - - - -_Move.prototype.onMouseUp = function (controller) { - - var i = 0; - var toolbox = controller.toolbox; - - if (controller.scope.mouseX < controller.toolbox.width) { - for(i = 0; i < toolbox.items.length; i++) { - toolbox.items[i].selected = false; - } - toolbox.selected_item = null; - controller.changeState(Ready); - - } else { - controller.changeState(Dropping); - } -}; -_Move.prototype.onMouseUp.transitions = ['Dropping']; - - -_Move.prototype.onMouseMove = function (controller) { - - var diffX = controller.scope.mouseX - controller.scope.pressedX; - var diffY = controller.scope.mouseY - controller.scope.pressedY; - - controller.toolbox.selected_item.x += diffX; - controller.toolbox.selected_item.y += diffY; - - controller.scope.pressedX = controller.scope.mouseX; - controller.scope.pressedY = controller.scope.mouseY; -}; - - -_OffScreen.prototype.onToggleToolbox = function (controller, msg_type, message) { - - controller.changeState(Ready); - controller.delegate_channel.send(msg_type, message); - -}; -_OffScreen.prototype.onToggleToolbox.transitions = ['Ready']; - - -_OffScreen.prototype.start = function (controller) { - - controller.toolbox.enabled = false; - -}; - -_OffScreen.prototype.end = function (controller) { - - controller.toolbox.enabled = true; - -}; - -_OffScreen.prototype.onDisable = function (controller) { - - controller.changeState(OffScreen2); -}; -_OffScreen.prototype.onDisable.transitions = ['OffScreen2']; - -_OffScreen2.prototype.onEnable = function (controller) { - - controller.changeState(OffScreen); -}; -_OffScreen2.prototype.onEnable.transitions = ['OffScreen']; - -_OffScreen2.prototype.onDisable = function () { - -}; - -_OffScreen2.prototype.start = function (controller) { - - controller.toolbox.enabled = false; -}; - -_OffScreen2.prototype.onToggleToolbox = function (controller, msg_type, message) { - - controller.changeState(Disabled); - controller.delegate_channel.send(msg_type, message); -}; -_OffScreen2.prototype.onToggleToolbox.transitions = ['Disabled']; - -_Disabled.prototype.onDisable = function () { - -}; - -_Disabled.prototype.onEnable = function (controller) { - - controller.changeState(Ready); -}; -_Disabled.prototype.onEnable.transitions = ['Ready']; - -_Disabled.prototype.start = function (controller) { - if(controller.toolbox !== undefined){ - controller.toolbox.enabled = false; - } -}; - -_Disabled.prototype.end = function (controller) { - - controller.toolbox.enabled = true; - -}; - -_Disabled.prototype.onToggleToolbox = function (controller, msg_type, message) { - - controller.changeState(OffScreen2); - controller.delegate_channel.send(msg_type, message); -}; -_Disabled.prototype.onToggleToolbox.transitions = ['OffScreen2']; diff --git a/awx/ui/client/src/network-ui/tools/copy-layout.py b/awx/ui/client/src/network-ui/tools/copy-layout.py deleted file mode 100755 index dd7cfbf94707..000000000000 --- a/awx/ui/client/src/network-ui/tools/copy-layout.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (c) 2018 Benjamin Thomasson - -""" -Usage: - copy-layout [options] - -Options: - -h, --help Show this page - --debug Show debug logging - --verbose Show verbose logging -""" -from docopt import docopt -import logging -import sys -import yaml - -logger = logging.getLogger('copy-layout') - - -def main(args=None): - if args is None: - args = sys.argv[1:] - parsed_args = docopt(__doc__, args) - if parsed_args['--debug']: - logging.basicConfig(level=logging.DEBUG) - elif parsed_args['--verbose']: - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.WARNING) - - with open(parsed_args['']) as f: - from_fsm = yaml.load(f.read()) - with open(parsed_args['']) as f: - to_fsm = yaml.load(f.read()) - - to_states = {x['label']: x for x in to_fsm.get('states', [])} - - to_fsm['name'] = from_fsm.get('name', '') - to_fsm['finite_state_machine_id'] = from_fsm.get('finite_state_machine_id', '') - to_fsm['diagram_id'] = from_fsm.get('diagram_id', '') - - for state in from_fsm.get('states', []): - to_states.get(state['label'], {})['x'] = state.get('x', 0) - to_states.get(state['label'], {})['y'] = state.get('y', 0) - - with open(parsed_args[''], 'w') as f: - f.write(yaml.safe_dump(to_fsm, default_flow_style=False)) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/awx/ui/client/src/network-ui/tools/fsm-diff b/awx/ui/client/src/network-ui/tools/fsm-diff deleted file mode 100755 index 5a400e96fe9c..000000000000 --- a/awx/ui/client/src/network-ui/tools/fsm-diff +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from fsm_diff.cli import main - -if __name__ == '__main__': - import sys - sys.exit(main(sys.argv[1:])) - diff --git a/awx/ui/client/src/network-ui/tools/fsm_diff/__init__.py b/awx/ui/client/src/network-ui/tools/fsm_diff/__init__.py deleted file mode 100755 index 268c10ff4023..000000000000 --- a/awx/ui/client/src/network-ui/tools/fsm_diff/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -__author__ = 'Ben Thomasson' -__email__ = 'benthomasson@gmail.com' -__version__ = '0.1.0' diff --git a/awx/ui/client/src/network-ui/tools/fsm_diff/cli.py b/awx/ui/client/src/network-ui/tools/fsm_diff/cli.py deleted file mode 100644 index d180676016f6..000000000000 --- a/awx/ui/client/src/network-ui/tools/fsm_diff/cli.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Usage: - fsm_diff [options] [] - -Options: - -h, --help Show this page - --debug Show debug logging - --verbose Show verbose logging -""" -from docopt import docopt -import logging -import sys -import yaml - -logger = logging.getLogger('cli') - - -def fsm_diff(a_name, b_name, a, b, silent=True): - - a_states = {x['label'] for x in a['states']} - b_states = {x['label'] for x in b['states']} - - missing_in_a = b_states - a_states - missing_in_b = a_states - b_states - - - if (missing_in_b) and not silent: - print "Extra states in " + a_name + ":\n ", "\n ".join(list(missing_in_b)) - - if (missing_in_a) and not silent: - print "Extra states in " + b_name + ":\n ", "\n ".join(list(missing_in_a)) - - new_states = missing_in_b.union(missing_in_a) - - a_transitions = {tuple(sorted(x.items())) for x in a['transitions']} - b_transitions = {tuple(sorted(x.items())) for x in b['transitions']} - - missing_in_a = b_transitions - a_transitions - missing_in_b = a_transitions - b_transitions - - - if (missing_in_b) and not silent: - print "Extra transitions in " + a_name + ":\n ", "\n ".join(map(str, missing_in_b)) - - if (missing_in_a) and not silent: - print "Extra transitions in " + b_name + ":\n ", "\n ".join(map(str, missing_in_a)) - - new_transitions = missing_in_b.union(missing_in_a) - - data = dict(states=[dict(label=x) for x in list(new_states)], - transitions=[dict(x) for x in list(new_transitions)]) - - return data - - -def main(args=None): - if args is None: - args = sys.argv[1:] - parsed_args = docopt(__doc__, args) - if parsed_args['--debug']: - logging.basicConfig(level=logging.DEBUG) - elif parsed_args['--verbose']: - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.WARNING) - - with open(parsed_args['']) as f: - a = yaml.load(f.read()) - - with open(parsed_args['']) as f: - b = yaml.load(f.read()) - - data = fsm_diff(parsed_args[''], parsed_args[''], a, b, silent=False) - - if parsed_args['']: - with open(parsed_args[''], 'w') as f: - f.write(yaml.dump(data, default_flow_style=False)) - - return 0 diff --git a/awx/ui/client/src/network-ui/tools/fsm_generate_diffs.py b/awx/ui/client/src/network-ui/tools/fsm_generate_diffs.py deleted file mode 100755 index b5df78c41994..000000000000 --- a/awx/ui/client/src/network-ui/tools/fsm_generate_diffs.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (c) 2017 Red Hat, Inc - -""" -Usage: - fsm_generate_diffs [options] - -Options: - -h, --help Show this page - --debug Show debug logging - --verbose Show verbose logging - --append Append the newly generated code to the implementation. -""" -from docopt import docopt -import logging -import sys -import fsm_diff.cli -import transform_fsm -import yaml - -from jinja2 import FileSystemLoader, Environment - -from subprocess import Popen, PIPE - -logger = logging.getLogger('fsm_generate_diffs') - - -def main(args=None): - if args is None: - args = sys.argv[1:] - parsed_args = docopt(__doc__, args) - if parsed_args['--debug']: - logging.basicConfig(level=logging.DEBUG) - elif parsed_args['--verbose']: - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.WARNING) - - implementation = parsed_args[''] - - p = Popen(['./extract.js', implementation], stdout=PIPE) - output = p.communicate()[0] - if p.returncode == 0: - b = yaml.load(output) - else: - return 1 - - with open(parsed_args['']) as f: - a = yaml.load(f.read()) - - data = fsm_diff.cli.fsm_diff(parsed_args[''], parsed_args[''], a, b) - data = transform_fsm.transform_fsm(data) - - env = Environment(loader=FileSystemLoader("templates")) - template = env.get_template('fsm.jst') - - if parsed_args['--append']: - with open(implementation, "a") as f: - f.write(template.render(**data)) - else: - print (template.render(**data)) - - - - return 0 - -if __name__ == '__main__': - import sys - sys.exit(main(sys.argv[1:])) diff --git a/awx/ui/client/src/network-ui/tools/requirements.txt b/awx/ui/client/src/network-ui/tools/requirements.txt deleted file mode 100644 index ec4c40220769..000000000000 --- a/awx/ui/client/src/network-ui/tools/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -jinja2 -docopt -pyyaml - diff --git a/awx/ui/client/src/network-ui/tools/transform_fsm.py b/awx/ui/client/src/network-ui/tools/transform_fsm.py deleted file mode 100755 index 9b5fd0a66ac0..000000000000 --- a/awx/ui/client/src/network-ui/tools/transform_fsm.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (c) 2017 Red Hat, Inc - -""" -Usage: - transform_fsm [options] - -Options: - -h, --help Show this page - --debug Show debug logging - --verbose Show verbose logging -""" -from docopt import docopt -import logging -import sys -import yaml - -logger = logging.getLogger('transform_fsm') - - -def transform_fsm(data): - - state_map = dict() - - for state in data['states']: - state_map[state['label']] = state - state['functions'] = dict() - - for transition in data['transitions']: - state = state_map.get(transition['from_state'], dict(label=transition['from_state'], functions=dict())) - state_map[transition['from_state']] = state - if state not in data['states']: - data['states'].append(state) - function_transitions = state['functions'].get(transition['label'], list()) - function_transitions.append(dict(to_state=transition['to_state'])) - state['functions'][transition['label']] = function_transitions - - for state in data['states']: - state['functions'] = sorted(state['functions'].items()) - - return data - -def main(args=None): - if args is None: - args = sys.argv[1:] - parsed_args = docopt(__doc__, args) - if parsed_args['--debug']: - logging.basicConfig(level=logging.DEBUG) - elif parsed_args['--verbose']: - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.WARNING) - - with open(parsed_args['']) as f: - data = yaml.load(f.read()) - - data = transform_fsm(data) - - with open(parsed_args[''], 'w') as f: - f.write(yaml.safe_dump(data, default_flow_style=False)) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) - diff --git a/awx/ui/client/src/network-ui/util.js b/awx/ui/client/src/network-ui/util.js deleted file mode 100644 index f732f7bcf590..000000000000 --- a/awx/ui/client/src/network-ui/util.js +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var math = require('mathjs'); - -function noop () { -} -exports.noop = noop; - -function natural_numbers (start) { - var counter = start; - return function () {return counter += 1;}; -} -exports.natural_numbers = natural_numbers; - - -function distance (x1, y1, x2, y2) { - - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); -} -exports.distance = distance; - -function pDistanceLine(x, y, x1, y1, x2, y2) { - //Code from http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment - //Joshua - // Find the dot product of two vectors , - // Divide by the length squared of - // Use scalar project to find param - // - - var A = x - x1; - var B = y - y1; - var C = x2 - x1; - var D = y2 - y1; - - var dot = A * C + B * D; - var len_sq = C * C + D * D; - var param = -1; - if (len_sq !== 0) { - //in case of 0 length line - param = dot / len_sq; - } - - var xx, yy; - - //Find a point xx, yy where the projection and the vector intersect. - //If less than 0 use x1, y1 as the closest point. - //If less than 1 use x2, y2 as the closest point. - //If between 0 and 1 use the projection intersection xx, yy - if (param < 0) { - xx = x1; - yy = y1; - } - else if (param > 1) { - xx = x2; - yy = y2; - } - else { - xx = x1 + param * C; - yy = y1 + param * D; - } - - return {x1:x, y1:y, x2: xx, y2: yy}; -} -exports.pDistanceLine = pDistanceLine; - -function pDistance(x, y, x1, y1, x2, y2) { - //Code from http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment - //Joshua - // Find the dot product of two vectors , - // Divide by the length squared of - // Use scalar project to find param - // - - var A = x - x1; - var B = y - y1; - var C = x2 - x1; - var D = y2 - y1; - - var dot = A * C + B * D; - var len_sq = C * C + D * D; - var param = -1; - if (len_sq !== 0) { - //in case of 0 length line - param = dot / len_sq; - } - - var xx, yy; - - //Find a point xx, yy where the projection and the vector intersect. - //If less than 0 use x1, y1 as the closest point. - //If less than 1 use x2, y2 as the closest point. - //If between 0 and 1 use the projection intersection xx, yy - if (param < 0) { - xx = x1; - yy = y1; - } - else if (param > 1) { - xx = x2; - yy = y2; - } - else { - xx = x1 + param * C; - yy = y1 + param * D; - } - - var dx = x - xx; - var dy = y - yy; - return Math.sqrt(dx * dx + dy * dy); -} -exports.pDistance = pDistance; - - -function cross_z_pos(x, y, x1, y1, x2, y2) { - var A = x - x1; - var B = y - y1; - var C = x2 - x1; - var D = y2 - y1; - - return math.cross([A, B, 0], [C, D, 0])[2] > 0; -} -exports.cross_z_pos = cross_z_pos; - -function intersection (x1, y1, x2, y2, x3, y3, x4, y4) { - //Find the point where lines through x1, y1, x2, y2 and x3, y3, x4, y4 intersect. - // - - var Aslope; - var Aintercept; - var Bslope; - var Bintercept; - - if ((x2 - x1) !== 0 && (x4 - x3) !== 0) { - Aslope = (y2 - y1)/(x2 - x1); - Aintercept = y1 - Aslope * x1; - - Bslope = (y4 - y3)/(x4 - x3); - Bintercept = y3 - Bslope * x3; - - var xi = (Bintercept - Aintercept) / (Aslope - Bslope); - var yi = Bslope * xi + Bintercept; - return {x: xi, y: yi}; - } - if ((x2 - x1) === 0 && (x4 - x3) === 0) { - return {x: null, y: null}; - } - if ((x2 - x1) === 0) { - Bslope = (y4 - y3)/(x4 - x3); - Bintercept = y3 - Bslope * x3; - return {x: x1, y: Bslope * x1 + Bintercept}; - } - if ((x4 - x3) === 0) { - Aslope = (y2 - y1)/(x2 - x1); - Aintercept = y1 - Aslope * x1; - return {x: x3, y: Aslope * x3 + Aintercept}; - } -} -exports.intersection = intersection; - - -function pCase(x, y, x1, y1, x2, y2) { - //Code from http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment - //Joshua - // Find the dot product of two vectors , - // Divide by the length squared of - // Use scalar project to find param - // - - var A = x - x1; - var B = y - y1; - var C = x2 - x1; - var D = y2 - y1; - - var dot = A * C + B * D; - var len_sq = C * C + D * D; - var param = -1; - if (len_sq !== 0) { - //in case of 0 length line - param = dot / len_sq; - } - - return param; -} -exports.pCase = pCase; diff --git a/awx/ui/client/src/network-ui/vendor/svg-crowbar.js b/awx/ui/client/src/network-ui/vendor/svg-crowbar.js deleted file mode 100644 index bba30938010d..000000000000 --- a/awx/ui/client/src/network-ui/vendor/svg-crowbar.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * @license svg-crowbar - * (c) 2013 The New York Times - * License: MIT - */ -function svg_crowbar () { - var doctype = ''; - - window.URL = (window.URL || window.webkitURL); - - var body = document.body; - - var prefix = { - xmlns: "http://www.w3.org/2000/xmlns/", - xlink: "http://www.w3.org/1999/xlink", - svg: "http://www.w3.org/2000/svg" - }; - - initialize(); - - function initialize() { - var documents = [window.document], - SVGSources = [], - iframes = document.querySelectorAll("iframe"), - objects = document.querySelectorAll("object"); - - [].forEach.call(iframes, function(el) { - try { - if (el.contentDocument) { - documents.push(el.contentDocument); - } - } catch(err) { - console.log(err); - } - }); - - [].forEach.call(objects, function(el) { - try { - if (el.contentDocument) { - documents.push(el.contentDocument); - } - } catch(err) { - console.log(err); - } - }); - - documents.forEach(function(doc) { - var styles = getStyles(doc); - var newSources = getSources(doc, styles); - // because of prototype on NYT pages - for (var i = 0; i < newSources.length; i++) { - SVGSources.push(newSources[i]); - } - }); - if (SVGSources.length > 1) { - createPopover(SVGSources); - } else if (SVGSources.length > 0) { - download(SVGSources[0]); - } else { - alert("The Crowbar couldn’t find any SVG nodes."); - } - } - - function createPopover(sources) { - cleanup(); - - sources.forEach(function(s1) { - sources.forEach(function(s2) { - if (s1 !== s2) { - if ((Math.abs(s1.top - s2.top) < 38) && (Math.abs(s1.left - s2.left) < 38)) { - s2.top += 38; - s2.left += 38; - } - } - }); - }); - - var buttonsContainer = document.createElement("div"); - body.appendChild(buttonsContainer); - - buttonsContainer.setAttribute("class", "svg-crowbar"); - buttonsContainer.style["z-index"] = 1e7; - buttonsContainer.style.position = "absolute"; - buttonsContainer.style.top = 0; - buttonsContainer.style.left = 0; - - - - var background = document.createElement("div"); - body.appendChild(background); - - background.setAttribute("class", "svg-crowbar"); - background.style.background = "rgba(255, 255, 255, 0.7)"; - background.style.position = "fixed"; - background.style.left = 0; - background.style.top = 0; - background.style.width = "100%"; - background.style.height = "100%"; - - sources.forEach(function(d, i) { - var buttonWrapper = document.createElement("div"); - buttonsContainer.appendChild(buttonWrapper); - buttonWrapper.setAttribute("class", "svg-crowbar"); - buttonWrapper.style.position = "absolute"; - buttonWrapper.style.top = (d.top + document.body.scrollTop) + "px"; - buttonWrapper.style.left = (document.body.scrollLeft + d.left) + "px"; - buttonWrapper.style.padding = "4px"; - buttonWrapper.style["border-radius"] = "3px"; - buttonWrapper.style.color = "white"; - buttonWrapper.style["text-align"] = "center"; - buttonWrapper.style["font-family"] = "'Helvetica Neue'"; - buttonWrapper.style.background = "rgba(0, 0, 0, 0.8)"; - buttonWrapper.style["box-shadow"] = "0px 4px 18px rgba(0, 0, 0, 0.4)"; - buttonWrapper.style.cursor = "move"; - buttonWrapper.textContent = "SVG #" + i + ": " + (d.id ? "#" + d.id : "") + (d.class ? "." + d.class : ""); - - var button = document.createElement("button"); - buttonWrapper.appendChild(button); - button.setAttribute("data-source-id", i); - button.style.width = "150px"; - button.style["font-size"] = "12px"; - button.style["line-height"] = "1.4em"; - button.style.margin = "5px 0 0 0"; - button.textContent = "Download"; - - button.onclick = function() { - // console.log(el, d, i, sources) - download(d); - }; - - }); - - } - - function cleanup() { - var crowbarElements = document.querySelectorAll(".svg-crowbar"); - - [].forEach.call(crowbarElements, function(el) { - el.parentNode.removeChild(el); - }); - } - - - function getSources(doc, styles) { - var svgInfo = [], - svgs = doc.querySelectorAll("svg"); - - styles = (styles === undefined) ? "" : styles; - - [].forEach.call(svgs, function (svg) { - - svg.setAttribute("version", "1.1"); - - var defsEl = document.createElement("defs"); - svg.insertBefore(defsEl, svg.firstChild); //TODO .insert("defs", ":first-child") - // defsEl.setAttribute("class", "svg-crowbar"); - - var styleEl = document.createElement("style"); - defsEl.appendChild(styleEl); - styleEl.setAttribute("type", "text/css"); - - - // removing attributes so they aren't doubled up - svg.removeAttribute("xmlns"); - svg.removeAttribute("xlink"); - - // These are needed for the svg - if (!svg.hasAttributeNS(prefix.xmlns, "xmlns")) { - svg.setAttributeNS(prefix.xmlns, "xmlns", prefix.svg); - } - - if (!svg.hasAttributeNS(prefix.xmlns, "xmlns:xlink")) { - svg.setAttributeNS(prefix.xmlns, "xmlns:xlink", prefix.xlink); - } - - var source = (new XMLSerializer()).serializeToString(svg).replace('', ''); - var rect = svg.getBoundingClientRect(); - svgInfo.push({ - top: rect.top, - left: rect.left, - width: rect.width, - height: rect.height, - class: svg.getAttribute("class"), - id: svg.getAttribute("id"), - childElementCount: svg.childElementCount, - source: [doctype + source] - }); - }); - return svgInfo; - } - - function download(source) { - var filename = "untitled"; - - if (source.id) { - filename = source.id; - } else if (source.class) { - filename = source.class; - } else if (window.document.title) { - filename = window.document.title.replace(/[^a-z0-9]/gi, '-').toLowerCase(); - } - - var url = window.URL.createObjectURL(new Blob(source.source, { "type" : "text\/xml" })); - - var a = document.createElement("a"); - body.appendChild(a); - a.setAttribute("class", "svg-crowbar"); - a.setAttribute("download", filename + ".svg"); - a.setAttribute("href", url); - a.style.display = "none"; - a.click(); - - setTimeout(function() { - window.URL.revokeObjectURL(url); - }, 10); - } - - function getStyles(doc) { - var styles = "", - styleSheets = doc.styleSheets; - - if (styleSheets) { - for (var i = 0; i < styleSheets.length; i++) { - processStyleSheet(styleSheets[i]); - } - } - - function processStyleSheet(ss) { - if (ss.cssRules) { - for (var i = 0; i < ss.cssRules.length; i++) { - var rule = ss.cssRules[i]; - if (rule.type === 3) { - // Import Rule - processStyleSheet(rule.styleSheet); - } else { - // hack for illustrator crashing on descendent selectors - if (rule.selectorText) { - if (rule.selectorText.indexOf(">") === -1) { - styles += "\n" + rule.cssText; - } - } - } - } - } - } - return styles; - } - -} -exports.svg_crowbar = svg_crowbar; diff --git a/awx/ui/client/src/network-ui/view.fsm.js b/awx/ui/client/src/network-ui/view.fsm.js deleted file mode 100644 index b1e047c1da1f..000000000000 --- a/awx/ui/client/src/network-ui/view.fsm.js +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ -var inherits = require('inherits'); -var fsm = require('./fsm.js'); - -function _State () { -} -inherits(_State, fsm._State); - -function _Ready () { - this.name = 'Ready'; -} -inherits(_Ready, _State); -var Ready = new _Ready(); -exports.Ready = Ready; - -function _Start () { - this.name = 'Start'; -} -inherits(_Start, _State); -var Start = new _Start(); -exports.Start = Start; - -function _Scale () { - this.name = 'Scale'; -} -inherits(_Scale, _State); -var Scale = new _Scale(); -exports.Scale = Scale; - -function _Pressed () { - this.name = 'Pressed'; -} -inherits(_Pressed, _State); -var Pressed = new _Pressed(); -exports.Pressed = Pressed; - -function _Pan () { - this.name = 'Pan'; -} -inherits(_Pan, _State); -var Pan = new _Pan(); -exports.Pan = Pan; - - - - -_Ready.prototype.onMouseDown = function (controller) { - - controller.scope.pressedX = controller.scope.mouseX; - controller.scope.pressedY = controller.scope.mouseY; - controller.scope.lastPanX = controller.scope.panX; - controller.scope.lastPanY = controller.scope.panY; - controller.scope.closeDetailsPanel(); - controller.changeState(Pressed); - -}; -_Ready.prototype.onMouseDown.transitions = ['Pressed']; - -_Ready.prototype.onMouseWheel = function (controller, msg_type, $event) { - - controller.changeState(Scale); - controller.handle_message(msg_type, $event); -}; -_Ready.prototype.onMouseWheel.transitions = ['Scale']; - - -_Start.prototype.start = function (controller) { - - controller.changeState(Ready); - -}; -_Start.prototype.start.transitions = ['Ready']; - -_Scale.prototype.onMouseWheel = function (controller, msg_type, message) { - var delta = message[1]; - if (Math.abs(delta) > 100) { - delta = delta / 10; - } - var new_scale = Math.max(controller.scope.MIN_ZOOM, - Math.min(controller.scope.MAX_ZOOM, - (controller.scope.current_scale + delta / (100 / controller.scope.current_scale)))); - var new_panX = controller.scope.mouseX - new_scale * ((controller.scope.mouseX - controller.scope.panX) / controller.scope.current_scale); - var new_panY = controller.scope.mouseY - new_scale * ((controller.scope.mouseY - controller.scope.panY) / controller.scope.current_scale); - controller.scope.updateScaledXY(); - controller.scope.current_scale = new_scale; - controller.scope.panX = new_panX; - controller.scope.panY = new_panY; - var item = controller.scope.context_menus[0]; - item.enabled = false; - controller.scope.$emit('awxNet-UpdateZoomWidget', controller.scope.current_scale, true); - controller.scope.updatePanAndScale(); - controller.changeState(Ready); -}; -_Scale.prototype.onMouseWheel.transitions = ['Ready']; - - -_Pressed.prototype.onMouseUp = function (controller) { - - controller.changeState(Ready); - -}; -_Pressed.prototype.onMouseUp.transitions = ['Ready']; - -_Pressed.prototype.onMouseMove = function (controller, msg_type, $event) { - - controller.changeState(Pan); - controller.handle_message(msg_type, $event); -}; -_Pressed.prototype.onMouseMove.transitions = ['Pan']; - -_Pan.prototype.onMouseMove = function (controller) { - - controller.scope.panX = (controller.scope.mouseX - controller.scope.pressedX) + controller.scope.lastPanX; - controller.scope.panY = (controller.scope.mouseY - controller.scope.pressedY) + controller.scope.lastPanY; - controller.scope.updateScaledXY(); - controller.scope.updatePanAndScale(); -}; - -_Pan.prototype.onMouseUp = function (controller) { - - controller.changeState(Ready); - -}; -_Pan.prototype.onMouseUp.transitions = ['Ready']; diff --git a/awx/ui/client/src/network-ui/zoom-widget/main.js b/awx/ui/client/src/network-ui/zoom-widget/main.js deleted file mode 100644 index 518ec0976bfe..000000000000 --- a/awx/ui/client/src/network-ui/zoom-widget/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import awxNetZoomWidget from './zoom.directive'; - -export default - angular.module('networkZoomWidget', []) - .directive('awxNetZoomWidget', awxNetZoomWidget); diff --git a/awx/ui/client/src/network-ui/zoom-widget/zoom.block.less b/awx/ui/client/src/network-ui/zoom-widget/zoom.block.less deleted file mode 100644 index d827dcbe1e70..000000000000 --- a/awx/ui/client/src/network-ui/zoom-widget/zoom.block.less +++ /dev/null @@ -1,59 +0,0 @@ -.Networking-zoomPanel{ - position: absolute; - bottom:0px; - right:0px; - border-top: 1px solid @btn-bord; - border-left: 1px solid @btn-bord; - width: 200px; - height:60px; -} - -.Networking-zoomPanel--expanded{ - right:400px; -} - -.NetworkingControls-manualControls{ - position: absolute; - background-color: @default-bg; - padding-left:15px; - width: 100%; -} - -.NetworkingControls-Zoom{ - display: flex; - flex: 1 0 auto; -} - -.NetworkingControls-Zoom--button { - line-height: 60px; - color: @default-icon; -} - -.NetworkingControls-Zoom--button:hover { - color: @default-link-hov; -} - -.NetworkingControls-zoomSlider { - width: 150px; - padding-left: 8px; - padding-right: 8px; -} - -.NetworkingControls-zoomPercentage { - text-align: center; - font-size: 0.7em; - height: 24px; - line-height: 24px; -} - -.ui-slider-handle.ui-state-default.ui-corner-all { - border-radius: 50%; - border-color: @default-link; - background: @default-link; -} - -.ui-slider-handle.ui-state-default.ui-corner-all:hover, -.ui-slider-handle.ui-state-default.ui-corner-all:active { - border-color: @default-link-hov; - background: @default-link-hov; -} diff --git a/awx/ui/client/src/network-ui/zoom-widget/zoom.directive.js b/awx/ui/client/src/network-ui/zoom-widget/zoom.directive.js deleted file mode 100644 index b4ba02398802..000000000000 --- a/awx/ui/client/src/network-ui/zoom-widget/zoom.directive.js +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************* - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import detailsController from './details.controller'; - -const templateUrl = require('~network-ui/zoom-widget/zoom.partial.html'); - -export default [ - function() { - return { - templateUrl, - restrict: 'E', - link(scope){ - - function init() { - scope.zoom = 100; - $( "#networking-slider" ).slider({ - value:100, - min: 0, - max: 200, - step: 10, - slide: function( event, ui ) { - scope.zoom = ui.value; - scope.zoomTo(); - } - }); - } - - init(); - - scope.$parent.$on('awxNet-UpdateZoomWidget', (e, scale, updateBoolean) => { - if(scale && updateBoolean){ - // scale is included, meaning this was triggered by - // the view FSM's onMouseWheel transition - let sliderPercent = 120 * (Math.log10(scale) + 1); - scope.zoom = Math.round(sliderPercent / 10) * 10; - } - $("#networking-slider").slider('value', scope.zoom); - }); - - scope.zoomTo = function() { - scope.zoom = Math.ceil(scope.zoom / 10) * 10; - this.$parent.$broadcast('awxNet-zoom', scope.zoom); - }; - - scope.zoomOut = function(){ - scope.zoom = scope.zoom - 10 > 0 ? scope.zoom - 10 : 0; - this.$parent.$broadcast('awxNet-zoom', scope.zoom); - }; - - scope.zoomIn = function(){ - scope.zoom = scope.zoom + 10 < 200 ? scope.zoom + 10 : 200; - this.$parent.$broadcast('awxNet-zoom', scope.zoom); - }; - } - }; -}]; diff --git a/awx/ui/client/src/network-ui/zoom-widget/zoom.partial.html b/awx/ui/client/src/network-ui/zoom-widget/zoom.partial.html deleted file mode 100644 index 09fa5acb70ae..000000000000 --- a/awx/ui/client/src/network-ui/zoom-widget/zoom.partial.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
-
- -
-
-
{{zoom}}%
-
-
-
- -
-
-
diff --git a/awx/ui/client/src/ng-console.js b/awx/ui/client/src/ng-console.js deleted file mode 100644 index 98c186ffeca8..000000000000 --- a/awx/ui/client/src/ng-console.js +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// THIS FILE ONLY INCLUDED IN DEBUG BUILDS -// -// To use: -// -// Open a console in Chrome DevTools and load this -// script with: -// -// require('tower/ng-console'); -// -// Then go to the Elements tab and drill down to any -// element within the angular app. Go back to the console -// and you can access the scope for the selected element -// using the variable $scope. -// -var ngAppElem = angular.element(document.querySelector('[ng-app]') || document); - -window.injector = ngAppElem.injector(); -window.inject = window.injector.invoke; -window.$rootScope = ngAppElem.scope(); - -// getService('auth') will create a variable `auth` assigned to the service `auth`. -// -window.getService = function getService(serviceName) { - window.inject([serviceName, function (s) {window[serviceName] = s;}]); -}; - -Object.defineProperty(window, '$scope', { - get: function () { - var elem = angular.element(window.__commandLineAPI.$0); - return elem.isolateScope() || elem.scope(); - }, -}); - -/** - * USAGE - * - * First copy the script and paste it in Chrome DevTools in Sources -> left pane -> Snippets. - * Then, after loading an Angular page, right click on the snippet and choose "run". - * Afterwards, you have the following available in the console: - * - * 1) $rootScope - * 2) inject(function ($q, $compile) { ...use $q and $compile here... }); - * 3) click on an element in DevTools; now $scope in the console points at the element scope (isolate if one exists). - * - * Enjoy! - */ diff --git a/awx/ui/client/src/notifications/add/add.controller.js b/awx/ui/client/src/notifications/add/add.controller.js deleted file mode 100644 index 11f7eb1aa176..000000000000 --- a/awx/ui/client/src/notifications/add/add.controller.js +++ /dev/null @@ -1,233 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'Wait', 'NotificationsFormObject', - 'ProcessErrors', 'GetBasePath', 'Alert', - 'GenerateForm', '$scope', '$state', 'CreateSelect2', 'GetChoices', - 'NotificationsTypeChange', 'ParseTypeChange', 'i18n', - function( - Rest, Wait, NotificationsFormObject, - ProcessErrors, GetBasePath, Alert, - GenerateForm, $scope, $state, CreateSelect2, GetChoices, - NotificationsTypeChange, ParseTypeChange, i18n - ) { - - var generator = GenerateForm, - form = NotificationsFormObject, - url = GetBasePath('notification_templates'); - - init(); - - function init() { - Rest.setUrl(GetBasePath('projects')); - Rest.options() - .then(({data}) => { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a notification template.', 'alert-info'); - } - }); - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - GetChoices({ - scope: $scope, - url: url, - field: 'notification_type', - variable: 'notification_type_options', - callback: 'choicesReady' - }); - } - - if ($state.params && $state.params.organization_id) { - let id = $state.params.organization_id, - url = GetBasePath('organizations') + id + '/'; - - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - $scope.organization_name = data.name; - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: `Failed to retrieve organization. GET status: ${status}` - }); - }); - } - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReady', function() { - var i; - for (i = 0; i < $scope.notification_type_options.length; i++) { - if ($scope.notification_type_options[i].value === '') { - $scope.notification_type_options[i].value = "manual"; - break; - } - } - CreateSelect2({ - element: '#notification_template_notification_type', - multiple: false - }); - - $scope.hipchatColors = [i18n._('Gray'), i18n._('Green'), i18n._('Purple'), i18n._('Red'), i18n._('Yellow'), i18n._('Random')]; - CreateSelect2({ - element: '#notification_template_color', - multiple: false - }); - }); - - $scope.$watch('headers', function validate_headers(str) { - try { - let headers = JSON.parse(str); - if (_.isObject(headers) && !_.isArray(headers)) { - let valid = true; - for (let k in headers) { - if (_.isObject(headers[k])) { - valid = false; - } - if (headers[k] === null) { - valid = false; - } - } - $scope.notification_template_form.headers.$setValidity('json', valid); - return; - } - } catch (err) {} - - $scope.notification_template_form.headers.$setValidity('json', false); - }); - - $scope.typeChange = function() { - for (var fld in form.fields) { - if (form.fields[fld] && form.fields[fld].subForm) { - if (form.fields[fld].type === 'checkbox_group' && form.fields[fld].fields) { - // Need to loop across the groups fields to null them out - for (var i = 0; i < form.fields[fld].fields.length; i++) { - // Pull the name out of the object (array of objects) - var subFldName = form.fields[fld].fields[i].name; - $scope[subFldName] = null; - $scope.notification_template_form[subFldName].$setPristine(); - } - } else { - $scope[fld] = null; - $scope.notification_template_form[fld].$setPristine(); - } - } - } - - NotificationsTypeChange.getDetailFields($scope.notification_type.value).forEach(function(field) { - $scope[field[0]] = field[1]; - }); - - - $scope.parse_type = 'json'; - if (!$scope.headers) { - $scope.headers = "{\n}"; - } - ParseTypeChange({ - scope: $scope, - parse_variable: 'parse_type', - variable: 'headers', - field_id: 'notification_template_headers' - }); - }; - - $scope.emailOptionsChange = function () { - if ($scope.email_options === 'use_ssl') { - if ($scope.use_ssl) { - $scope.email_options = null; - $scope.use_ssl = false; - return; - } - - $scope.use_ssl = true; - $scope.use_tls = false; - } - else if ($scope.email_options === 'use_tls') { - if ($scope.use_tls) { - $scope.email_options = null; - $scope.use_tls = false; - return; - } - - $scope.use_ssl = false; - $scope.use_tls = true; - } - }; - - // Save - $scope.formSave = function() { - var params, - v = $scope.notification_type.value; - - generator.clearApiErrors($scope); - params = { - "name": $scope.name, - "description": $scope.description, - "organization": $scope.organization, - "notification_type": v, - "notification_configuration": {} - }; - - function processValue(value, i, field) { - if (field.type === 'textarea') { - if (field.name === 'headers') { - $scope[i] = JSON.parse($scope[i]); - } else { - $scope[i] = $scope[i].toString().split('\n'); - } - } - if (field.type === 'checkbox') { - $scope[i] = Boolean($scope[i]); - } - if (field.type === 'number') { - $scope[i] = Number($scope[i]); - } - if (i === "username" && $scope.notification_type.value === "email" && value === null) { - $scope[i] = ""; - } - if (field.type === 'sensitive' && value === null) { - $scope[i] = ""; - } - return $scope[i]; - } - - params.notification_configuration = _.object(Object.keys(form.fields) - .filter(i => (form.fields[i].ngShow && form.fields[i].ngShow.indexOf(v) > -1)) - .map(i => [i, processValue($scope[i], i, form.fields[i])])); - - delete params.notification_configuration.email_options; - - for(var j = 0; j < form.fields.email_options.options.length; j++) { - if(form.fields.email_options.options[j].ngShow && form.fields.email_options.options[j].ngShow.indexOf(v) > -1) { - params.notification_configuration[form.fields.email_options.options[j].value] = Boolean($scope[form.fields.email_options.options[j].value]); - } - } - - Wait('start'); - Rest.setUrl(url); - Rest.post(params) - .then(() => { - $state.go('notifications', {}, { reload: true }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new notifier. POST returned status: ' + status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('notifications'); - }; - - } -]; diff --git a/awx/ui/client/src/notifications/add/main.js b/awx/ui/client/src/notifications/add/main.js deleted file mode 100644 index 104849060bb1..000000000000 --- a/awx/ui/client/src/notifications/add/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './add.controller'; - -export default - angular.module('notificationsAdd', []) - .controller('notificationsAddController', controller); diff --git a/awx/ui/client/src/notifications/edit/edit.controller.js b/awx/ui/client/src/notifications/edit/edit.controller.js deleted file mode 100644 index 0d871dd26f54..000000000000 --- a/awx/ui/client/src/notifications/edit/edit.controller.js +++ /dev/null @@ -1,301 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'Wait', - 'NotificationsFormObject', 'ProcessErrors', 'GetBasePath', - 'GenerateForm', - 'notification_template', - '$scope', '$state', 'GetChoices', 'CreateSelect2', 'Empty', - 'NotificationsTypeChange', 'ParseTypeChange', 'i18n', - function( - Rest, Wait, - NotificationsFormObject, ProcessErrors, GetBasePath, - GenerateForm, - notification_template, - $scope, $state, GetChoices, CreateSelect2, Empty, - NotificationsTypeChange, ParseTypeChange, i18n - ) { - var generator = GenerateForm, - id = notification_template.id, - form = NotificationsFormObject, - master = {}, - url = GetBasePath('notification_templates'); - - init(); - - function init() { - $scope.notification_template = notification_template; - - $scope.$watch('notification_template.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAdd = false; - } - }); - - GetChoices({ - scope: $scope, - url: url, - field: 'notification_type', - variable: 'notification_type_options', - callback: 'choicesReady' - }); - } - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReady', function() { - var i; - for (i = 0; i < $scope.notification_type_options.length; i++) { - if ($scope.notification_type_options[i].value === '') { - $scope.notification_type_options[i].value = "manual"; - break; - } - } - - Wait('start'); - Rest.setUrl(url + id + '/'); - Rest.get() - .then(({data}) => { - var fld; - for (fld in form.fields) { - if (data[fld]) { - $scope[fld] = data[fld]; - master[fld] = data[fld]; - } - - if(form.fields[fld].type === 'radio_group') { - if(data.notification_configuration.use_ssl === true){ - $scope.email_options = "use_ssl"; - master.email_options = "use_ssl"; - $scope.use_ssl = true; - master.use_ssl = true; - $scope.use_tls = false; - master.use_tls = false; - } - if(data.notification_configuration.use_tls === true){ - $scope.email_options = "use_tls"; - master.email_options = "use_tls"; - $scope.use_ssl = false; - master.use_ssl = false; - $scope.use_tls = true; - master.use_tls = true; - } - } - else { - if (data.notification_configuration[fld]) { - $scope[fld] = data.notification_configuration[fld]; - master[fld] = data.notification_configuration[fld]; - - if (form.fields[fld].type === 'textarea') { - if (form.fields[fld].name === 'headers') { - $scope[fld] = JSON.stringify($scope[fld], null, 2); - } else { - $scope[fld] = $scope[fld].join('\n'); - } - } - } - - if (form.fields[fld].sourceModel && data.summary_fields && - data.summary_fields[form.fields[fld].sourceModel]) { - $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - } - } - } - data.notification_type = (Empty(data.notification_type)) ? '' : data.notification_type; - for (var i = 0; i < $scope.notification_type_options.length; i++) { - if ($scope.notification_type_options[i].value === data.notification_type) { - $scope.notification_type = $scope.notification_type_options[i]; - break; - } - } - - master.notification_type = $scope.notification_type; - CreateSelect2({ - element: '#notification_template_notification_type', - multiple: false - }); - - $scope.hipchatColors = [i18n._('Gray'), i18n._('Green'), i18n._('Purple'), i18n._('Red'), i18n._('Yellow'), i18n._('Random')]; - CreateSelect2({ - element: '#notification_template_color', - multiple: false - }); - NotificationsTypeChange.getDetailFields($scope.notification_type.value).forEach(function(field) { - $scope[field[0]] = field[1]; - }); - $scope.notification_obj = data; - - $scope.parse_type = 'json'; - if (!$scope.headers) { - $scope.headers = "{\n}"; - } - ParseTypeChange({ - scope: $scope, - parse_variable: 'parse_type', - variable: 'headers', - field_id: 'notification_template_headers', - }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to retrieve notification: ' + id + '. GET status: ' + status - }); - }); - }); - - - - $scope.$watch('headers', function validate_headers(str) { - try { - let headers = JSON.parse(str); - if (_.isObject(headers) && !_.isArray(headers)) { - let valid = true; - for (let k in headers) { - if (_.isObject(headers[k])) { - valid = false; - } - if (headers[k] === null) { - valid = false; - } - } - $scope.notification_template_form.headers.$setValidity('json', valid); - return; - } - } catch (err) {} - - $scope.notification_template_form.headers.$setValidity('json', false); - }); - - $scope.typeChange = function() { - for (var fld in form.fields) { - if (form.fields[fld] && form.fields[fld].subForm) { - if (form.fields[fld].type === 'checkbox_group' && form.fields[fld].fields) { - // Need to loop across the groups fields to null them out - for (var i = 0; i < form.fields[fld].fields.length; i++) { - // Pull the name out of the object (array of objects) - var subFldName = form.fields[fld].fields[i].name; - $scope[subFldName] = null; - $scope.notification_template_form[subFldName].$setPristine(); - } - } else { - $scope[fld] = null; - $scope.notification_template_form[fld].$setPristine(); - } - } - } - - NotificationsTypeChange.getDetailFields($scope.notification_type.value).forEach(function(field) { - $scope[field[0]] = field[1]; - }); - - $scope.parse_type = 'json'; - if (!$scope.headers) { - $scope.headers = "{\n}"; - } - ParseTypeChange({ - scope: $scope, - parse_variable: 'parse_type', - variable: 'headers', - field_id: 'notification_template_headers', - }); - }; - - $scope.emailOptionsChange = function () { - if ($scope.email_options === 'use_ssl') { - if ($scope.use_ssl) { - $scope.email_options = null; - $scope.use_ssl = false; - return; - } - - $scope.use_ssl = true; - $scope.use_tls = false; - } - else if ($scope.email_options === 'use_tls') { - if ($scope.use_tls) { - $scope.email_options = null; - $scope.use_tls = false; - return; - } - - $scope.use_ssl = false; - $scope.use_tls = true; - } - }; - - $scope.formSave = function() { - var params, - v = $scope.notification_type.value; - - generator.clearApiErrors($scope); - params = { - "name": $scope.name, - "description": $scope.description, - "organization": $scope.organization, - "notification_type": v, - "notification_configuration": {} - }; - - function processValue(value, i, field) { - if (field.type === 'textarea') { - if (field.name === 'headers') { - $scope[i] = JSON.parse($scope[i]); - } else { - $scope[i] = $scope[i].toString().split('\n'); - } - } - if (field.type === 'checkbox') { - $scope[i] = Boolean($scope[i]); - } - if (field.type === 'number') { - $scope[i] = Number($scope[i]); - } - if (i === "username" && $scope.notification_type.value === "email" && (value === null || value === undefined)) { - $scope[i] = ""; - } - if (field.type === 'sensitive' && (value === null || value === undefined)) { - $scope[i] = ""; - } - return $scope[i]; - } - - params.notification_configuration = _.object(Object.keys(form.fields) - .filter(i => (form.fields[i].ngShow && form.fields[i].ngShow.indexOf(v) > -1)) - .map(i => [i, processValue($scope[i], i, form.fields[i])])); - - delete params.notification_configuration.email_options; - - params.notification_configuration.use_ssl = Boolean($scope.use_ssl); - params.notification_configuration.use_tls = Boolean($scope.use_tls); - - Wait('start'); - Rest.setUrl(url + id + '/'); - Rest.put(params) - .then(() => { - $state.go('notifications', {}, { reload: true }); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new notification template. POST returned status: ' + status - }); - }); - }; - - - $scope.formCancel = function() { - $state.go('notifications'); - }; - - } -]; diff --git a/awx/ui/client/src/notifications/edit/main.js b/awx/ui/client/src/notifications/edit/main.js deleted file mode 100644 index 55865ede89a6..000000000000 --- a/awx/ui/client/src/notifications/edit/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './edit.controller'; - -export default - angular.module('notificationsEdit', []) - .controller('notificationsEditController', controller); diff --git a/awx/ui/client/src/notifications/main.js b/awx/ui/client/src/notifications/main.js deleted file mode 100644 index c1a2a559bea5..000000000000 --- a/awx/ui/client/src/notifications/main.js +++ /dev/null @@ -1,94 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -import notificationTemplatesList from './notification-templates-list/main'; -import notificationsAdd from './add/main'; -import notificationsEdit from './edit/main'; - -import list from './notificationTemplates.list'; -import form from './notificationTemplates.form'; -import notificationsList from './notifications.list'; -import toggleNotification from './shared/toggle-notification.factory'; -import notificationsListInit from './shared/notification-list-init.factory'; -import typeChange from './shared/type-change.service'; -import { N_ } from '../i18n'; - -export default -angular.module('notifications', [ - notificationTemplatesList.name, - notificationsAdd.name, - notificationsEdit.name - ]) - .factory('NotificationTemplatesList', list) - .factory('NotificationsFormObject', form) - .factory('NotificationsList', notificationsList) - .factory('ToggleNotification', toggleNotification) - .factory('NotificationsListInit', notificationsListInit) - .service('NotificationsTypeChange', typeChange) - .config(['$stateProvider', 'stateDefinitionsProvider', - function($stateProvider, stateDefinitionsProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(); - - // lazily generate a tree of substates which will replace this node in ui-router's stateRegistry - // see: stateDefinition.factory for usage documentation - $stateProvider.state({ - name: 'notifications.**', - url: '/notification_templates', - ncyBreadcrumb: { - label: N_("NOTIFICATIONS") - }, - lazyLoad: () => stateDefinitions.generateTree({ - parent: 'notifications', // top-most node in the generated tree - modes: ['add', 'edit'], // form nodes to generate - list: 'NotificationTemplatesList', - form: 'NotificationsFormObject', - controllers: { - list: 'notificationTemplatesListController', - add: 'notificationsAddController', - edit: 'notificationsEditController' - }, - urls: { - add: '/add?organization_id' - }, - resolve: { - edit: { - notification_template: ['$state', '$stateParams', '$q', - 'Rest', 'GetBasePath', 'ProcessErrors', - function($state, $stateParams, $q, rest, getBasePath, ProcessErrors) { - if ($stateParams.notification_template) { - return $q.when($stateParams.notification_template); - } - - var notificationTemplateId = $stateParams.notification_template_id; - - var url = getBasePath('notification_templates') + notificationTemplateId + '/'; - rest.setUrl(url); - return rest.get() - .then(function(data) { - return data.data; - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get inventory script info. GET returned status: ' + - response.status - }); - }); - } - ] - } - }, - data: { - activityStream: true, - activityStreamTarget: 'notification_template' - }, - ncyBreadcrumb: { - label: N_('NOTIFICATIONS') - } - }) - }); - } - ]); diff --git a/awx/ui/client/src/notifications/notification-templates-list/add-notifications-action.partial.html b/awx/ui/client/src/notifications/notification-templates-list/add-notifications-action.partial.html deleted file mode 100644 index af71530737f1..000000000000 --- a/awx/ui/client/src/notifications/notification-templates-list/add-notifications-action.partial.html +++ /dev/null @@ -1,4 +0,0 @@ -
diff --git a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js deleted file mode 100644 index 8e588d967193..000000000000 --- a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js +++ /dev/null @@ -1,225 +0,0 @@ - /************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['$scope', 'Wait', 'NotificationTemplatesList', - 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', - 'ngToast', '$filter', 'Dataset', 'rbacUiControlService', - 'i18n', 'NotificationTemplate', - function( - $scope, Wait, NotificationTemplatesList, - GetBasePath, Rest, ProcessErrors, Prompt, $state, - ngToast, $filter, Dataset, rbacUiControlService, - i18n, NotificationTemplate) { - - var defaultUrl = GetBasePath('notification_templates'), - list = NotificationTemplatesList; - - init(); - - function init() { - $scope.canAdd = false; - - rbacUiControlService.canAdd("notification_templates") - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - } - - $scope.$on(`notification_template_options`, function(event, data){ - $scope.options = data.data.actions.GET; - optionsRequestDataProcessing(); - }); - - $scope.$watchCollection("notification_templates", function() { - optionsRequestDataProcessing(); - } - ); - // iterate over the list and add fields like type label, after the - // OPTIONS request returns, or the list is sorted/paginated/searched. - function optionsRequestDataProcessing(){ - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - // Set the item type label - if (list.fields.notification_type && $scope.options && - $scope.options.hasOwnProperty('notification_type')) { - $scope.options.notification_type.choices.forEach(function(choice) { - if (choice[0] === item.notification_type) { - itm.type_label = choice[1]; - var recent_notifications = itm.summary_fields.recent_notifications; - itm.status = recent_notifications && recent_notifications.length > 0 ? recent_notifications[0].status : "none"; - } - }); - } - setStatus(itm); - }); - } - - function setStatus(notification_template) { - var html, recent_notifications = notification_template.summary_fields.recent_notifications; - if (recent_notifications.length > 0) { - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - html += "\n"; - - recent_notifications.forEach(function(row) { - html += "\n"; - html += ``; - html += "\n"; - html += "\n"; - }); - html += "\n"; - html += "
" + i18n._("Status") + "" + i18n._("Time") + "
" + ($filter('longDate')(row.created)).replace(/ /, '
') + "
\n"; - } else { - html = "

" + i18n._("No recent notifications.") + "

\n"; - } - notification_template.template_status_html = html; - } - - $scope.copyNotification = notificationTemplate => { - Wait('start'); - new NotificationTemplate('get', notificationTemplate.id) - .then(model => model.copy()) - .then(({ id }) => { - const params = { - notification_template_id: id, - notification_template: this.notification_templates - }; - $state.go('notifications.edit', params, { reload: true }); - }) - .catch(({ data, status }) => { - const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; - ProcessErrors($scope, data, status, null, params); - }) - .finally(() => Wait('stop')); - }; - - $scope.testNotification = function() { - var name = $filter('sanitize')(this.notification_template.name), - pending_retries = 10; - - Rest.setUrl(defaultUrl + this.notification_template.id + '/test/'); - Rest.post({}) - .then(function(data) { - if (data && data.data && data.data.notification) { - Wait('start'); - // Using a setTimeout here to wait for the - // notification to be processed and for a status - // to be returned from the API. - retrieveStatus(data.data.notification); - } else { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to notifcatin templates failed. Notification returned status: ' + status - }); - } - }) - .catch(function() { - ngToast.danger({ - content: ` ${name}: ` + i18n._('Notification Failed.'), - }); - }); - - function retrieveStatus(id) { - setTimeout(function() { - let url = GetBasePath('notifications') + id; - Rest.setUrl(url); - Rest.get() - .then(function(res) { - if (res && res.data && res.data.status && res.data.status === "successful") { - ngToast.success({ - content: ` ${name}: Notification sent.` - }); - $state.reload(); - } else if (res && res.data && res.data.status && res.data.status === "failed") { - ngToast.danger({ - content: ` ${name}: Notification failed.` - }); - $state.reload(); - } else if (res && res.data && res.data.status && res.data.status === "pending" && pending_retries > 0) { - pending_retries--; - retrieveStatus(id); - } else { - Wait('stop'); - ProcessErrors($scope, null, status, null, { - hdr: 'Error!', - msg: 'Call to test notifications failed.' - }); - } - - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get ' + url + '. GET status: ' + status - }); - }); - }, 5000); - } - }; - - - $scope.addNotification = function() { - $state.go('notifications.add'); - }; - - $scope.editNotification = function() { - $state.go('notifications.edit', { - notification_template_id: this.notification_template.id, - notification_template: this.notification_templates - }); - }; - - $scope.deleteNotification = function(id, name) { - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() - .then(() => { - - let reloadListStateParams = null; - - if($scope.notification_templates.length === 1 && $state.params.notification_template_search && !_.isEmpty($state.params.notification_template_search.page) && $state.params.notification_template_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.notification_template_search.page = (parseInt(reloadListStateParams.notification_template_search.page)-1).toString(); - } - - if (parseInt($state.params.notification_template_id) === id) { - $state.go("^", reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - Prompt({ - hdr: i18n._('Delete'), - resourceName: $filter('sanitize')(name), - body: '
' + i18n._('Are you sure you want to delete this notification template?') + '
', - action: action, - actionText: i18n._('DELETE') - }); - }; - } - ]; diff --git a/awx/ui/client/src/notifications/notification-templates-list/main.js b/awx/ui/client/src/notifications/notification-templates-list/main.js deleted file mode 100644 index 47adeea176c9..000000000000 --- a/awx/ui/client/src/notifications/notification-templates-list/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './list.controller'; - -export default - angular.module('notificationTemplatesList', []) - .controller('notificationTemplatesListController', controller); diff --git a/awx/ui/client/src/notifications/notificationTemplates.form.js b/awx/ui/client/src/notifications/notificationTemplates.form.js deleted file mode 100644 index e2b15ef77b81..000000000000 --- a/awx/ui/client/src/notifications/notificationTemplates.form.js +++ /dev/null @@ -1,498 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:CustomInventory - * @description This form is for adding/editing an organization -*/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW NOTIFICATION TEMPLATE'), - editTitle: '{{ name }}', - name: 'notification_template', - // I18N for "CREATE NOTIFICATION_TEMPLATE" - // on /#/notification_templates/add - breadcrumbName: i18n._('NOTIFICATION TEMPLATE'), - stateTree: 'notifications', - basePath: 'notification_templates', - showActions: true, - subFormTitles: { - typeSubForm: i18n._('Type Details'), - }, - - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - list: 'OrganizationList', - basePath: 'organizations', - sourceModel: 'organization', - sourceField: 'name', - required: true, - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - notification_type: { - label: i18n._('Type'), - type: 'select', - required: true, - class: 'NotificationsForm-typeSelect', - ngOptions: 'type.label for type in notification_type_options track by type.value', - ngChange: 'typeChange()', - hasSubForm: true, - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - username: { - label: i18n._('Username'), - type: 'text', - ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - password: { - labelBind: 'passwordLabel', - type: 'sensitive', - hasShowInputButton: true, - awRequiredWhen: { - reqExpression: "password_required" , - init: "false" - }, - ngShow: "notification_type.value == 'email' || notification_type.value == 'irc' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - host: { - label: i18n._('Host'), - type: 'text', - awRequiredWhen: { - reqExpression: "email_required", - init: "false" - }, - ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - recipients: { - label: i18n._('Recipient List'), - type: 'textarea', - rows: 3, - awPopOver: i18n._('Enter one email address per line to create a recipient list for this type of notification.'), - dataTitle: i18n._('Recipient List'), - dataPlacement: 'right', - dataContainer: "body", - awRequiredWhen: { - reqExpression: "email_required", - init: "false" - }, - ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - sender: { - label: i18n._('Sender Email'), - type: 'text', - awRequiredWhen: { - reqExpression: "email_required", - init: "false" - }, - ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - port: { - labelBind: 'portLabel', - type: 'number', - integer: true, - spinner: true, - 'class': "input-small", - min: 0, - awRequiredWhen: { - reqExpression: "port_required", - init: "false" - }, - ngShow: "notification_type.value == 'email' || notification_type.value == 'irc'", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - channels: { - label: i18n._('Destination Channels'), - type: 'textarea', - rows: 3, - awPopOver: i18n._('Enter one Slack channel per line. The pound symbol (#) is not required.'), - dataTitle: i18n._('Destination Channels'), - dataPlacement: 'right', - dataContainer: "body", - awRequiredWhen: { - reqExpression: "channel_required", - init: "false" - }, - ngShow: "notification_type.value == 'slack'", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - rooms: { - label: i18n._('Destination Channels'), - type: 'textarea', - rows: 3, - awPopOver: i18n._('Enter one HipChat channel per line. The pound symbol (#) is not required.'), - dataTitle: i18n._('Destination Channels'), - dataPlacement: 'right', - dataContainer: "body", - awRequiredWhen: { - reqExpression: "room_required", - init: "false" - }, - ngShow: "notification_type.value == 'hipchat'", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - token: { - labelBind: 'tokenLabel', - type: 'sensitive', - hasShowInputButton: true, - awRequiredWhen: { - reqExpression: "token_required", - init: "false" - }, - ngShow: "notification_type.value == 'slack' || notification_type.value == 'pagerduty' || notification_type.value == 'hipchat'", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - account_token: { - label: i18n._('Account Token'), - type: 'sensitive', - hasShowInputButton: true, - awRequiredWhen: { - reqExpression: "twilio_required", - init: "false" - }, - ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - from_number: { - label: i18n._('Source Phone Number'), - dataTitle: i18n._('Source Phone Number'), - type: 'text', - awPopOver: i18n._('Enter the number associated with the "Messaging Service" in Twilio in the format +18005550199.'), - awRequiredWhen: { - reqExpression: "twilio_required", - init: "false" - }, - ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - to_numbers: { - label: i18n._('Destination SMS Number'), - dataTitle: i18n._('Destination SMS Number'), - type: 'textarea', - rows: 3, - awPopOver: i18n._('Enter one phone number per line to specify where to route SMS messages.'), - dataPlacement: 'right', - dataContainer: "body", - awRequiredWhen: { - reqExpression: "twilio_required", - init: "false" - }, - ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - account_sid: { - label: i18n._('Account SID'), - type: 'text', - awRequiredWhen: { - reqExpression: "twilio_required", - init: "false" - }, - ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - subdomain: { - label: i18n._('Pagerduty subdomain'), - type: 'text', - awRequiredWhen: { - reqExpression: "pagerduty_required", - init: "false" - }, - ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - service_key: { - label: i18n._('API Service/Integration Key'), - type: 'text', - awRequiredWhen: { - reqExpression: "pagerduty_required", - init: "false" - }, - ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - client_name: { - label: i18n._('Client Identifier'), - type: 'text', - awRequiredWhen: { - reqExpression: "pagerduty_required", - init: "false" - }, - ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - api_url: { - label: 'API URL', - type: 'text', - placeholder: 'https://mycompany.hipchat.com', - awRequiredWhen: { - reqExpression: "hipchat_required", - init: "false" - }, - ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - message_from: { - label: i18n._('Notification Label'), - type: 'text', - awRequiredWhen: { - reqExpression: "hipchat_required", - init: "false" - }, - ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - color: { - label: i18n._('Notification Color'), - dataTitle: i18n._('Notification Color'), - type: 'select', - ngOptions: 'color for color in hipchatColors track by color', - awPopOver: i18n._('Specify a notification color. Acceptable colors are: yellow, green, red purple, gray or random.'), - awRequiredWhen: { - reqExpression: "hipchat_required", - init: "false" - }, - ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - notify: { - label: i18n._('Notify Channel'), - type: 'checkbox', - ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - url: { - label: i18n._('Target URL'), - type: 'text', - awRequiredWhen: { - reqExpression: "webhook_required", - init: "false" - }, - ngShow: "notification_type.value == 'webhook' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - headers: { - label: i18n._('HTTP Headers'), - dataTitle: i18n._('HTTP Headers'), - type: 'textarea', - name: 'headers', - rows: 5, - 'class': 'Form-formGroup--fullWidth', - awRequiredWhen: { - reqExpression: "webhook_required", - init: "false" - }, - awPopOver: i18n._('Specify HTTP Headers in JSON format. Refer to the Ansible Tower documentation for example syntax.'), - dataPlacement: 'right', - ngShow: "notification_type.value == 'webhook' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - mattermost_url: { - label: i18n._('Target URL'), - type: 'text', - awRequiredWhen: { - reqExpression: "mattermost_required", - init: "false" - }, - ngShow: "notification_type.value == 'mattermost' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - mattermost_username: { - label: i18n._('Username'), - type: 'text', - ngShow: "notification_type.value == 'mattermost' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - mattermost_channel: { - label: i18n._('Channel'), - type: 'text', - ngShow: "notification_type.value == 'mattermost' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - mattermost_icon_url: { - label: i18n._('Icon URL'), - type: 'text', - ngShow: "notification_type.value == 'mattermost' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - mattermost_no_verify_ssl: { - label: i18n._('Disable SSL Verification'), - type: 'checkbox', - ngShow: "notification_type.value == 'mattermost' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - rocketchat_url: { - label: i18n._('Target URL'), - type: 'text', - awRequiredWhen: { - reqExpression: "rocketchat_required", - init: "false" - }, - ngShow: "notification_type.value == 'rocketchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - rocketchat_username: { - label: i18n._('Username'), - type: 'text', - ngShow: "notification_type.value == 'rocketchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - rocketchat_icon_url: { - label: i18n._('Icon URL'), - type: 'text', - ngShow: "notification_type.value == 'rocketchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - rocketchat_no_verify_ssl: { - label: i18n._('Disable SSL Verification'), - type: 'checkbox', - ngShow: "notification_type.value == 'rocketchat' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - server: { - label: i18n._('IRC Server Address'), - type: 'text', - awRequiredWhen: { - reqExpression: "irc_required", - init: "false" - }, - ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - nickname: { - label: i18n._('IRC Nick'), - type: 'text', - awRequiredWhen: { - reqExpression: "irc_required", - init: "false" - }, - ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - targets: { - label: i18n._('Destination Channels or Users'), - type: 'textarea', - rows: 3, - awPopOver: i18n._('Enter one IRC channel or username per line. The pound symbol (#) for channels, and the at (@) symbol for users, are not required.'), - dataTitle: i18n._('Destination Channels or Users'), - dataPlacement: 'right', - dataContainer: "body", - awRequiredWhen: { - reqExpression: "irc_required", - init: "false" - }, - ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - use_ssl: { - label: i18n._('SSL Connection'), - type: 'checkbox', - ngShow: "notification_type.value == 'irc'", - subForm: 'typeSubForm', - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' - }, - email_options: { - label: i18n._('Options'), - type: 'radio_group', - subForm: 'typeSubForm', - ngShow: "notification_type.value == 'email'", - ngClick: "emailOptionsChange()", - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)', - options: [{ - value: 'use_tls', - label: i18n._('Use TLS'), - ngShow: "notification_type.value == 'email' ", - labelClass: 'NotificationsForm-radioButtons' - }, { - value: 'use_ssl', - label: i18n._('Use SSL'), - ngShow: "notification_type.value == 'email'", - labelClass: 'NotificationsForm-radioButtons' - }] - }, - hex_color: { - label: i18n._('Notification Color'), - dataTitle: i18n._('Notification Color'), - type: 'text', - subForm: 'typeSubForm', - ngShow: "notification_type.value == 'slack' ", - ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)', - awPopOver: i18n._('Specify a notification color. Acceptable colors are hex color code (example: #3af or #789abc) .') - } - }, - - buttons: { //for now always generates -
- -
ADD A NEW TEMPLATE
-
- - -
- - - - diff --git a/awx/ui/client/src/organizations/linkout/addUsers/main.js b/awx/ui/client/src/organizations/linkout/addUsers/main.js deleted file mode 100644 index 83604f2c7704..000000000000 --- a/awx/ui/client/src/organizations/linkout/addUsers/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import addUsersDirective from './addUsers.directive'; - -export default - angular.module('AddUsers', []) - .directive('addUsers', addUsersDirective); diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-admins.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-admins.controller.js deleted file mode 100644 index ab5908c041a8..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-admins.controller.js +++ /dev/null @@ -1,78 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$stateParams', '$scope', 'Rest', '$state', - '$compile', 'Wait', 'OrgAdminList', - 'OrgAdminsDataset', - 'Prompt', 'ProcessErrors', 'GetBasePath', '$filter', - function($stateParams, $scope, Rest, $state, - $compile, Wait, OrgAdminList, OrgAdminsDataset, Prompt, ProcessErrors, - GetBasePath, $filter) { - - var orgBase = GetBasePath('organizations'); - - init(); - - function init() { - // search init - $scope.list = OrgAdminList; - $scope.user_dataset = OrgAdminsDataset.data; - $scope.users = $scope.user_dataset.results; - - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - - $scope.orgRelatedUrls = data.related; - - }); - } - - $scope.addUsers = function() { - $compile("")($scope); - }; - - $scope.editUser = function(id) { - $state.go('users.edit', { user_id: id }); - }; - - $scope.deleteUser = function(id, name) { - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = orgBase + $stateParams.organization_id + '/admins/'; - Rest.setUrl(url); - Rest.post({ - id: id, - disassociate: true - }).then(() => { - $state.go('.', null, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - Prompt({ - hdr: 'Delete', - body: '
Are you sure you want to remove the following administrator from this organization?
' + $filter('sanitize')(name) + '
', - action: action, - actionText: 'DELETE' - }); - }; - - $scope.formCancel = function() { - $state.go('organizations'); - }; - - } -]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js deleted file mode 100644 index 57cf501c4d61..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js +++ /dev/null @@ -1,264 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', '$location', - '$stateParams', '$compile', '$filter', 'Rest', 'InventoryList', - 'OrgInventoryDataset', 'OrgInventoryList', - 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'i18n', - function($scope, $rootScope, $location, - $stateParams, $compile, $filter, Rest, InventoryList, - Dataset, OrgInventoryList, - ProcessErrors, GetBasePath, Wait, - Find, Empty, $state, i18n) { - - var list = OrgInventoryList, - orgBase = GetBasePath('organizations'); - - init(); - - function init() { - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $rootScope.flashMessage = null; - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - $scope.orgRelatedUrls = data.related; - - }); - - $scope.$watch('inventories', ()=>{ - _.forEach($scope.inventories, processInventoryRow); - }); - } - - function processInventoryRow(item) { - if (item.has_inventory_sources) { - if (item.inventory_sources_with_failures > 0) { - item.syncStatus = 'error'; - item.syncTip = item.inventory_sources_with_failures + ' groups with sync failures. Click for details'; - } else { - item.syncStatus = 'successful'; - item.syncTip = 'No inventory sync failures. Click for details.'; - } - } else { - item.syncStatus = 'na'; - item.syncTip = 'Not configured for inventory sync.'; - item.launch_class = "btn-disabled"; - } - if (item.has_active_failures) { - item.hostsStatus = 'eritemror'; - item.hostsTip = item.hosts_with_active_failures + ' hosts with failures. Click for details.'; - } else if (item.total_hosts) { - item.hostsStatus = 'successful'; - item.hostsTip = 'No hosts with failures. Click for details.'; - } else { - item.hostsStatus = 'none'; - item.hostsTip = 'Inventory contains 0 hosts.'; - } - - item.kind_label = item.kind === '' ? 'Inventory' : (item.kind === 'smart' ? i18n._('Smart Inventory'): i18n._('Inventory')); - - return item; - } - - function ellipsis(a) { - if (a.length > 20) { - return a.substr(0, 20) + '...'; - } - return a; - } - - function attachElem(event, html, title) { - var elem = $(event.target).parent(); - try { - elem.tooltip('hide'); - elem.popover('destroy'); - } catch (err) { - //ignore - } - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - $('.tooltip').each(function() { - // close any lingering tool tipss - $(this).hide(); - }); - elem.attr({ - "aw-pop-over": html, - "data-popover-title": title, - "data-placement": "right" - }); - $compile(elem)($scope); - elem.on('shown.bs.popover', function() { - $('.popover').each(function() { - $compile($(this))($scope); //make nested directives work! - }); - $('.popover-content, .popover-title').click(function() { - elem.popover('hide'); - }); - }); - elem.popover('show'); - } - - if ($scope.removeHostSummaryReady) { - $scope.removeHostSummaryReady(); - } - $scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) { - - var html, title = "Recent Jobs"; - Wait('stop'); - if (data.count > 0) { - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - html += "\n"; - - data.results.forEach(function(row) { - html += "\n"; - html += "\n"; - html += ""; - html += ""; - html += "\n"; - }); - html += "\n"; - html += "
StatusFinishedName
" + ($filter('longDate')(row.finished)).replace(/ /, '
') + "
" + ellipsis(row.name) + "
\n"; - } else { - html = "

No recent job data available for this inventory.

\n"; - } - attachElem(event, html, title); - }); - - if ($scope.removeGroupSummaryReady) { - $scope.removeGroupSummaryReady(); - } - $scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) { - var html, title; - - Wait('stop'); - - // Build the html for our popover - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - data.results.forEach(function(row) { - if (row.related.last_update) { - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - } else { - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - } - }); - html += "\n"; - html += "
StatusLast SyncGroup
" + ($filter('longDate')(row.last_updated)).replace(/ /, '
') + "
" + ellipsis(row.summary_fields.group.name) + "
NA" + ellipsis(row.summary_fields.group.name) + "
\n"; - title = "Sync Status"; - attachElem(event, html, title); - }); - - $scope.showGroupSummary = function(event, id) { - var inventory; - if (!Empty(id)) { - inventory = Find({ list: $scope.inventories, key: 'id', val: id }); - if (inventory.syncStatus !== 'na') { - Wait('start'); - Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5'); - Rest.get() - .then(({data}) => { - $scope.$emit('GroupSummaryReady', event, inventory, data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status - }); - }); - } - } - }; - - $scope.showHostSummary = function(event, id) { - var url, inventory; - if (!Empty(id)) { - inventory = Find({ list: $scope.inventories, key: 'id', val: id }); - if (inventory.total_hosts > 0) { - Wait('start'); - url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed="; - url += (inventory.has_active_failures) ? 'true' : "false"; - url += "&order_by=-finished&page_size=5"; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - $scope.$emit('HostSummaryReady', event, data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status - }); - }); - } - } - }; - - $scope.viewJob = function(url) { - // Pull the id out of the URL - var id = url.replace(/^\//, '').split('/')[3]; - $state.go('output', { id: id, type: 'inventory' }); - - }; - - $scope.editInventory = function (inventory) { - if(inventory.kind && inventory.kind === 'smart') { - $state.go('inventories.editSmartInventory', {smartinventory_id: inventory.id}); - } - else { - $state.go('inventories.edit', {inventory_id: inventory.id}); - } - }; - - // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status - $scope.viewJobs = function(id) { - $location.url('/jobs/?inventory__int=' + id); - }; - - $scope.viewFailedJobs = function(id) { - $location.url('/jobs/?inventory__int=' + id + '&status=failed'); - }; - - $scope.formCancel = function() { - $state.go('organizations'); - }; - - } -]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js deleted file mode 100644 index 67003502ced9..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js +++ /dev/null @@ -1,80 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', - '$stateParams', 'Rest', 'ProcessErrors', - 'GetBasePath', 'Wait', - '$state', 'OrgJobTemplateList', 'OrgJobTemplateDataset', 'QuerySet', - function($scope, $rootScope, - $stateParams, Rest, ProcessErrors, - GetBasePath, Wait, - $state, OrgJobTemplateList, Dataset, qs) { - - var list = OrgJobTemplateList, - orgBase = GetBasePath('organizations'); - - $scope.$on(`ws-jobs`, function () { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - qs.search(path, $state.params[`${list.iterator}_search`]) - .then(function(searchResponse) { - $scope[`${list.iterator}_dataset`] = searchResponse.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - }); - }); - - init(); - - function init() { - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - - $scope.orgRelatedUrls = data.related; - }); - } - - $scope.$on(`${list.iterator}_options`, function(event, data){ - $scope.options = data.data.actions.GET; - optionsRequestDataProcessing(); - }); - - $scope.$watchCollection(`${$scope.list.name}`, function() { - optionsRequestDataProcessing(); - } - ); - // iterate over the list and add fields like type label, after the - // OPTIONS request returns, or the list is sorted/paginated/searched - function optionsRequestDataProcessing(){ - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - - // Set the item type label - if (list.fields.type && $scope.options && $scope.options.hasOwnProperty('type')) { - $scope.options.type.choices.forEach(function(choice) { - if (choice[0] === item.type) { - itm.type_label = choice[1]; - } - }); - } - }); - } - - $scope.editJobTemplate = function(id) { - $state.go('templates.editJobTemplate', { job_template_id: id }); - }; - - $scope.scheduleJob = function(id) { - $state.go('templates.editJobTemplate.schedules', { id: id }); - }; - } -]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js deleted file mode 100644 index 48a59a967d12..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js +++ /dev/null @@ -1,313 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', '$log', '$stateParams', 'Rest', 'Alert', - 'OrgProjectList', 'OrgProjectDataset', 'ProcessErrors', 'GetBasePath', - 'ProjectUpdate', 'Wait', 'GetChoices', 'Empty', 'Find', 'GetProjectIcon', - 'GetProjectToolTip', '$filter', '$state', - function($scope, $rootScope, $log, $stateParams, Rest, Alert, - OrgProjectList, Dataset, ProcessErrors, GetBasePath, ProjectUpdate, - Wait, GetChoices, Empty, Find, GetProjectIcon, GetProjectToolTip, $filter, - $state) { - - var list = OrgProjectList, - projUrl, - choiceCount = 0, - orgBase = GetBasePath('organizations'), - projBase = GetBasePath('projects'); - - init(); - - function init() { - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $rootScope.flashMessage = null; - - $scope.$on('choicesReadyProjectList', function() { - Wait('stop'); - if ($scope.projects) { - $scope.projects.forEach(function(project, i) { - $scope.projects[i].statusIcon = GetProjectIcon(project.status); - $scope.projects[i].statusTip = GetProjectToolTip(project.status); - $scope.projects[i].scm_update_tooltip = "Get latest SCM revision"; - $scope.projects[i].scm_schedule_tooltip = "Schedule SCM revision updates"; - $scope.projects[i].scm_type_class = ""; - - if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') { - $scope.projects[i].statusTip = 'Canceled. Click for details'; - } - - if (project.status === 'running' || project.status === 'updating') { - $scope.projects[i].scm_update_tooltip = "SCM update currently running"; - $scope.projects[i].scm_type_class = "btn-disabled"; - } - - $scope.project_scm_type_options.forEach(function(type) { - if (type.value === project.scm_type) { - $scope.projects[i].scm_type = type.label; - if (type.label === 'Manual') { - $scope.projects[i].scm_update_tooltip = 'Manual projects do not require an SCM update'; - $scope.projects[i].scm_schedule_tooltip = 'Manual projects do not require a schedule'; - $scope.projects[i].scm_type_class = 'btn-disabled'; - $scope.projects[i].statusTip = 'Not configured for SCM'; - $scope.projects[i].statusIcon = 'none'; - } - } - }); - }); - } - }); - } - - $scope.$on(`${list.iterator}_options`, function(event, data){ - $scope.options = data.data.actions.GET; - optionsRequestDataProcessing(); - }); - - $scope.$watchCollection(`${$scope.list.name}`, function() { - optionsRequestDataProcessing(); - } - ); - - // iterate over the list and add fields like type label, after the - // OPTIONS request returns, or the list is sorted/paginated/searched - function optionsRequestDataProcessing(){ - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - - // Set the item type label - if (list.fields.scm_type && $scope.options && - $scope.options.hasOwnProperty('scm_type')) { - $scope.options.scm_type.choices.forEach(function(choice) { - if (choice[0] === item.scm_type) { - itm.type_label = choice[1]; - } - }); - } - - // buildTooltips(itm); - - }); - } - - // Go out and get the organization - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - - $scope.orgRelatedUrls = data.related; - - - $scope.$on('ws-jobs', function(e, data) { - var project; - $log.debug(data); - if ($scope.projects) { - // Assuming we have a list of projects available - project = Find({ list: $scope.projects, key: 'id', val: data.project_id }); - if (project) { - // And we found the affected project - $log.debug('Received event for project: ' + project.name); - $log.debug('Status changed to: ' + data.status); - if (!(data.status === 'successful' || data.status === 'failed')) { - project.scm_update_tooltip = "SCM update currently running"; - project.scm_type_class = "btn-disabled"; - } - project.status = data.status; - project.statusIcon = GetProjectIcon(data.status); - project.statusTip = GetProjectToolTip(data.status); - } - } - }); - - if ($scope.removeChoicesHere) { - $scope.removeChoicesHere(); - } - $scope.removeChoicesHere = $scope.$on('choicesCompleteProjectList', function() { - - list.fields.scm_type.searchOptions = $scope.project_scm_type_options; - list.fields.status.searchOptions = $scope.project_status_options; - - if ($stateParams.scm_type && $stateParams.status) { - // Request coming from home page. User wants all errors for an scm_type - projUrl += '?status=' + $stateParams.status; - } - }); - - if ($scope.removeChoicesReadyList) { - $scope.removeChoicesReadyList(); - } - $scope.removeChoicesReadyList = $scope.$on('choicesReadyProjectList', function() { - choiceCount++; - if (choiceCount === 2) { - $scope.$emit('choicesCompleteProjectList'); - } - }); - - // Load options for status --used in search - GetChoices({ - scope: $scope, - url: projBase, - field: 'status', - variable: 'project_status_options', - callback: 'choicesReadyProjectList' - }); - - // Load the list of options for Kind - GetChoices({ - scope: $scope, - url: projBase, - field: 'scm_type', - variable: 'project_scm_type_options', - callback: 'choicesReadyProjectList' - }); - - }); - - $scope.editProject = function(id) { - $state.go('projects.edit', { project_id: id }); - }; - - if ($scope.removeGoTojobResults) { - $scope.removeGoTojobResults(); - } - $scope.removeGoTojobResults = $scope.$on('GoTojobResults', function(e, data) { - if (data.summary_fields.current_update || data.summary_fields.last_update) { - - Wait('start'); - - // Grab the id from summary_fields - var id = (data.summary_fields.current_update) ? data.summary_fields.current_update.id : data.summary_fields.last_update.id; - - $state.go('output', { id: id, type: 'project' }); - - } else { - Alert('No Updates Available', 'There is no SCM update information available for this project. An update has not yet been ' + - ' completed. If you have not already done so, start an update for this project.', 'alert-info'); - } - }); - - $scope.showSCMStatus = function(id) { - // Refresh the project list - var project = Find({ list: $scope.projects, key: 'id', val: id }); - if (Empty(project.scm_type) || project.scm_type === 'Manual') { - Alert('No SCM Configuration', 'The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, ' + - 'and then run an update.', 'alert-info'); - } else { - // Refresh what we have in memory to insure we're accessing the most recent status record - Rest.setUrl(project.url); - Rest.get() - .then(({data}) => { - $scope.$emit('GoTojobResults', data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Project lookup failed. GET returned: ' + status - }); - }); - } - }; - - if ($scope.removeCancelUpdate) { - $scope.removeCancelUpdate(); - } - $scope.removeCancelUpdate = $scope.$on('Cancel_Update', function(e, url) { - // Cancel the project update process - Rest.setUrl(url); - Rest.post() - .then(() => { - Alert('SCM Update Cancel', 'Your request to cancel the update was submitted to the task manager.', 'alert-info'); - $scope.refresh(); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST status: ' + status }); - }); - }); - - if ($scope.removeCheckCancel) { - $scope.removeCheckCancel(); - } - $scope.removeCheckCancel = $scope.$on('Check_Cancel', function(e, data) { - // Check that we 'can' cancel the update - var url = data.related.cancel; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - if (data.can_cancel) { - $scope.$emit('Cancel_Update', url); - } else { - Alert('Cancel Not Allowed', '
Either you do not have access or the SCM update process completed. ' + - 'Click the Refresh button to view the latest status.
', 'alert-info', null, null, null, null, true); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + ' failed. GET status: ' + status }); - }); - }); - - $scope.cancelUpdate = function(id, name) { - Rest.setUrl(GetBasePath("projects") + id); - Rest.get() - .then(({data}) => { - if (data.related.current_update) { - Rest.setUrl(data.related.current_update); - Rest.get() - .then(({data}) => { - $scope.$emit('Check_Cancel', data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + data.related.current_update + ' failed. GET status: ' + status - }); - }); - } else { - Alert('Update Not Found', '
An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the Refresh ' + - 'button to view the latest status.
', 'alert-info', undefined, undefined, undefined, undefined, true); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to get project failed. GET status: ' + status - }); - }); - }; - - $scope.SCMUpdate = function(project_id, event) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - $scope.projects.forEach(function(project) { - if (project.id === project_id) { - if (!((project.scm_type === "Manual" || Empty(project.scm_type)) || (project.status === 'updating' || project.status === 'running' || project.status === 'pending'))) { - ProjectUpdate({ scope: $scope, project_id: project.id }); - } - } - }); - }; - - $scope.editSchedules = function(id) { - var project = Find({ list: $scope.projects, key: 'id', val: id }); - if (!(project.scm_type === "Manual" || Empty(project.scm_type)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) { - $state.go('projects.edit.schedules', { project_id: id }); - } - }; - - $scope.formCancel = function() { - $state.go('organizations'); - }; - - } -]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-teams.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-teams.controller.js deleted file mode 100644 index c4b9435d1d93..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-teams.controller.js +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$stateParams', 'OrgTeamList', 'Rest', 'OrgTeamsDataset', - 'GetBasePath', '$state', - function($scope, $stateParams, OrgTeamList, Rest, Dataset, - GetBasePath, $state) { - - var list = OrgTeamList, - orgBase = GetBasePath('organizations'); - - init(); - - function init() { - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watchCollection(list.name, function() { - function setOrganizationName(organization) { - organization.organization_name = organization.summary_fields.organization.name; - return organization; - } - _.forEach($scope.teams, (team) => setOrganizationName(team)); - }); - - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - - $scope.orgRelatedUrls = data.related; - }); - } - - $scope.editTeam = function(id) { - $state.go('teams.edit', { team_id: id }); - }; - - $scope.formCancel = function() { - $state.go('organizations'); - }; - } -]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-users.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-users.controller.js deleted file mode 100644 index d657b973c8ec..000000000000 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-users.controller.js +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$stateParams', '$scope', 'OrgUserList','Rest', '$state', - '$compile', 'Wait', 'OrgUsersDataset', - 'Prompt', 'ProcessErrors', 'GetBasePath', '$filter', - function($stateParams, $scope, OrgUserList, Rest, $state, - $compile, Wait, OrgUsersDataset, Prompt, ProcessErrors, - GetBasePath, $filter) { - - var orgBase = GetBasePath('organizations'); - - init(); - - function init() { - // search init - $scope.list = OrgUserList; - $scope.user_dataset = OrgUsersDataset.data; - $scope.users = $scope.user_dataset.results; - - Rest.setUrl(orgBase + $stateParams.organization_id); - Rest.get() - .then(({data}) => { - $scope.organization_name = data.name; - $scope.name = data.name; - $scope.org_id = data.id; - - $scope.orgRelatedUrls = data.related; - - }); - } - - $scope.addUsers = function() { - $compile("")($scope); - }; - - $scope.editUser = function(id) { - $state.go('users.edit', { user_id: id }); - }; - - $scope.deleteUser = function(id, name) { - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = orgBase + $stateParams.organization_id + '/users/'; - Rest.setUrl(url); - Rest.post({ - id: id, - disassociate: true - }).then(() => { - $state.go('.', null, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - Prompt({ - hdr: 'Delete', - body: '
Are you sure you want to remove the following user from this organization?
' + $filter('sanitize')(name) + '
', - action: action, - actionText: 'DELETE' - }); - }; - - $scope.formCancel = function() { - $state.go('organizations'); - }; - - } -]; diff --git a/awx/ui/client/src/organizations/linkout/main.js b/awx/ui/client/src/organizations/linkout/main.js deleted file mode 100644 index e6d31a156c0d..000000000000 --- a/awx/ui/client/src/organizations/linkout/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import AddUsers from './addUsers/main'; - -export default angular.module('organizationsLinkout', [AddUsers.name]); diff --git a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js b/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js deleted file mode 100644 index f605f6c08e09..000000000000 --- a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js +++ /dev/null @@ -1,289 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import OrganizationsJobTemplatesRoute from '~features/templates/routes/organizationsTemplatesList.route'; - -import OrganizationsAdmins from './controllers/organizations-admins.controller'; -import OrganizationsInventories from './controllers/organizations-inventories.controller'; -import OrganizationsProjects from './controllers/organizations-projects.controller'; -import OrganizationsTeams from './controllers/organizations-teams.controller'; -import OrganizationsUsers from './controllers/organizations-users.controller'; -import { N_ } from '../../i18n'; - -let lists = [{ - name: 'organizations.users', - url: '/:organization_id/users', - searchPrefix: 'user', - views: { - 'form': { - controller: OrganizationsUsers, - templateProvider: function(OrgUserList, generateList) { - let html = generateList.build({ - list: OrgUserList, - mode: 'edit', - cancelButton: true - }); - return generateList.wrapPanel(html); - }, - } - }, - params: { - user_search: { - value: { - order_by: 'username' - }, - dynamic: true - } - }, - ncyBreadcrumb: { - parent: "organizations.edit", - label: N_("USERS") - }, - - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - OrgUsersDataset: ['OrgUserList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || list.basePath; - return qs.search(path, $stateParams.user_search); - } - ], - OrgUserList: ['UserList', 'GetBasePath', '$stateParams', function(UserList, GetBasePath, $stateParams) { - let list = _.cloneDeep(UserList); - delete list.actions.add; - list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/users`; - list.searchRowActions = { - add: { - awToolTip: 'Add existing user to organization', - actionClass: 'at-Button--add', - actionId: 'button-add', - ngClick: 'addUsers()' - } - }; - return list; - }] - } -}, { - name: 'organizations.teams', - url: '/:organization_id/teams', - searchPrefix: 'team', - views: { - 'form': { - controller: OrganizationsTeams, - templateProvider: function(OrgTeamList, generateList) { - let html = generateList.build({ - list: OrgTeamList, - mode: 'edit', - cancelButton: true - }); - return generateList.wrapPanel(html); - }, - }, - }, - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - ncyBreadcrumb: { - parent: "organizations.edit", - label: N_("TEAMS") - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - OrgTeamList: ['TeamList', 'GetBasePath', '$stateParams', function(TeamList, GetBasePath, $stateParams) { - let list = _.cloneDeep(TeamList); - delete list.actions.add; - // @issue Why is the delete action unavailable in this view? - delete list.fieldActions.delete; - list.listTitle = N_('Teams') + ` | {{ name }}`; - list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/teams`; - list.emptyListText = "This list is populated by teams added from the Teams section"; - return list; - }], - OrgTeamsDataset: ['OrgTeamList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || list.basePath; - return qs.search(path, $stateParams.team_search); - } - ] - } -}, { - name: 'organizations.inventories', - url: '/:organization_id/inventories', - searchPrefix: 'inventory', - views: { - 'form': { - controller: OrganizationsInventories, - templateProvider: function(OrgInventoryList, generateList) { - let html = generateList.build({ - list: OrgInventoryList, - mode: 'edit', - cancelButton: true - }); - return generateList.wrapPanel(html); - }, - }, - }, - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - ncyBreadcrumb: { - parent: "organizations.edit", - label: N_("INVENTORIES") - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - OrgInventoryList: ['InventoryList', 'GetBasePath', '$stateParams', function(InventoryList, GetBasePath, $stateParams) { - let list = _.cloneDeep(InventoryList); - delete list.actions.add; - // @issue Why is the delete action unavailable in this view? - delete list.fieldActions.delete; - list.title = true; - list.listTitle = N_('Inventories') + ` | {{ name }}`; - list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/inventories`; - list.emptyListText = "This list is populated by inventories added from the Inventories section"; - return list; - }], - OrgInventoryDataset: ['OrgInventoryList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || list.basePath; - return qs.search(path, $stateParams.inventory_search); - } - ] - } -}, { - name: 'organizations.projects', - url: '/:organization_id/projects', - searchPrefix: 'project', - views: { - 'form': { - controller: OrganizationsProjects, - templateProvider: function(OrgProjectList, generateList) { - let html = generateList.build({ - list: OrgProjectList, - mode: 'edit', - cancelButton: true - }); - return generateList.wrapPanel(html); - }, - }, - }, - data: { - activityStream: true, - activityStreamTarget: 'organization', - socket: { - "groups": { - "jobs": ["status_changed"] - } - }, - }, - ncyBreadcrumb: { - parent: "organizations.edit", - label: N_("PROJECTS") - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - OrgProjectList: ['ProjectList', 'GetBasePath', '$stateParams', function(ProjectList, GetBasePath, $stateParams) { - let list = _.cloneDeep(ProjectList); - delete list.actions; - // @issue Why is the delete action unavailable in this view? - delete list.fieldActions.delete; - list.listTitle = N_('Projects') + ` | {{ name }}`; - list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/projects`; - list.emptyListText = "This list is populated by projects added from the Projects section"; - return list; - }], - OrgProjectDataset: ['OrgProjectList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || list.basePath; - return qs.search(path, $stateParams.project_search); - } - ] - } -}, { - name: 'organizations.admins', - url: '/:organization_id/admins', - searchPrefix: 'user', - params: { - user_search: { - value: { - order_by: 'username' - }, - dynamic: true - }, - add_user_search: { - value: { - order_by: 'username', - page_size: '5', - }, - dynamic: true, - squash: true - } - }, - views: { - 'form': { - controller: OrganizationsAdmins, - templateProvider: function(OrgAdminList, generateList) { - let html = generateList.build({ - list: OrgAdminList, - mode: 'edit', - cancelButton: true - }); - return generateList.wrapPanel(html); - }, - } - }, - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - ncyBreadcrumb: { - parent: "organizations.edit", - label: N_("ADMINS") - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - OrgAdminsDataset: ['OrgAdminList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || list.basePath; - return qs.search(path, $stateParams[`user_search`]); - } - ], - OrgAdminList: ['UserList', 'GetBasePath', '$stateParams', function(UserList, GetBasePath, $stateParams) { - let list = _.cloneDeep(UserList); - delete list.actions.add; - list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/admins`; - list.searchRowActions = { - add: { - awToolTip: 'Add existing user to organization as administrator', - actionClass: 'at-Button--add', - ngClick: 'addUsers()' - } - }; - list.listTitle = N_('Admins') + ` | {{ name }}`; - return list; - }] - } -}]; - -lists.push(OrganizationsJobTemplatesRoute); - -export default lists; diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js deleted file mode 100644 index 48a61b0397f3..000000000000 --- a/awx/ui/client/src/organizations/list/organizations-list.controller.js +++ /dev/null @@ -1,201 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['$stateParams', '$scope', '$rootScope', - 'Rest', 'OrganizationList', 'Prompt', 'OrganizationModel', - 'ProcessErrors', 'GetBasePath', 'Wait', '$state', - 'rbacUiControlService', '$filter', 'Dataset', 'i18n', - 'AppStrings', - function($stateParams, $scope, $rootScope, - Rest, OrganizationList, Prompt, Organization, - ProcessErrors, GetBasePath, Wait, $state, - rbacUiControlService, $filter, Dataset, i18n, - AppStrings - ) { - - var defaultUrl = GetBasePath('organizations'), - list = OrganizationList; - - $scope.canAdd = false; - - rbacUiControlService.canAdd("organizations") - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - $scope.orgCount = Dataset.data.count; - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.orgCards = parseCardData($scope[list.name]); - $rootScope.flashMessage = null; - - // grab the pagination elements, move, destroy list generator elements - $('#organization-pagination').appendTo('#OrgCards'); - $('#organizations tag-search').appendTo('.OrgCards-search'); - $('#organizations-list').remove(); - - function parseCardData(cards) { - return cards.map(function(card) { - var val = {}, - url = '/#/organizations/' + card.id + '/'; - val.user_capabilities = card.summary_fields.user_capabilities; - val.name = card.name; - val.id = card.id; - val.description = card.description || undefined; - val.links = []; - val.links.push({ - href: url + 'users', - name: i18n._("USERS"), - count: card.summary_fields.related_field_counts.users, - activeMode: 'users' - }); - val.links.push({ - href: url + 'teams', - name: i18n._("TEAMS"), - count: card.summary_fields.related_field_counts.teams, - activeMode: 'teams' - }); - val.links.push({ - href: url + 'inventories', - name: i18n._("INVENTORIES"), - count: card.summary_fields.related_field_counts.inventories, - activeMode: 'inventories' - }); - val.links.push({ - href: url + 'projects', - name: i18n._("PROJECTS"), - count: card.summary_fields.related_field_counts.projects, - activeMode: 'projects' - }); - val.links.push({ - href: url + 'job_templates', - name: i18n._("JOB TEMPLATES"), - count: card.summary_fields.related_field_counts.job_templates, - activeMode: 'job_templates' - }); - val.links.push({ - href: url + 'admins', - name: i18n._("ADMINS"), - count: card.summary_fields.related_field_counts.admins, - activeMode: 'admins' - }); - return val; - }); - } - - $scope.$on("ReloadOrgListView", function() { - Rest.setUrl($scope.current_url); - Rest.get() - .then(({data}) => $scope.organizations = data.results) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + defaultUrl + ' failed. DELETE returned status: ' + status - }); - }); - }); - - - $scope.$watchCollection('organizations', function(value){ - $scope.orgCards = parseCardData(value); - }); - - if ($scope.removePostRefresh) { - $scope.removePostRefresh(); - } - - $scope.$watchCollection(`${list.iterator}_dataset`, function(data) { - $scope[list.name] = data.results; - $scope.orgCards = parseCardData($scope[list.name]); - }); - - $scope.addOrganization = function() { - $state.transitionTo('organizations.add'); - }; - - $scope.editOrganization = function(id) { - $state.transitionTo('organizations.edit', { - organization_id: id - }); - }; - - function isDeletedOrganizationBeingEdited(deleted_organization_id, editing_organization_id) { - if (editing_organization_id === undefined) { - return false; - } - if (deleted_organization_id === editing_organization_id) { - return true; - } - return false; - } - - $scope.deleteOrganization = function(id, name) { - - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() - .then(() => { - Wait('stop'); - - let reloadListStateParams = null; - - if($scope.organizations.length === 1 && $state.params.organization_search && !_.isEmpty($state.params.organization_search.page) && $state.params.organization_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.organization_search.page = (parseInt(reloadListStateParams.organization_search.page)-1).toString(); - } - - if (isDeletedOrganizationBeingEdited(id, parseInt($stateParams.organization_id)) === true) { - $state.go('^', reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, { reload: true }); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - const organization = new Organization(); - - organization.getDependentResourceCounts(id) - .then((counts) => { - const invalidateRelatedLines = []; - let deleteModalBody = `
${AppStrings.get('deleteResource.CONFIRM', 'organization')}
`; - - counts.forEach(countObj => { - if(countObj.count && countObj.count > 0) { - invalidateRelatedLines.push(`
${countObj.label}${countObj.count}
`); - } - }); - - if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { - deleteModalBody = `
${AppStrings.get('deleteResource.UNAVAILABLE', 'organization')} ${AppStrings.get('deleteResource.CONFIRM', 'organization')}
`; - invalidateRelatedLines.forEach(invalidateRelatedLine => { - deleteModalBody += invalidateRelatedLine; - }); - } - - Prompt({ - hdr: i18n._('Delete'), - resourceName: $filter('sanitize')(name), - body: deleteModalBody, - action: action, - actionText: i18n._('DELETE') - }); - }); - }; - } -]; diff --git a/awx/ui/client/src/organizations/list/organizations-list.partial.html b/awx/ui/client/src/organizations/list/organizations-list.partial.html deleted file mode 100644 index 8a7a2feee66d..000000000000 --- a/awx/ui/client/src/organizations/list/organizations-list.partial.html +++ /dev/null @@ -1,116 +0,0 @@ -
-
-
-
-
-
- ORGANIZATIONS -
- - {{ orgCount }} - -
- -
- -
-
-
- -
-
- - - - -
PLEASE ADD ITEMS TO THIS LIST
- -
-
-
-

- - {{ card.name }} - -

-
- - - -
-
- -
-
- - - -
-
-
diff --git a/awx/ui/client/src/organizations/main.js b/awx/ui/client/src/organizations/main.js deleted file mode 100644 index a0b179261f83..000000000000 --- a/awx/ui/client/src/organizations/main.js +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import { templateUrl } from '../shared/template-url/template-url.factory'; -import OrganizationsList from './list/organizations-list.controller'; -import OrganizationsAdd from './add/organizations-add.controller'; -import OrganizationsEdit from './edit/organizations-edit.controller'; -import organizationsLinkout from './linkout/main'; -import OrganizationsLinkoutStates from './linkout/organizations-linkout.route'; -import OrganizationForm from './organizations.form'; -import OrganizationList from './organizations.list'; -import { N_ } from '../i18n'; - - -export default -angular.module('Organizations', [ - organizationsLinkout.name - ]) - .controller('OrganizationsList', OrganizationsList) - .controller('OrganizationsAdd', OrganizationsAdd) - .controller('OrganizationsEdit', OrganizationsEdit) - .factory('OrganizationForm', OrganizationForm) - .factory('OrganizationList', OrganizationList) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { - let stateExtender = $stateExtenderProvider.$get(), - stateDefinitions = stateDefinitionsProvider.$get(); - - // lazily generate a tree of substates which will replace this node in ui-router's stateRegistry - // see: stateDefinition.factory for usage documentation - $stateProvider.state({ - name: 'organizations.**', - url: '/organizations', - lazyLoad: () => stateDefinitions.generateTree({ - parent: 'organizations', // top-most node in the generated tree - modes: ['add', 'edit'], // form nodes to generate - list: 'OrganizationList', - form: 'OrganizationForm', - controllers: { - list: 'OrganizationsList', - add: 'OrganizationsAdd', - edit: 'OrganizationsEdit' - }, - templates: { - list: templateUrl('organizations/list/organizations-list') - }, - ncyBreadcrumb: { - label: N_('ORGANIZATIONS') - }, - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - resolve: { - add: { - ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => { - return ConfigService.getConfig() - .then(response => response) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get config. GET returned status: ' + - 'status: ' + status - }); - }); - - }] - }, - edit: { - ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => { - return ConfigService.getConfig() - .then(response => response) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get config. GET returned status: ' + - 'status: ' + status - }); - }); - }], - InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - let path = `${GetBasePath('organizations')}${$stateParams.organization_id}/instance_groups/`; - Rest.setUrl(path); - return Rest.get() - .then(({data}) => { - if (data.results.length > 0) { - return data.results; - } - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get instance groups. GET returned ' + - 'status: ' + status - }); - }); - }] - } - } - // concat manually-defined state definitions with generated defintions - }).then((generated) => { - let linkoutDefinitions = _.map(OrganizationsLinkoutStates, (state) => stateExtender.buildDefinition(state)); - return { - states: _(generated.states) - .concat(linkoutDefinitions) - .value() - }; - }) - }); - } - ]); diff --git a/awx/ui/client/src/organizations/organizations.block.less b/awx/ui/client/src/organizations/organizations.block.less deleted file mode 100644 index 9075f485cacc..000000000000 --- a/awx/ui/client/src/organizations/organizations.block.less +++ /dev/null @@ -1,5 +0,0 @@ -#organizations { - .List-noItems { - margin-top: 20px; - } -} \ No newline at end of file diff --git a/awx/ui/client/src/organizations/organizations.form.js b/awx/ui/client/src/organizations/organizations.form.js deleted file mode 100644 index 79d8098afed7..000000000000 --- a/awx/ui/client/src/organizations/organizations.form.js +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Organizations - * @description This form is for adding/editing an organization -*/ - -export default ['NotificationsList', 'i18n', - function(NotificationsList, i18n) { - return function() { - var OrganizationFormObject = { - - addTitle: i18n._('NEW ORGANIZATION'), //Title in add mode - editTitle: '{{ name }}', //Title in edit mode - name: 'organization', //entity or model name in singular form - stateTree: 'organizations', - tabs: true, - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - instance_groups: { - label: i18n._('Instance Groups'), - type: 'custom', - awPopOver: "

" + i18n._("Select the Instance Groups for this Organization to run on.") + "

", - dataTitle: i18n._('Instance Groups'), - dataContainer: 'body', - dataPlacement: 'right', - control: '', - }, - custom_virtualenv: { - label: i18n._('Ansible Environment'), - defaultText: i18n._('Default Environment'), - type: 'select', - ngOptions: 'venv for venv in custom_virtualenvs_options track by venv', - awPopOver: "

" + i18n._("Select the custom Python virtual environment for this organization to run on.") + "

", - dataTitle: i18n._('Ansible Environment'), - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)', - ngShow: 'custom_virtualenvs_options.length > 0' - } - }, - - buttons: { //for now always generates -
- - - - - -
-
-
{{name || "New Job Template"}}
SURVEY
-
- - -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
PREVIEW
-
-
PLEASE ADD A SURVEY PROMPT.
-
    -
  • - -
    - -
    - -
    - {{question.question_description}} -
    -
    - - -   - - - -
    - - -
    - -
    -
  • -
  • - Drop question here to reorder -
  • -
-
-
-
- - - - -
-
-
- -
-
- diff --git a/awx/ui/client/src/portal-mode/main.js b/awx/ui/client/src/portal-mode/main.js deleted file mode 100644 index d74c97ddd910..000000000000 --- a/awx/ui/client/src/portal-mode/main.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import route from './portal-mode.route'; -import templatesRoute from '~features/templates/routes/portalModeTemplatesList.route.js'; -import myJobsRoute from '~features/jobs/routes/portalModeMyJobs.route.js'; -import allJobsRoute from '~features/jobs/routes/portalModeAllJobs.route.js'; -export default - angular.module('portalMode', []) - .run(['$stateExtender', function($stateExtender){ - $stateExtender.addState(templatesRoute); - $stateExtender.addState(myJobsRoute); - $stateExtender.addState(allJobsRoute); - }]); diff --git a/awx/ui/client/src/portal-mode/portal-mode-layout.partial.html b/awx/ui/client/src/portal-mode/portal-mode-layout.partial.html deleted file mode 100644 index 417e97e1bc80..000000000000 --- a/awx/ui/client/src/portal-mode/portal-mode-layout.partial.html +++ /dev/null @@ -1,52 +0,0 @@ -
-
-
-
-
-
-
-
JOB TEMPLATES
-
-
-
-
-
-
-
-
-
-
-
JOBS
-
-
-
-
-
- - -
-
-
- -
-
-
-
-
-
-
-
-
diff --git a/awx/ui/client/src/portal-mode/portal-mode.block.less b/awx/ui/client/src/portal-mode/portal-mode.block.less deleted file mode 100644 index 7a8fb934d8ff..000000000000 --- a/awx/ui/client/src/portal-mode/portal-mode.block.less +++ /dev/null @@ -1,54 +0,0 @@ -.PortalMode-container{ - display: flex; - flex-direction: row; - @media screen and(max-width: 900px){ - flex-direction: column; - height: 100%; - } -} - -.PortalMode-panel--left{ - .OnePlusOne-panel--left; -} - -.PortalMode-panel--right{ - .OnePlusOne-panel--right; - .List-tableHeader:last-of-type{ - text-align:left; - } -} - -.PortalMode-panel .List-header { - height: 14px; - margin-bottom: 20px; -} - -.PortalMode-panelHeader{ - .OnePlusOne-panelHeader; -} - -.PortalMode-filterHolder { - position: absolute; - right: 1px; - margin-right: 25px; - display: flex; - align-items: center; - justify-content: center; - - .btn.btn-xs { - padding: 1px 10px; - } -} - -.PortalMode-filterButton--edges { - &:first-child { - border-right: none; - } - &:last-child { - border-left: none; - } -} - -.PortalMode-refresh { - margin-left: 10px; -} diff --git a/awx/ui/client/src/projects/add/projects-add.controller.js b/awx/ui/client/src/projects/add/projects-add.controller.js deleted file mode 100644 index a5ccdbdbf238..000000000000 --- a/awx/ui/client/src/projects/add/projects-add.controller.js +++ /dev/null @@ -1,203 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$location', '$stateParams', 'GenerateForm', - 'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', - 'GetProjectPath', 'GetChoices', 'Wait', '$state', 'CreateSelect2', 'i18n', - 'CredentialTypes', 'ConfigData', - function($scope, $location, $stateParams, GenerateForm, ProjectsForm, Rest, - Alert, ProcessErrors, GetBasePath, GetProjectPath, GetChoices, Wait, $state, - CreateSelect2, i18n, CredentialTypes, ConfigData) { - - let form = ProjectsForm(), - base = $location.path().replace(/^\//, '').split('/')[0], - defaultUrl = GetBasePath('projects'), - master = {}; - - init(); - - function init() { - $scope.canEditOrg = true; - $scope.custom_virtualenvs_options = ConfigData.custom_virtualenvs; - - Rest.setUrl(GetBasePath('projects')); - Rest.options() - .then(({data}) => { - if (!data.actions.POST) { - $state.go("^"); - Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a project.'), 'alert-info'); - } - }); - - CreateSelect2({ - element: '#project_custom_virtualenv', - multiple: false, - opts: $scope.custom_virtualenvs_options - }); - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - } - - GetProjectPath({ scope: $scope, master: master }); - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReady', function() { - var i; - for (i = 0; i < $scope.scm_type_options.length; i++) { - if ($scope.scm_type_options[i].value === '') { - $scope.scm_type_options[i].value = "manual"; - //$scope.scm_type = $scope.scm_type_options[i]; - break; - } - } - - CreateSelect2({ - element: '#project_scm_type', - multiple: false - }); - - $scope.scmRequired = false; - master.scm_type = $scope.scm_type; - }); - - // Load the list of options for Kind - GetChoices({ - scope: $scope, - url: defaultUrl, - field: 'scm_type', - variable: 'scm_type_options', - callback: 'choicesReady' - }); - CreateSelect2({ - element: '#local-path-select', - multiple: false - }); - - // Save - $scope.formSave = function() { - var i, fld, url, data = {}; - data = {}; - for (fld in form.fields) { - if (form.fields[fld].type === 'checkbox_group') { - for (i = 0; i < form.fields[fld].fields.length; i++) { - data[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name]; - } - } else { - if (form.fields[fld].type !== 'alertblock') { - data[fld] = $scope[fld]; - } - } - } - - if ($scope.scm_type.value === "manual") { - data.scm_type = ""; - data.local_path = $scope.local_path.value; - } else { - data.scm_type = $scope.scm_type.value; - delete data.local_path; - } - - url = (base === 'teams') ? GetBasePath('teams') + $stateParams.team_id + '/projects/' : defaultUrl; - Wait('start'); - Rest.setUrl(url); - Rest.post(data) - .then(({data}) => { - $scope.addedItem = data.id; - $state.go('projects.edit', { project_id: data.id }, { reload: true }); - }) - .catch(({data, status}) => { - Wait('stop'); - ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), - msg: i18n._('Failed to create new project. POST returned status: ') + status }); - }); - }; - - $scope.scmChange = function() { - // When an scm_type is set, path is not required - if ($scope.scm_type) { - $scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false; - $scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false; - $scope.scmBranchLabel = i18n._('SCM Branch'); - // Dynamically update popover values - if ($scope.scm_type.value) { - if(($scope.lookupType === 'insights_credential' && $scope.scm_type.value !== 'insights') || ($scope.lookupType === 'scm_credential' && $scope.scm_type.value === 'insights')) { - $scope.credential = null; - $scope.credential_name = ''; - } - switch ($scope.scm_type.value) { - case 'git': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + - i18n._('Example URLs for GIT SCM include:') + - '

  • https://github.com/ansible/ansible.git
  • ' + - '
  • git@github.com:ansible/ansible.git
  • git://servername.example.com/ansible.git
' + - '

' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' + - 'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' + - 'SSH. GIT read only protocol (git://) does not use username or password information.'), '', ''); - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('SCM Branch/Tag/Commit'); - break; - case 'svn': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('Example URLs for Subversion SCM include:') + '

' + - '
  • https://github.com/ansible/ansible
  • svn://servername.example.com/path
  • ' + - '
  • svn+ssh://servername.example.com/path
'; - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('Revision #'); - break; - case 'hg': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('Example URLs for Mercurial SCM include:') + '

' + - '
  • https://bitbucket.org/username/project
  • ssh://hg@bitbucket.org/username/project
  • ' + - '
  • ssh://server.example.com/path
' + - '

' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' + - 'Do not put the username and key in the URL. ' + - 'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '', ''); - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('SCM Branch/Tag/Revision'); - break; - case 'insights': - $scope.pathRequired = false; - $scope.scmRequired = false; - $scope.credRequired = true; - $scope.credentialLabel = "Credential"; - $scope.lookupType = 'insights_credential'; - break; - default: - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('URL popover text') + '

'; - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - } - } - } - }; - $scope.formCancel = function() { - $state.go('projects'); - }; - $scope.lookupCredential = function(){ - // Perform a lookup on the credential_type. Git, Mercurial, and Subversion - // all use SCM as their credential type. - let credType = _.filter(CredentialTypes, function(credType){ - return ($scope.scm_type.value !== "insights" && credType.kind === "scm" || - $scope.scm_type.value === "insights" && credType.kind === "insights"); - }); - $state.go('.credential', { - credential_search: { - credential_type: credType[0].id, - page_size: '5', - page: '1' - } - }); - }; - } -]; diff --git a/awx/ui/client/src/projects/edit/projects-edit.controller.js b/awx/ui/client/src/projects/edit/projects-edit.controller.js deleted file mode 100644 index 8f28ac1b7913..000000000000 --- a/awx/ui/client/src/projects/edit/projects-edit.controller.js +++ /dev/null @@ -1,350 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest', - 'Alert', 'ProcessErrors', 'GenerateForm', 'Prompt', - 'GetBasePath', 'GetProjectPath', 'Authorization', 'GetChoices', 'Empty', - 'Wait', 'ProjectUpdate', '$state', 'CreateSelect2', 'ToggleNotification', - 'i18n', 'CredentialTypes', 'OrgAdminLookup', 'ConfigData', - function($scope, $rootScope, $stateParams, ProjectsForm, Rest, Alert, - ProcessErrors, GenerateForm, Prompt, GetBasePath, - GetProjectPath, Authorization, GetChoices, Empty, Wait, ProjectUpdate, - $state, CreateSelect2, ToggleNotification, i18n, CredentialTypes, - OrgAdminLookup, ConfigData) { - - let form = ProjectsForm(), - defaultUrl = GetBasePath('projects') + $stateParams.project_id + '/', - master = {}, - id = $stateParams.project_id; - - init(); - - function init() { - $scope.project_local_paths = []; - $scope.base_dir = ''; - $scope.custom_virtualenvs_options = ConfigData.custom_virtualenvs; - } - - $scope.$watch('project_obj.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAdd = false; - } - }); - - if ($scope.pathsReadyRemove) { - $scope.pathsReadyRemove(); - } - $scope.pathsReadyRemove = $scope.$on('pathsReady', function () { - CreateSelect2({ - element: '#local-path-select', - multiple: false - }); - }); - - // After the project is loaded, retrieve each related set - if ($scope.projectLoadedRemove) { - $scope.projectLoadedRemove(); - } - $scope.projectLoadedRemove = $scope.$on('projectLoaded', function() { - var opts = []; - - if (Authorization.getUserInfo('is_superuser') === true) { - GetProjectPath({ scope: $scope, master: master }); - } else { - opts.push({ - label: $scope.local_path, - value: $scope.local_path - }); - $scope.project_local_paths = opts; - $scope.local_path = $scope.project_local_paths[0]; - $scope.base_dir = i18n._('You do not have access to view this property'); - $scope.$emit('pathsReady'); - } - - $scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false; - $scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false; - $scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch'; - Wait('stop'); - - $scope.scmChange(); - }); - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReady', function() { - let i; - for (i = 0; i < $scope.scm_type_options.length; i++) { - if ($scope.scm_type_options[i].value === '') { - $scope.scm_type_options[i].value = "manual"; - break; - } - } - // Retrieve detail record and prepopulate the form - Rest.setUrl(defaultUrl); - Rest.get({ params: { id: id } }) - .then(({data}) => { - var fld, i; - for (fld in form.fields) { - if (form.fields[fld].type === 'checkbox_group') { - for (i = 0; i < form.fields[fld].fields.length; i++) { - $scope[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name]; - master[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name]; - } - } else { - if (data[fld] !== undefined) { - $scope[fld] = data[fld]; - master[fld] = data[fld]; - } - } - if (form.fields[fld].sourceModel && data.summary_fields && - data.summary_fields[form.fields[fld].sourceModel]) { - $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - } - } - - data.scm_type = (Empty(data.scm_type)) ? 'manual' : data.scm_type; - for (i = 0; i < $scope.scm_type_options.length; i++) { - if ($scope.scm_type_options[i].value === data.scm_type) { - $scope.scm_type = $scope.scm_type_options[i]; - break; - } - } - - if ($scope.scm_type.value !== 'manual') { - $scope.pathRequired = false; - $scope.scmRequired = true; - } else { - $scope.pathRequired = true; - $scope.scmRequired = false; - } - - master.scm_type = $scope.scm_type; - CreateSelect2({ - element: '#project_scm_type', - multiple: false - }); - - $scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch'; - $scope.scm_update_tooltip = i18n._("Get latest SCM revision"); - $scope.scm_type_class = ""; - if (data.status === 'running' || data.status === 'updating') { - $scope.scm_update_tooltip = i18n._("SCM update currently running"); - $scope.scm_type_class = "btn-disabled"; - } - if (Empty(data.scm_type)) { - $scope.scm_update_tooltip = i18n._('Manual projects do not require an SCM update'); - $scope.scm_type_class = "btn-disabled"; - } - - OrgAdminLookup.checkForRoleLevelAdminAccess(data.organization, 'project_admin_role') - .then(function(canEditOrg){ - $scope.canEditOrg = canEditOrg; - }); - - CreateSelect2({ - element: '#project_custom_virtualenv', - multiple: false, - opts: $scope.custom_virtualenvs_options - }); - - $scope.project_obj = data; - $scope.name = data.name; - $scope.breadcrumb.project_name = data.name; - $scope.$emit('projectLoaded'); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Failed to retrieve project: %s. GET status: '), id) + status - }); - }); - }); - - // Load the list of options for Kind - Wait('start'); - GetChoices({ - url: GetBasePath('projects'), - scope: $scope, - field: 'scm_type', - variable: 'scm_type_options', - callback: 'choicesReady' - }); - - $scope.toggleNotification = function(event, id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: $scope.project_obj.url, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - - // Save changes to the parent - $scope.formSave = function() { - var fld, i, params; - GenerateForm.clearApiErrors($scope); - Wait('start'); - $rootScope.flashMessage = null; - params = {}; - for (fld in form.fields) { - if (form.fields[fld].type === 'checkbox_group') { - for (i = 0; i < form.fields[fld].fields.length; i++) { - params[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name]; - } - } else { - if (form.fields[fld].type !== 'alertblock') { - params[fld] = $scope[fld]; - } - } - } - - if ($scope.scm_type.value === "manual") { - params.scm_type = ""; - params.local_path = $scope.local_path.value; - } else { - params.scm_type = $scope.scm_type.value; - delete params.local_path; - } - - Rest.setUrl(defaultUrl); - Rest.put(params) - .then(() => { - Wait('stop'); - $state.go($state.current, {}, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Failed to update project: %s. PUT status: '), id) + status }); - }); - }; - - // Related set: Delete button - $scope['delete'] = function(set, itm_id, name, title) { - var action = function() { - var url = GetBasePath('projects') + id + '/' + set + '/'; - $rootScope.flashMessage = null; - Rest.setUrl(url); - Rest.post({ id: itm_id, disassociate: 1 }) - .then(() => { - $('#prompt-modal').modal('hide'); - }) - .catch(({data, status}) => { - $('#prompt-modal').modal('hide'); - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST returned status: '), url) + status }); - }); - }; - - Prompt({ - hdr: i18n._('Delete'), - body: '
' + i18n.sprintf(i18n._('Are you sure you want to remove the %s below from %s?'), title, $scope.name) + '
' + '
' + name + '
', - action: action, - actionText: i18n._('DELETE') - }); - }; - - $scope.scmChange = function() { - if ($scope.scm_type) { - $scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false; - $scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false; - $scope.scmBranchLabel = i18n._('SCM Branch'); - - // Dynamically update popover values - if ($scope.scm_type.value) { - if(($scope.lookupType === 'insights_credential' && $scope.scm_type.value !== 'insights') || ($scope.lookupType === 'scm_credential' && $scope.scm_type.value === 'insights')) { - $scope.credential = null; - $scope.credential_name = ''; - } - switch ($scope.scm_type.value) { - case 'git': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('Example URLs for GIT SCM include:') + '

  • https://github.com/ansible/ansible.git
  • ' + - '
  • git@github.com:ansible/ansible.git
  • git://servername.example.com/ansible.git
' + - '

' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' + - 'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' + - 'SSH. GIT read only protocol (git://) does not use username or password information.'), '', ''); - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('SCM Branch/Tag/Commit'); - break; - case 'svn': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('Example URLs for Subversion SCM include:') + '

' + - '
  • https://github.com/ansible/ansible
  • svn://servername.example.com/path
  • ' + - '
  • svn+ssh://servername.example.com/path
'; - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('Revision #'); - break; - case 'hg': - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('Example URLs for Mercurial SCM include:') + '

' + - '
  • https://bitbucket.org/username/project
  • ssh://hg@bitbucket.org/username/project
  • ' + - '
  • ssh://server.example.com/path
' + - '

' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' + - 'Do not put the username and key in the URL. ' + - 'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '', ''); - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - $scope.scmBranchLabel = i18n._('SCM Branch/Tag/Revision'); - break; - case 'insights': - $scope.pathRequired = false; - $scope.scmRequired = false; - $scope.credRequired = true; - $scope.credentialLabel = "Credential"; - $scope.lookupType = 'insights_credential'; - break; - default: - $scope.credentialLabel = "SCM Credential"; - $scope.urlPopover = '

' + i18n._('URL popover text'); - $scope.credRequired = false; - $scope.lookupType = 'scm_credential'; - } - } - } - }; - - $scope.lookupCredential = function(){ - // Perform a lookup on the credential_type. Git, Mercurial, and Subversion - // all use SCM as their credential type. - let credType = _.filter(CredentialTypes, function(credType){ - return ($scope.scm_type.value !== "insights" && credType.kind === "scm" || - $scope.scm_type.value === "insights" && credType.kind === "insights"); - }); - $state.go('.credential', { - credential_search: { - credential_type: credType[0].id, - page_size: '5', - page: '1' - } - }); - }; - - $scope.SCMUpdate = function() { - if ($scope.project_obj.scm_type === "Manual" || Empty($scope.project_obj.scm_type)) { - // ignore - } else if ($scope.project_obj.status === 'updating' || $scope.project_obj.status === 'running' || $scope.project_obj.status === 'pending') { - Alert(i18n._('Update in Progress'), i18n._('The SCM update process is running.'), 'alert-info'); - } else { - ProjectUpdate({ scope: $scope, project_id: $scope.project_obj.id }); - } - }; - - $scope.formCancel = function() { - $state.transitionTo('projects'); - }; - } -]; diff --git a/awx/ui/client/src/projects/factories/get-project-icon.factory.js b/awx/ui/client/src/projects/factories/get-project-icon.factory.js deleted file mode 100644 index 5234041e38d5..000000000000 --- a/awx/ui/client/src/projects/factories/get-project-icon.factory.js +++ /dev/null @@ -1,30 +0,0 @@ -export default - function GetProjectIcon() { - return function(status) { - var result = ''; - switch (status) { - case 'n/a': - case 'ok': - case 'never updated': - result = 'none'; - break; - case 'pending': - case 'waiting': - case 'new': - result = 'none'; - break; - case 'updating': - case 'running': - result = 'running'; - break; - case 'successful': - result = 'success'; - break; - case 'failed': - case 'missing': - case 'canceled': - result = 'error'; - } - return result; - }; - } diff --git a/awx/ui/client/src/projects/factories/get-project-path.factory.js b/awx/ui/client/src/projects/factories/get-project-path.factory.js deleted file mode 100644 index 3778f3c28e50..000000000000 --- a/awx/ui/client/src/projects/factories/get-project-path.factory.js +++ /dev/null @@ -1,78 +0,0 @@ -export default - function GetProjectPath(Alert, Rest, GetBasePath, ProcessErrors) { - return function(params) { - var scope = params.scope, - master = params.master; - - function arraySort(data) { - //Sort nodes by name - var i, j, names = [], - newData = []; - for (i = 0; i < data.length; i++) { - names.push(data[i].value); - } - names.sort(); - for (j = 0; j < names.length; j++) { - for (i = 0; i < data.length; i++) { - if (data[i].value === names[j]) { - newData.push(data[i]); - } - } - } - return newData; - } - - scope.showMissingPlaybooksAlert = false; - - Rest.setUrl(GetBasePath('config')); - Rest.get() - .then(({data}) => { - var opts = [], i; - if (data.project_local_paths) { - for (i = 0; i < data.project_local_paths.length; i++) { - opts.push({ - label: data.project_local_paths[i], - value: data.project_local_paths[i] - }); - } - } - if (scope.local_path) { - // List only includes paths not assigned to projects, so add the - // path assigned to the current project. - opts.push({ - label: scope.local_path, - value: scope.local_path - }); - } - scope.project_local_paths = arraySort(opts); - if (scope.local_path) { - for (i = 0; scope.project_local_paths.length; i++) { - if (scope.project_local_paths[i].value === scope.local_path) { - scope.local_path = scope.project_local_paths[i]; - break; - } - } - } - scope.base_dir = data.project_base_dir; - master.local_path = scope.local_path; - master.base_dir = scope.base_dir; // Keep in master object so that it doesn't get - // wiped out on form reset. - if (opts.length === 0) { - // trigger display of alert block when scm_type == manual - scope.showMissingPlaybooksAlert = true; - } - scope.$emit('pathsReady'); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to access API config. GET status: ' + status }); - }); - }; - } - -GetProjectPath.$inject = - [ 'Alert', - 'Rest', - 'GetBasePath', - 'ProcessErrors' - ]; diff --git a/awx/ui/client/src/projects/factories/get-project-tool-tip.factory.js b/awx/ui/client/src/projects/factories/get-project-tool-tip.factory.js deleted file mode 100644 index 834a6c9d99ac..000000000000 --- a/awx/ui/client/src/projects/factories/get-project-tool-tip.factory.js +++ /dev/null @@ -1,38 +0,0 @@ -export default - function GetProjectToolTip(i18n) { - return function(status) { - var result = ''; - switch (status) { - case 'n/a': - case 'ok': - case 'never updated': - result = i18n._('No SCM updates have run for this project'); - break; - case 'pending': - case 'waiting': - case 'new': - result = i18n._('Update queued. Click for details'); - break; - case 'updating': - case 'running': - result = i18n._('Update running. Click for details'); - break; - case 'successful': - result = i18n._('Update succeeded. Click for details'); - break; - case 'failed': - result = i18n._('Update failed. Click for details'); - break; - case 'missing': - result = i18n._('Update missing. Click for details'); - break; - case 'canceled': - result = i18n._('Update canceled. Click for details'); - break; - } - return result; - }; - } - -GetProjectToolTip.$inject = - [ 'i18n' ]; diff --git a/awx/ui/client/src/projects/list/projects-list.controller.js b/awx/ui/client/src/projects/list/projects-list.controller.js deleted file mode 100644 index c4aa5db6c82f..000000000000 --- a/awx/ui/client/src/projects/list/projects-list.controller.js +++ /dev/null @@ -1,339 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', - 'ProjectList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ProjectUpdate', - 'Wait', 'Empty', 'Find', 'GetProjectIcon', 'GetProjectToolTip', '$filter', - '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet', 'ProjectModel', - 'ProjectsStrings', - function($scope, $rootScope, $log, Rest, Alert, ProjectList, - Prompt, ProcessErrors, GetBasePath, ProjectUpdate, Wait, Empty, Find, - GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService, - Dataset, i18n, qs, Project, ProjectsStrings) { - - let project = new Project(); - - var list = ProjectList; - - init(); - - function init() { - $scope.canAdd = false; - - rbacUiControlService.canAdd('projects') - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - _.forEach($scope[list.name], buildTooltips); - $rootScope.flashMessage = null; - } - - $scope.$on(`${list.iterator}_options`, function(event, data){ - $scope.options = data.data.actions.GET; - optionsRequestDataProcessing(); - }); - - $scope.$watchCollection(`${$scope.list.name}`, function() { - optionsRequestDataProcessing(); - } - ); - - // iterate over the list and add fields like type label, after the - // OPTIONS request returns, or the list is sorted/paginated/searched - function optionsRequestDataProcessing(){ - if ($scope[list.name] !== undefined) { - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - - // Set the item type label - if (list.fields.scm_type && $scope.options && - $scope.options.hasOwnProperty('scm_type')) { - $scope.options.scm_type.choices.forEach(function(choice) { - if (choice[0] === item.scm_type) { - itm.type_label = choice[1]; - } - }); - } - - buildTooltips(itm); - - }); - } - } - - function buildTooltips(project) { - project.statusIcon = GetProjectIcon(project.status); - project.statusTip = GetProjectToolTip(project.status); - project.scm_update_tooltip = i18n._("Get latest SCM revision"); - project.scm_schedule_tooltip = i18n._("Schedule SCM revision updates"); - project.scm_type_class = ""; - - if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') { - project.statusTip = i18n._('Canceled. Click for details'); - project.scm_type_class = "btn-disabled"; - } - - if (project.status === 'running' || project.status === 'updating') { - project.scm_update_tooltip = i18n._("SCM update currently running"); - project.scm_type_class = "btn-disabled"; - } - if (project.scm_type === 'manual') { - project.scm_update_tooltip = i18n._('Manual projects do not require an SCM update'); - project.scm_schedule_tooltip = i18n._('Manual projects do not require a schedule'); - project.scm_type_class = 'btn-disabled'; - project.statusTip = i18n._('Not configured for SCM'); - project.statusIcon = 'none'; - } - } - - $scope.reloadList = function(){ - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - qs.search(path, $state.params[`${list.iterator}_search`]) - .then(function(searchResponse) { - $scope[`${list.iterator}_dataset`] = searchResponse.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - }); - }; - - $scope.$on(`ws-jobs`, function(e, data) { - var project; - $log.debug(data); - if ($scope.projects) { - // Assuming we have a list of projects available - project = Find({ list: $scope.projects, key: 'id', val: data.project_id }); - if (project) { - // And we found the affected project - $log.debug('Received event for project: ' + project.name); - $log.debug('Status changed to: ' + data.status); - if (data.status === 'successful' || data.status === 'failed' || data.status === 'canceled') { - $scope.reloadList(); - } else { - project.scm_update_tooltip = "SCM update currently running"; - project.scm_type_class = "btn-disabled"; - } - project.status = data.status; - project.statusIcon = GetProjectIcon(data.status); - project.statusTip = GetProjectToolTip(data.status); - } - } - }); - - $scope.addProject = function() { - $state.go('projects.add'); - }; - - $scope.editProject = function(id) { - $state.go('projects.edit', { project_id: id }); - }; - - if ($scope.removeGoTojobResults) { - $scope.removeGoTojobResults(); - } - $scope.removeGoTojobResults = $scope.$on('GoTojobResults', function(e, data) { - if (data.summary_fields.current_update || data.summary_fields.last_update) { - - Wait('start'); - - // Grab the id from summary_fields - var id = (data.summary_fields.current_update) ? data.summary_fields.current_update.id : data.summary_fields.last_update.id; - - $state.go('output', { id: id, type: 'project'}, { reload: true }); - - } else { - Alert(i18n._('No Updates Available'), i18n._('There is no SCM update information available for this project. An update has not yet been ' + - ' completed. If you have not already done so, start an update for this project.'), 'alert-info'); - } - }); - - $scope.copyProject = project => { - Wait('start'); - new Project('get', project.id) - .then(model => model.copy()) - .then(({ id }) => { - const params = { project_id: id }; - $state.go('projects.edit', params, { reload: true }); - }) - .catch(({ data, status }) => { - const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; - ProcessErrors($scope, data, status, null, params); - }) - .finally(() => Wait('stop')); - }; - - $scope.showSCMStatus = function(id) { - // Refresh the project list - var project = Find({ list: $scope.projects, key: 'id', val: id }); - if (Empty(project.scm_type) || project.scm_type === 'Manual') { - Alert(i18n._('No SCM Configuration'), i18n._('The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, ' + - 'and then run an update.'), 'alert-info'); - } else { - // Refresh what we have in memory to insure we're accessing the most recent status record - Rest.setUrl(project.url); - Rest.get() - .then(({data}) => { - $scope.$emit('GoTojobResults', data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n._('Project lookup failed. GET returned: ') + status }); - }); - } - }; - - $scope.deleteProject = function(id, name) { - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - project.request('delete', id) - .then(() => { - - let reloadListStateParams = null; - - if($scope.projects.length === 1 && $state.params.project_search && !_.isEmpty($state.params.project_search.page) && $state.params.project_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.project_search.page = (parseInt(reloadListStateParams.project_search.page)-1).toString(); - } - - if (parseInt($state.params.project_id) === id) { - $state.go("^", reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), `${project.path}${id}/`) + status }); - }) - .finally(function() { - Wait('stop'); - }); - }; - - project.getDependentResourceCounts(id) - .then((counts) => { - const invalidateRelatedLines = []; - let deleteModalBody = `

${ProjectsStrings.get('deleteResource.CONFIRM', 'project')}
`; - - counts.forEach(countObj => { - if(countObj.count && countObj.count > 0) { - invalidateRelatedLines.push(`
${countObj.label}${countObj.count}
`); - } - }); - - if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { - deleteModalBody = `
${ProjectsStrings.get('deleteResource.USED_BY', 'project')} ${ProjectsStrings.get('deleteResource.CONFIRM', 'project')}
`; - invalidateRelatedLines.forEach(invalidateRelatedLine => { - deleteModalBody += invalidateRelatedLine; - }); - } - - Prompt({ - hdr: i18n._('Delete'), - resourceName: $filter('sanitize')(name), - body: deleteModalBody, - action: action, - actionText: i18n._('DELETE') - }); - }); - }; - - if ($scope.removeCancelUpdate) { - $scope.removeCancelUpdate(); - } - $scope.removeCancelUpdate = $scope.$on('Cancel_Update', function(e, url) { - // Cancel the project update process - Rest.setUrl(url); - Rest.post() - .then(() => { - Alert(i18n._('SCM Update Cancel'), i18n._('Your request to cancel the update was submitted to the task manager.'), 'alert-info'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST status: '), url) + status }); - }); - }); - - if ($scope.removeCheckCancel) { - $scope.removeCheckCancel(); - } - $scope.removeCheckCancel = $scope.$on('Check_Cancel', function(e, data) { - // Check that we 'can' cancel the update - var url = data.related.cancel; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - if (data.can_cancel) { - $scope.$emit('Cancel_Update', url); - } else { - Alert(i18n._('Cancel Not Allowed'), '
' + i18n.sprintf(i18n._('Either you do not have access or the SCM update process completed. ' + - 'Click the %sRefresh%s button to view the latest status.'), '', '') + '
', 'alert-info', null, null, null, null, true); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), url) + status }); - }); - }); - - $scope.cancelUpdate = function(project) { - project.pending_cancellation = true; - Rest.setUrl(GetBasePath("projects") + project.id); - Rest.get() - .then(({data}) => { - if (data.related.current_update) { - Rest.setUrl(data.related.current_update); - Rest.get() - .then(({data}) => { - $scope.$emit('Check_Cancel', data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), data.related.current_update) + status }); - }); - } else { - Alert(i18n._('Update Not Found'), '
' + i18n.sprintf(i18n._('An SCM update does not appear to be running for project: %s. Click the %sRefresh%s ' + - 'button to view the latest status.'), $filter('sanitize')(name), '', '') + '
', 'alert-info',undefined,undefined,undefined,undefined,true); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n._('Call to get project failed. GET status: ') + status }); - }); - }; - - $scope.SCMUpdate = function(project_id, event) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - $scope.projects.forEach(function(project) { - if (project.id === project_id) { - if (project.scm_type === "Manual" || Empty(project.scm_type)) { - // Do not respond. Button appears greyed out as if it is disabled. Not disabled though, because we need mouse over event - // to work. So user can click, but we just won't do anything. - //Alert('Missing SCM Setup', 'Before running an SCM update, edit the project and provide the SCM access information.', 'alert-info'); - } else if (project.status === 'updating' || project.status === 'running' || project.status === 'pending') { - // Alert('Update in Progress', 'The SCM update process is running. Use the Refresh button to monitor the status.', 'alert-info'); - } else { - ProjectUpdate({ scope: $scope, project_id: project.id }); - } - } - }); - }; - - $scope.editSchedules = function(id) { - var project = Find({ list: $scope.projects, key: 'id', val: id }); - if (!(project.scm_type === "Manual" || Empty(project.scm_type)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) { - $state.go('projects.edit.schedules', { project_id: id }); - } - }; - } -]; diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js deleted file mode 100644 index 144fb99b916c..000000000000 --- a/awx/ui/client/src/projects/main.js +++ /dev/null @@ -1,125 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import ProjectsList from './list/projects-list.controller'; -import ProjectsAdd from './add/projects-add.controller'; -import ProjectsEdit from './edit/projects-edit.controller'; -import ProjectList from './projects.list'; -import ProjectsForm from './projects.form'; -import { N_ } from '../i18n'; -import GetProjectPath from './factories/get-project-path.factory'; -import GetProjectIcon from './factories/get-project-icon.factory'; -import GetProjectToolTip from './factories/get-project-tool-tip.factory'; -import { - projectsSchedulesListRoute, - projectsSchedulesAddRoute, - projectsSchedulesEditRoute -} from '../scheduler/schedules.route'; - -import ProjectsTemplatesRoute from '~features/templates/routes/projectsTemplatesList.route'; -import ProjectsStrings from './projects.strings'; - -export default -angular.module('Projects', []) - .controller('ProjectsList', ProjectsList) - .controller('ProjectsAdd', ProjectsAdd) - .controller('ProjectsEdit', ProjectsEdit) - .factory('GetProjectPath', GetProjectPath) - .factory('GetProjectIcon', GetProjectIcon) - .factory('GetProjectToolTip', GetProjectToolTip) - .factory('ProjectList', ProjectList) - .factory('ProjectsForm', ProjectsForm) - .service('ProjectsStrings', ProjectsStrings) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider,$stateExtenderProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(); - let stateExtender = $stateExtenderProvider.$get(); - var projectResolve = { - CredentialTypes: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', - (Rest, $stateParams, GetBasePath, ProcessErrors) => { - var path = GetBasePath('credential_types'); - Rest.setUrl(path); - return Rest.get() - .then(function(data) { - return (data.data.results); - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get credential types. GET returned status: ' + - response.status - }); - }); - } - ], - ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => { - return ConfigService.getConfig() - .then(response => response) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get config. GET returned status: ' + - 'status: ' + status - }); - }); - }] - }; - - function generateStateTree() { - let projectTree = stateDefinitions.generateTree({ - parent: 'projects', // top-most node in the generated tree (will replace this state definition) - modes: ['add', 'edit'], - generateSchedulerView: true, - list: 'ProjectList', - form: 'ProjectsForm', - controllers: { - list: ProjectsList, // DI strings or objects - add: ProjectsAdd, - edit: ProjectsEdit - }, - data: { - activityStream: true, - activityStreamTarget: 'project', - socket: { - "groups": { - "jobs": ["status_changed"] - } - } - }, - ncyBreadcrumb: { - label: N_('PROJECTS') - }, - breadcrumbs: { - edit: '{{breadcrumb.project_name}}' - }, - resolve: { - add: projectResolve, - edit: projectResolve - } - }); - - return Promise.all([ - projectTree - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(ProjectsTemplatesRoute), - stateExtender.buildDefinition(projectsSchedulesListRoute), - stateExtender.buildDefinition(projectsSchedulesAddRoute), - stateExtender.buildDefinition(projectsSchedulesEditRoute) - ]) - }; - }); - } - let stateTree = { - name: 'projects.**', - url: '/projects', - lazyLoad: () => generateStateTree() - }; - $stateProvider.state(stateTree); - } - ]); diff --git a/awx/ui/client/src/projects/projects.form.js b/awx/ui/client/src/projects/projects.form.js deleted file mode 100644 index bd82dabbc271..000000000000 --- a/awx/ui/client/src/projects/projects.form.js +++ /dev/null @@ -1,311 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Projects - * @description This form is for adding/editing projects -*/ - -export default ['i18n', 'NotificationsList', 'TemplateList', - function(i18n, NotificationsList, TemplateList) { - return function() { - var projectsFormObj = { - addTitle: i18n._('NEW PROJECT'), - editTitle: '{{ name }}', - name: 'project', - basePath: 'projects', - // the top-most node of generated state tree - stateTree: 'projects', - forceListeners: true, - tabs: true, - subFormTitles: { - sourceSubForm: i18n._('Source Details'), - }, - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - list: 'OrganizationList', - sourceModel: 'organization', - basePath: 'organizations', - sourceField: 'name', - dataTitle: i18n._('Organization'), - required: true, - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', - awLookupWhen: '(project_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg' - }, - scm_type: { - label: i18n._('SCM Type'), - type: 'select', - class: 'Form-dropDown--scmType', - defaultText: 'Choose an SCM Type', - ngOptions: 'type.label for type in scm_type_options track by type.value', - ngChange: 'scmChange()', - required: true, - hasSubForm: true, - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - missing_path_alert: { - type: 'alertblock', - ngShow: "showMissingPlaybooksAlert && scm_type.value == 'manual'", - alertTxt: '

WARNING: There are no available playbook directories in {{ base_dir }}. ' + - 'Either that directory is empty, or all of the contents are already assigned to other projects. ' + - 'Create a new directory there and make sure the playbook files can be read by the "awx" system user, ' + - 'or have {{BRAND_NAME}} directly retrieve your playbooks from source control using the SCM Type option above.

', - closeable: false - }, - base_dir: { - label: i18n._('Project Base Path'), - type: 'text', - class: 'Form-textUneditable', - showonly: true, - ngShow: "scm_type.value == 'manual' " , - awPopOver: '

' + i18n._('Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. ' + - 'Together the base path and selected playbook directory provide the full path used to locate playbooks.') + '

' + - '

' + i18n.sprintf(i18n._('Change %s under "Configure {{BRAND_NAME}}" to change this location.'), 'PROJECTS_ROOT') + '

', - dataTitle: i18n._('Project Base Path'), - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - local_path: { - label: i18n._('Playbook Directory'), - type: 'select', - id: 'local-path-select', - ngOptions: 'path.label for path in project_local_paths', - awRequiredWhen: { - reqExpression: "pathRequired", - init: false - }, - ngShow: "scm_type.value == 'manual' && !showMissingPlaybooksAlert", - awPopOver: '

' + i18n._('Select from the list of directories found in the Project Base Path. ' + - 'Together the base path and the playbook directory provide the full path used to locate playbooks.') + '

', - dataTitle: i18n._('Project Path'), - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - scm_url: { - label: 'SCM URL', - type: 'text', - ngShow: "scm_type && scm_type.value !== 'manual' && scm_type.value !== 'insights' ", - awRequiredWhen: { - reqExpression: "scmRequired", - init: false - }, - subForm: 'sourceSubForm', - hideSubForm: "scm_type.value === 'manual'", - awPopOverWatch: "urlPopover", - awPopOver: "set in controllers/projects", - dataTitle: 'SCM URL', - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - scm_branch: { - labelBind: "scmBranchLabel", - type: 'text', - ngShow: "scm_type && scm_type.value !== 'manual' && scm_type.value !== 'insights'", - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm', - }, - credential: { - labelBind: 'credentialLabel', - type: 'lookup', - basePath: 'credentials', - list: 'CredentialList', - search: { - credential_type: null - }, - ngClick: 'lookupCredential()', - awRequiredWhen: { - reqExpression: "credRequired", - init: false - }, - ngShow: "scm_type && scm_type.value !== 'manual'", - sourceModel: 'credential', - awLookupType: '{{lookupType}}', - sourceField: 'name', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - checkbox_group: { - label: i18n._('SCM Update Options'), - type: 'checkbox_group', - ngShow: "scm_type && scm_type.value !== 'manual'", - subForm: 'sourceSubForm', - fields: [{ - name: 'scm_clean', - label: i18n._('Clean'), - type: 'checkbox', - awPopOver: '

' + i18n._('Remove any local modifications prior to performing an update.') + '

', - dataTitle: i18n._('SCM Clean'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options stack-inline', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, { - name: 'scm_delete_on_update', - label: i18n._('Delete on Update'), - type: 'checkbox', - awPopOver: '

' + i18n._('Delete the local repository in its entirety prior to performing an update.') + '

' + i18n._('Depending on the size of the ' + - 'repository this may significantly increase the amount of time required to complete an update.') + '

', - dataTitle: i18n._('SCM Delete'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options stack-inline', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, { - name: 'scm_update_on_launch', - label: i18n._('Update Revision on Launch'), - type: 'checkbox', - awPopOver: '

' + i18n._('Each time a job runs using this project, update the revision of the project prior to starting the job.') + '

', - dataTitle: i18n._('SCM Update'), - dataContainer: 'body', - dataPlacement: 'right', - labelClass: 'checkbox-options stack-inline', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }] - }, - scm_update_cache_timeout: { - label: i18n.sprintf(i18n._('Cache Timeout%s (seconds)%s'), '', ''), - id: 'scm-cache-timeout', - type: 'number', - integer: true, - min: 0, - ngShow: "scm_update_on_launch && scm_type.value !== 'manual'", - spinner: true, - "default": '0', - awPopOver: '

' + i18n._('Time in seconds to consider a project to be current. During job runs and callbacks the task system will ' + - 'evaluate the timestamp of the latest project update. If it is older than Cache Timeout, it is not considered current, ' + - 'and a new project update will be performed.') + '

', - dataTitle: i18n._('Cache Timeout'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', - subForm: 'sourceSubForm' - }, - custom_virtualenv: { - label: i18n._('Ansible Environment'), - type: 'select', - defaultText: i18n._('Default Environment'), - ngOptions: 'venv for venv in custom_virtualenvs_options track by venv', - awPopOver: "

" + i18n._("Select the custom Python virtual environment for this project to run on.") + "

", - dataTitle: i18n._('Ansible Environment'), - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', - ngShow: 'custom_virtualenvs_options.length > 0' - }, - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - permissions: { - name: 'permissions', - awToolTip: i18n._('Please save before assigning permissions.'), - djangoModel: 'access_list', - dataPlacement: 'top', - basePath: 'api/v2/projects/{{$stateParams.project_id}}/access_list/', - search: { - order_by: 'username' - }, - type: 'collection', - title: i18n._('Permissions'), - iterator: 'permission', - index: false, - open: false, - actions: { - add: { - ngClick: "$state.go('.add')", - label: 'Add', - awToolTip: i18n._('Add a permission'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - fields: { - username: { - label: i18n._('User'), - uiSref: 'users({user_id: field.id})', - class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' - }, - role: { - label: i18n._('Role'), - type: 'role', - nosort: true, - class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', - }, - team_roles: { - label: i18n._('Team Roles'), - type: 'team_roles', - nosort: true, - class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4', - } - } - }, - notifications: { - include: "NotificationsList", - }, - templates: { - include: "TemplateList", - }, - schedules: { - title: i18n._('Schedules'), - skipGenerator: true, - ngClick: "$state.go('projects.edit.schedules')" - } - } - - }; - - var itm; - - for (itm in projectsFormObj.related) { - if (projectsFormObj.related[itm].include === "TemplateList") { - projectsFormObj.related[itm] = _.clone(TemplateList); - projectsFormObj.related[itm].title = i18n._('Job Templates'); - projectsFormObj.related[itm].skipGenerator = true; - } - if (projectsFormObj.related[itm].include === "NotificationsList") { - projectsFormObj.related[itm] = NotificationsList; - projectsFormObj.related[itm].generateList = true; // tell form generator to call list generator and inject a list - } - } - return projectsFormObj; -};}]; diff --git a/awx/ui/client/src/projects/projects.list.js b/awx/ui/client/src/projects/projects.list.js deleted file mode 100644 index 06fcd7d1d484..000000000000 --- a/awx/ui/client/src/projects/projects.list.js +++ /dev/null @@ -1,137 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - - name: 'projects', - iterator: 'project', - basePath: 'projects', - selectTitle: i18n._('Add Project'), - editTitle: i18n._('PROJECTS'), - listTitle: i18n._('PROJECTS'), - selectInstructions: '

Select existing projects by clicking each project or checking the related checkbox. When finished, click the blue ' + - 'Select button, located bottom right.

Create a new project by clicking the button.

', - index: false, - hover: true, - emptyListText: i18n._('No Projects Have Been Created'), - - fields: { - status: { - label: '', - iconOnly: true, - ngClick: 'showSCMStatus(project.id)', - awToolTip: '{{ project.statusTip }}', - dataTipWatch: 'project.statusTip', - dataPlacement: 'right', - icon: "icon-job-{{ project.statusIcon }}", - columnClass: "List-staticColumn--smallStatus", - nosort: true, - excludeModal: true - }, - name: { - key: true, - label: i18n._('Name'), - columnClass: "col-lg-4 col-md-4 col-sm-4 col-xs-7 List-staticColumnAdjacent", - modalColumnClass: 'col-md-8', - awToolTip: '{{project.description | sanitize}}', - dataPlacement: 'top' - }, - scm_type: { - label: i18n._('Type'), - ngBind: 'project.type_label', - excludeModal: true, - columnClass: 'col-lg-2 col-md-2 col-sm-2 hidden-xs' - }, - scm_revision: { - label: i18n._('Revision'), - excludeModal: true, - columnClass: 'List-tableCell col-lg-2 col-md-2 hidden-sm hidden-xs', - type: 'revision' - }, - last_updated: { - label: i18n._('Last Updated'), - filter: "longDate", - columnClass: "col-lg-3 hidden-md hidden-sm hidden-xs", - excludeModal: true, - nosort: true - } - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refresh()", - ngShow: "socketStatus === 'error'", - actionClass: 'btn List-buttonDefault', - buttonContent: i18n._('REFRESH') - }, - add: { - mode: 'all', // One of: edit, select, all - ngClick: 'addProject()', - awToolTip: i18n._('Create a new project'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: "canAdd" - } - }, - - fieldActions: { - - columnClass: 'col-lg-4 col-md-3 col-sm-4 col-xs-5', - edit: { - ngClick: "editProject(project.id)", - awToolTip: i18n._('Edit the project'), - dataPlacement: 'top', - ngShow: "project.summary_fields.user_capabilities.edit" - }, - scm_update: { - ngClick: 'SCMUpdate(project.id, $event)', - awToolTip: "{{ project.scm_update_tooltip }}", - dataTipWatch: "project.scm_update_tooltip", - ngClass: "project.scm_type_class", - dataPlacement: 'top', - ngShow: "project.summary_fields.user_capabilities.start" - }, - schedule: { - mode: 'all', - ngClick: "editSchedules(project.id)", - awToolTip: "{{ project.scm_schedule_tooltip }}", - ngClass: "project.scm_type_class", - dataPlacement: 'top', - ngShow: "project.summary_fields.user_capabilities.schedule" - }, - copy: { - label: i18n._('Copy'), - ngClick: 'copyProject(project)', - "class": 'btn-danger btn-xs', - awToolTip: i18n._('Copy project'), - dataPlacement: 'top', - ngShow: 'project.summary_fields.user_capabilities.copy' - }, - view: { - ngClick: "editProject(project.id)", - awToolTip: i18n._('View the project'), - dataPlacement: 'top', - ngShow: "!project.summary_fields.user_capabilities.edit", - icon: 'fa-eye', - }, - "delete": { - ngClick: "deleteProject(project.id, project.name)", - awToolTip: i18n._('Delete the project'), - ngShow: "(project.status !== 'updating' && project.status !== 'running' && project.status !== 'pending' && project.status !== 'waiting') && project.summary_fields.user_capabilities.delete", - dataPlacement: 'top' - }, - cancel: { - ngClick: "cancelUpdate(project)", - awToolTip: i18n._('Cancel the SCM update'), - ngShow: "(project.status == 'updating' || project.status == 'running' || project.status == 'pending' || project.status == 'waiting') && project.summary_fields.user_capabilities.start", - dataPlacement: 'top', - ngDisabled: "project.pending_cancellation || project.status == 'canceled'" - } - } - };}]; diff --git a/awx/ui/client/src/projects/projects.strings.js b/awx/ui/client/src/projects/projects.strings.js deleted file mode 100644 index 37e4141a7b4c..000000000000 --- a/awx/ui/client/src/projects/projects.strings.js +++ /dev/null @@ -1,7 +0,0 @@ -function ProjectsStrings (BaseString) { - BaseString.call(this, 'projects'); -} - -ProjectsStrings.$inject = ['BaseStringService']; - -export default ProjectsStrings; diff --git a/awx/ui/client/src/rest/get-choices.factory.js b/awx/ui/client/src/rest/get-choices.factory.js deleted file mode 100644 index e9f7e4398da3..000000000000 --- a/awx/ui/client/src/rest/get-choices.factory.js +++ /dev/null @@ -1,57 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:Permissions - * @description - * Gets permission type labels from the API and sets them as the permissions labels on the relevant radio buttons - * - */ - - export default - ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { - return function (params) { - var scope = params.scope, - url = params.url, - field = params.field, - options = params.options; - - if (!options) { - // Auto populate the field if there is only one result - Rest.setUrl(url); - return Rest.options() - .then(function (data) { - data = data.data; - var choices = data.actions.GET[field].choices; - - // manually add the adhoc label to the choices object if - // the permission_type field - if (field === "permission_type") { - choices.push(["adhoc", - data.actions.GET.run_ad_hoc_commands.help_text]); - } - - return choices; - }) - .catch(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get ' + field + ' labels. Options requrest returned status: ' + status }); - }); - } else { - var choices = options.actions.GET[field].choices; - - // manually add the adhoc label to the choices object if - // the permission_type field - if (field === "permission_type") { - choices.push(["adhoc", - options.actions.GET.run_ad_hoc_commands.help_text]); - } - - return choices; - } - }; - }]; diff --git a/awx/ui/client/src/rest/get-labels.factory.js b/awx/ui/client/src/rest/get-labels.factory.js deleted file mode 100644 index 2b20ca70bb4a..000000000000 --- a/awx/ui/client/src/rest/get-labels.factory.js +++ /dev/null @@ -1,26 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:Permissions - * @description - * Gets permission type labels from the API and sets them as the permissions labels on the relevant radio buttons - * - */ - - export default - [function() { - return function (params) { - // convert the choices from the API from the format - // [["read", "Read Inventory"], ...] to - // {read: "Read Inventory", ...} - return params.choices.reduce(function(obj, kvp) { - obj[kvp[0]] = kvp[1]; - return obj; - }, {}); - }; - }]; diff --git a/awx/ui/client/src/rest/interceptors.service.js b/awx/ui/client/src/rest/interceptors.service.js deleted file mode 100644 index e30b1d5b9947..000000000000 --- a/awx/ui/client/src/rest/interceptors.service.js +++ /dev/null @@ -1,35 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - [ '$rootScope', '$q', '$injector', - function ($rootScope, $q, $injector) { - return { - response: function(config) { - if(config.headers('auth-token-timeout') !== null){ - $rootScope.loginConfig.promise.then(function () { - $AnsibleConfig.session_timeout = Number(config.headers('auth-token-timeout')); - }); - } - return config; - }, - responseError: function(rejection){ - if(rejection && rejection.data && rejection.data.detail && rejection.data.detail === "Maximum per-user sessions reached"){ - $rootScope.sessionTimer.expireSession('session_limit'); - var state = $injector.get('$state'); - state.go('signOut'); - return $q.reject(rejection); - } - return $q.reject(rejection); - } - }; - }]; diff --git a/awx/ui/client/src/rest/main.js b/awx/ui/client/src/rest/main.js deleted file mode 100644 index 5466355a1212..000000000000 --- a/awx/ui/client/src/rest/main.js +++ /dev/null @@ -1,20 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import restServicesFactory from './restServices.factory'; -import interceptors from './interceptors.service'; -import fieldChoices from './get-choices.factory'; -import fieldLabels from './get-labels.factory'; - -export default - angular.module('RestServices', []) - .config(['$httpProvider', function($httpProvider) { - $httpProvider.interceptors.push('RestInterceptor'); - }]) - .factory('Rest', restServicesFactory) - .service('RestInterceptor', interceptors) - .factory('fieldChoices', fieldChoices) - .factory('fieldLabels', fieldLabels); diff --git a/awx/ui/client/src/rest/restServices.factory.js b/awx/ui/client/src/rest/restServices.factory.js deleted file mode 100644 index e562b68b266b..000000000000 --- a/awx/ui/client/src/rest/restServices.factory.js +++ /dev/null @@ -1,210 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name shared.function:RestServices - * @description - * - * A wrapper for angular's $http service. Post user authentication API requests should go through Rest rather than directly using $http. The goal is to decouple - * the application from $http, allowing Rest or anything that provides the same methods to handle setting authentication headers and performing tasks such as checking - * for an expired authentication token. Having this buffer between the application and $http will prove useful should the authentication scheme change. - * - * #.setUrl() - * - * Before calling an action methods (i.e. get, put, post, destroy, options) to send the request, call setUrl. Pass a string containing the URL endpoint and any parameters. - * Note that $http will automaticall encode the URL, replacing spaces and special characters with appropriate %hex codes. Example URL values might include: - * - * ``` - * /api/v2/inventories/9/ - * /api/v2/credentials/?name=SSH Key&kind=ssh - * ``` - * - * When constructing the URL be sure to use the GetBasePath() method found in js/shared/Utilities.js. GetBasePath uses the response objects from /api and - * /api//to construct the base portion of the path. This way the API version number and base endpoints are not hard-coded within the application. - * - * #Action methods: .get(), put(), .post(), .destroy(), options() - * - * Use the method matching the REST action to be performed. In the case of put, post and destroy a JSON object can be passed as a parameter. If included, - * it will be sent as part of the request. - * - * In every case a call to an action method returns a promise object, allowing the caller to pass reponse functions to the promise methods. The functions can inspect - * the respoinse details and initiate action. For example: - * - * ``` - * var url = GetBasePath('inventories') + $stateParams.id + '/'; - * Rest.setUrl(url); - * Rest.get() - * .then(({data}) => { - * // review the data object and take action - * }) - * .error(function(status, data) { - * // handle the error - typically a call to ProcessErrors() found in js/shared/Utitlties.js - * }); - * ``` - * - * ##Options Reqeusts - * - * options() requests are used by the GetChoices() method found in js/shared/Utilities.js. Sending an Options request to an API endpoint returns an object that includes - * possible values for fields that are typically presented in the UI as dropdowns or <select> elements. GetChoices will inspect the response object for the request - * field and return an array of { label: 'Choice Label', value: 'choice 1' } objects. - * - */ - -export default - ['$http', '$rootScope', '$q', - function ($http, $rootScope, $q) { - return { - - headers: {}, - - setUrl: function (url) { - // Ensure that a trailing slash is present at the end of the url (before query params, etc) - this.url = url.replace(/\/?(\?|#|$)/, '/$1'); - }, - checkExpired: function () { - return ($rootScope.sessionTimer) ? $rootScope.sessionTimer.isExpired() : false; - }, - pReplace: function () { - //in our url, replace :xx params with a value, assuming - //we can find it in user supplied params. - var key, rgx; - for (key in this.params) { - rgx = new RegExp("\\:" + key, 'gm'); - if (rgx.test(this.url)) { - this.url = this.url.replace(rgx, this.params[key]); - delete this.params[key]; - } - } - }, - createResponse: function (data, status) { - // Simulate an http response when a token error occurs - // http://stackoverflow.com/questions/18243286/angularjs-promises-simulate-http-promises - - var promise = $q.reject({ - data: data, - status: status - }); - promise.success = function (fn) { - promise.then(function (response) { - fn(response.data, response.status); - }, null); - return promise; - }; - promise.error = function (fn) { - promise.then(null, function (response) { - fn(response.data, response.status); - }); - return promise; - }; - return promise; - }, - - setHeader: function (hdr) { - // Pass in { key: value } pairs to be added to the header - for (var h in hdr) { - this.headers[h] = hdr[h]; - } - }, - get: function (args) { - args = (args) ? args : {}; - this.params = (args.params) ? args.params : null; - this.pReplace(); - var expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - return $http({ - method: 'GET', - url: this.url, - headers: this.headers, - params: this.params - }); - } - }, - post: function (data) { - var expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - return $http({ - method: 'POST', - url: this.url, - headers: this.headers, - data: data - }); - } - }, - put: function (data) { - var expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - return $http({ - method: 'PUT', - url: this.url, - headers: this.headers, - data: data - }); - } - }, - patch: function (data) { - var expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - return $http({ - method: 'PATCH', - url: this.url, - headers: this.headers, - data: data - }); - } - }, - destroy: function (data) { - var expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - return $http({ - method: 'DELETE', - url: this.url, - headers: this.headers, - data: data - }); - } - }, - options: function (cache) { - var params, - expired = this.checkExpired(); - if (expired) { - return this.createResponse({ - detail: 'Session is expired' - }, 401); - } else { - params = { - method: 'OPTIONS', - url: this.url, - headers: this.headers, - data: '', - cache: (cache ? true : false) - }; - return $http(params); - } - } - }; - } - ]; diff --git a/awx/ui/client/src/scheduler/editSchedule.resolve.js b/awx/ui/client/src/scheduler/editSchedule.resolve.js deleted file mode 100644 index f65dc17b9c3d..000000000000 --- a/awx/ui/client/src/scheduler/editSchedule.resolve.js +++ /dev/null @@ -1,38 +0,0 @@ -function editScheduleResolve () { - const resolve = { - scheduleResolve: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', - (Rest, $stateParams, GetBasePath, ProcessErrors) => { - var path = `${GetBasePath('schedules')}${parseInt($stateParams.schedule_id)}/`; - Rest.setUrl(path); - return Rest.get() - .then(function(data) { - return (data.data); - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get schedule info. GET returned status: ' + - response.status - }); - }); - } - ], - timezonesResolve: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', - (Rest, $stateParams, GetBasePath, ProcessErrors) => { - var path = `${GetBasePath('schedules')}zoneinfo`; - Rest.setUrl(path); - return Rest.get() - .then(function(data) { - return (data.data); - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get zoneinfo. GET returned status: ' + - response.status - }); - }); - } - ] - }; - return resolve; -} -export default editScheduleResolve; diff --git a/awx/ui/client/src/scheduler/factories/delete-schedule.factory.js b/awx/ui/client/src/scheduler/factories/delete-schedule.factory.js deleted file mode 100644 index 232102805582..000000000000 --- a/awx/ui/client/src/scheduler/factories/delete-schedule.factory.js +++ /dev/null @@ -1,70 +0,0 @@ -export default - function DeleteSchedule(GetBasePath, Rest, Wait, $state, - ProcessErrors, Prompt, Find, $location, $filter) { - return function(params) { - var scope = params.scope, - id = params.id, - callback = params.callback, - action, schedule, list, url, hdr; - - if (scope.schedules) { - list = scope.schedules; - } - else if (scope.scheduled_jobs) { - list = scope.scheduled_jobs; - } - - url = GetBasePath('schedules') + id + '/'; - schedule = Find({list: list, key: 'id', val: id }); - hdr = 'Delete Schedule'; - - action = function () { - Wait('start'); - Rest.setUrl(url); - Rest.destroy() - .then(() => { - $('#prompt-modal').modal('hide'); - scope.$emit(callback, id); - - let reloadListStateParams = null; - - if(scope.schedules.length === 1 && $state.params.schedule_search && !_.isEmpty($state.params.schedule_search.page) && $state.params.schedule_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.schedule_search.page = (parseInt(reloadListStateParams.schedule_search.page)-1).toString(); - } - - if (parseInt($state.params.schedule_id) === id) { - $state.go('^', reloadListStateParams, {reload: true}); - } - else{ - $state.go('.', reloadListStateParams, {reload: true}); - } - }) - .catch(({data, status}) => { - try { - $('#prompt-modal').modal('hide'); - } - catch(e) { - // ignore - } - ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - ' failed. DELETE returned: ' + status }); - }); - }; - - Prompt({ - hdr: hdr, - resourceName: $filter('sanitize')(schedule.name), - body: '
Are you sure you want to delete this schedule?
', - action: action, - actionText: 'DELETE', - backdrop: false - }); - }; - } - -DeleteSchedule.$inject = - [ 'GetBasePath','Rest', 'Wait', '$state', - 'ProcessErrors', 'Prompt', 'Find', '$location', - '$filter' - ]; diff --git a/awx/ui/client/src/scheduler/factories/r-rule-to-api.factory.js b/awx/ui/client/src/scheduler/factories/r-rule-to-api.factory.js deleted file mode 100644 index 9c86205559a8..000000000000 --- a/awx/ui/client/src/scheduler/factories/r-rule-to-api.factory.js +++ /dev/null @@ -1,30 +0,0 @@ -export default - function RRuleToAPI() { - - // This function removes the 'Z' from the UNTIL portion of the - // rrule. The API will default to using the timezone that is - // specified in the TZID as the locale for the UNTIL. - function parseOutZ (rrule) { - let until = rrule.split('UNTIL='); - if(_.has(until, '1')){ - rrule = until[0]; - until = until[1].replace('Z', ''); - return `${rrule}UNTIL=${until}`; - } else { - return rrule; - } - } - - - return function(rrule, scope) { - let localTime = scope.schedulerLocalTime; - let timeZone = scope.schedulerTimeZone.name; - - let response = rrule.replace(/(^.*(?=DTSTART))(DTSTART.*?)(=.*?;)(.*$)/, (str, p1, p2, p3, p4) => { - return p2 + ';TZID=' + timeZone + ':' + localTime + ' ' + 'RRULE:' + p4; - }); - - response = parseOutZ(response); - return response; - }; - } diff --git a/awx/ui/client/src/scheduler/factories/schedule-post.factory.js b/awx/ui/client/src/scheduler/factories/schedule-post.factory.js deleted file mode 100644 index 619d2670a9c3..000000000000 --- a/awx/ui/client/src/scheduler/factories/schedule-post.factory.js +++ /dev/null @@ -1,164 +0,0 @@ -export default - function SchedulePost(Rest, ProcessErrors, RRuleToAPI, Wait, $q, Schedule, PromptService) { - return function(params) { - var scope = params.scope, - url = params.url, - scheduler = params.scheduler, - mode = params.mode, - scheduleData = (params.schedule) ? params.schedule : {}, - promptData = params.promptData, - priorCredentials = params.priorCredentials ? params.priorCredentials : [], - newSchedule, rrule, extra_vars; - const deferred = $q.defer(); - if (scheduler.isValid()) { - Wait('start'); - newSchedule = scheduler.getValue(); - rrule = scheduler.getRRule(); - scheduleData.name = newSchedule.name; - scheduleData.rrule = RRuleToAPI(rrule.toString(), scope); - scheduleData.description = (/error/.test(rrule.toText())) ? '' : rrule.toText(); - - if (scope.cleanupJob) { - extra_vars = { - "days" : scope.scheduler_form.schedulerPurgeDays.$viewValue - }; - scheduleData.extra_data = JSON.stringify(extra_vars); - } - else if(scope.extraVars){ - scheduleData.extra_data = scope.parseType === 'yaml' ? - (scope.extraVars === '---' ? "" : jsyaml.safeLoad(scope.extraVars)) : scope.extraVars; - } - - if(promptData) { - scheduleData = PromptService.bundlePromptDataForSaving({ - promptData: promptData, - dataToSave: scheduleData - }); - } - - Rest.setUrl(url); - if (mode === 'add') { - Rest.post(scheduleData) - .then(({data}) => { - if(_.get(promptData, 'launchConf.ask_credential_on_launch')){ - // This finds the credentials that were selected in the prompt but don't occur - // in the template defaults - const credentialsToPost = promptData.prompts.credentials.value.filter(function(credFromPrompt) { - const defaultCreds = promptData.launchConf.defaults.credentials ? promptData.launchConf.defaults.credentials : []; - return !defaultCreds.some(function(defaultCred) { - return credFromPrompt.id === defaultCred.id; - }); - }); - - const promises = []; - const schedule = new Schedule(); - - credentialsToPost.forEach((credentialToPost) => { - promises.push(schedule.postCredential({ - id: data.id, - data: { - id: credentialToPost.id - } - })); - }); - - $q.all(promises) - .then(() => { - Wait('stop'); - deferred.resolve(); - }); - } else { - Wait('stop'); - deferred.resolve(); - } - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'POST to ' + url + ' returned: ' + status }); - - deferred.reject(); - }); - } - else { - Rest.put(scheduleData) - .then(({data}) => { - if(_.get(promptData, 'launchConf.ask_credential_on_launch')){ - const credentialsNotInPriorCredentials = promptData.prompts.credentials.value.filter(function(credFromPrompt) { - const defaultCreds = promptData.launchConf.defaults.credentials ? promptData.launchConf.defaults.credentials : []; - return !defaultCreds.some(function(defaultCred) { - return credFromPrompt.id === defaultCred.id; - }); - }); - - const credentialsToAdd = credentialsNotInPriorCredentials.filter(function(credNotInPrior) { - return !priorCredentials.some(function(priorCred) { - return credNotInPrior.id === priorCred.id; - }); - }); - - const credentialsToRemove = priorCredentials.filter(function(priorCred) { - return !credentialsNotInPriorCredentials.some(function(credNotInPrior) { - return priorCred.id === credNotInPrior.id; - }); - }); - - const promises = []; - const schedule = new Schedule(); - - credentialsToAdd.forEach((credentialToAdd) => { - promises.push(schedule.postCredential({ - id: data.id, - data: { - id: credentialToAdd.id - } - })); - }); - - credentialsToRemove.forEach((credentialToRemove) => { - promises.push(schedule.postCredential({ - id: data.id, - data: { - id: credentialToRemove.id, - disassociate: true - } - })); - }); - - $q.all(promises) - .then(() => { - Wait('stop'); - deferred.resolve(); - }); - } else { - Wait('stop'); - deferred.resolve(); - } - - Wait('stop'); - deferred.resolve(scheduleData); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'POST to ' + url + ' returned: ' + status }); - - deferred.reject(); - }); - } - } - else { - deferred.reject(); - } - - return deferred.promise; - }; - } - -SchedulePost.$inject = - [ 'Rest', - 'ProcessErrors', - 'RRuleToAPI', - 'Wait', - '$q', - 'ScheduleModel', - 'PromptService' - ]; diff --git a/awx/ui/client/src/scheduler/factories/toggle-schedule.factory.js b/awx/ui/client/src/scheduler/factories/toggle-schedule.factory.js deleted file mode 100644 index 5c2b04e395c2..000000000000 --- a/awx/ui/client/src/scheduler/factories/toggle-schedule.factory.js +++ /dev/null @@ -1,46 +0,0 @@ -export default - function ToggleSchedule(Wait, GetBasePath, ProcessErrors, Rest, $state) { - return function(params) { - var scope = params.scope, - id = params.id, - url = GetBasePath('schedules') + id +'/'; - - // Perform the update - if (scope.removeScheduleFound) { - scope.removeScheduleFound(); - } - scope.removeScheduleFound = scope.$on('ScheduleFound', function(e, data) { - data.enabled = (data.enabled) ? false : true; - Rest.put(data) - .then(() => { - Wait('stop'); - $state.go('.', null, {reload: true}); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to update schedule ' + id + ' PUT returned: ' + status }); - }); - }); - - Wait('start'); - - // Get the schedule - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - scope.$emit('ScheduleFound', data); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve schedule ' + id + ' GET returned: ' + status }); - }); - }; - } - -ToggleSchedule.$inject = - [ 'Wait', - 'GetBasePath', - 'ProcessErrors', - 'Rest', - '$state' - ]; diff --git a/awx/ui/client/src/scheduler/main.js b/awx/ui/client/src/scheduler/main.js deleted file mode 100644 index 038053e83a5f..000000000000 --- a/awx/ui/client/src/scheduler/main.js +++ /dev/null @@ -1,29 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import listController from './schedulerList.controller'; -import addController from './schedulerAdd.controller'; -import editController from './schedulerEdit.controller'; -import schedulerDatePicker from './schedulerDatePicker.directive'; -import DeleteSchedule from './factories/delete-schedule.factory'; -import RRuleToAPI from './factories/r-rule-to-api.factory'; -import SchedulePost from './factories/schedule-post.factory'; -import ToggleSchedule from './factories/toggle-schedule.factory'; -import SchedulesList from './schedules.list'; -import ScheduledJobsList from './scheduled-jobs.list'; - -export default - angular.module('scheduler', []) - .controller('schedulerListController', listController) - .controller('schedulerAddController', addController) - .controller('schedulerEditController', editController) - .factory('DeleteSchedule', DeleteSchedule) - .factory('RRuleToAPI', RRuleToAPI) - .factory('SchedulePost', SchedulePost) - .factory('ToggleSchedule', ToggleSchedule) - .factory('SchedulesList', SchedulesList) - .factory('ScheduledJobsList', ScheduledJobsList) - .directive('schedulerDatePicker', schedulerDatePicker); diff --git a/awx/ui/client/src/scheduler/repeatFrequencyOptions.block.less b/awx/ui/client/src/scheduler/repeatFrequencyOptions.block.less deleted file mode 100644 index ae9dafb7723e..000000000000 --- a/awx/ui/client/src/scheduler/repeatFrequencyOptions.block.less +++ /dev/null @@ -1,176 +0,0 @@ -/** @define RepeatFrequencyOptions */ - -.RepeatFrequencyOptions { - width: ~"calc(100% + 21px)"; - padding: 20px; - border-left: 5px solid @default-border; - margin-left: -20px; - padding-left: 17px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; - align-items: flex-start; -} - -.RepeatFrequencyOptions-formGroup { - padding-right: 0px; -} - -@media (min-width: 901px) { - .RepeatFrequencyOptions-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: ~"calc(33% - 32px)"; - margin-right: 50px; - } - - .RepeatFrequencyOptions-formGroup:nth-child(3n+3) { - flex: 0 0 auto; - margin-bottom: 25px; - margin-right: 0px; - } -} - -@media (min-width: 651px) and (max-width: 900px) { - .RepeatFrequencyOptions-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: ~"calc(50% - 25px)"; - margin-right: 50px; - } - - .RepeatFrequencyOptions-formGroup:nth-child(2n+2) { - flex: 0 0 auto; - margin-bottom: 25px; - margin-right: 0px; - } -} - -@media (max-width: 650px) { - .RepeatFrequencyOptions-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: 100%; - margin-right: 0px; - } -} - -.RepeatFrequencyOptions-label { - width: 100%; - margin-top: -2px; - text-transform: uppercase; - font-weight: bold; - color: @default-interface-txt; - font-size: 13px; - margin-left: -20px; - border-left: 5px solid @default-border; - padding-left: 15px; - padding-bottom: 15px; -} - -.RepeatFrequencyOptions-weekButtonContainer { - width: 100%; -} - -.RepeatFrequencyOptions-weekButtonGroup { - height: 27px; - width: 100%; - display: flex; -} - -.RepeatFrequencyOptions-weekButton { - height: 27px; - padding-top: 2px; - padding-right: 4px; - padding-left: 4px; - flex: 1; -} - -.RepeatFrequencyOptions-weekButton.active { - background-color: @default-list-header-bg !important; - border-color: @d7grey !important; -} - -.RepeatFrequencyOptions-everyGroup { - display: flex; - flex-wrap: wrap; - align-items: baseline; -} - -.RepeatFrequencyOptions-inlineLabel { - font-weight: normal; - color: @default-interface-txt; - text-transform: uppercase; - flex: initial; - width: 54px; - margin-left: 10px; - font-size: 13px; -} - -.RepeatFrequencyOptions-occurencesGroup { - width: 100%; -} - -.RepeatFrequencyOptions-radioLabel { - margin-top: 0px; - margin-bottom: 5px; -} - -.RepeatFrequencyOptions-everyLabel { - margin-top: 2px; -} - -.RepeatFrequencyOptions-spacedSelect, -.RepeatFrequencyOptions-spacedSelect ~ .select2 { - margin-bottom: 10px; -} - -.RepeatFrequencyOptions-subFormBorderFixer { - height: 25px; - width: 5px; - background: @default-bg; - margin-left: -20px; - margin-top: -25px; - margin-right: 50px; -} - -.RepeatFrequencyOptions-monthlyOccurence, -.RepeatFrequencyOptions-yearlyOccurence { - text-transform: capitalize; -} - -.RepeatFrequencyOptions-error { - flex: initial; - width: 100%; -} - -.RepeatFrequencyOptions-nameBorderErrorFix { - border-color: @default-err !important; -} - -.RepeatFrequencyOptions-inputGroup { - display: flex; - justify-content: space-between; -} - -.RepeatFrequencyOptions-inputGroup--thirds > .select2 { - width: ~"calc(33% - 3px)" !important; -} - -.RepeatFrequencyOptions-inputGroup--halves > .select2 { - width: ~"calc(50% - 3px)" !important; -} - -.RepeatFrequencyOptions-inputGroup--halvesWithNumber > .select2 { - width: ~"calc(50% - 3px)" !important; - margin-right: 7px; -} - -.RepeatFrequencyOptions-inputGroup--halvesWithSelect > .select2 { - width: ~"calc(50% - 3px)" !important; - margin-left: 7px; -} - -.RepeatFrequencyOptions-inputGroup--halvesWithSelect > .RepeatFrequencyOptions-number { - width: ~"calc(50% - 3px)" !important; -} diff --git a/awx/ui/client/src/scheduler/scheduleToggle.block.less b/awx/ui/client/src/scheduler/scheduleToggle.block.less deleted file mode 100644 index 8a9028105036..000000000000 --- a/awx/ui/client/src/scheduler/scheduleToggle.block.less +++ /dev/null @@ -1,77 +0,0 @@ -/** @define ScheduleToggle */ - -.Form-formGroup--disabled .ScheduleToggle { - cursor: not-allowed; - border-color: @default-link !important; - .ScheduleToggle-switch { - background-color: @d7grey !important; - cursor: not-allowed; - } -} - -.ScheduleToggle { - border-radius: 5px; - border: 1px solid @default-link; - background-color: @default-link; - margin-top: 2px; - cursor: pointer; - display: flex; - justify-content: flex-end; - width: 42px; - - &.ScheduleToggle--disabled { - cursor: not-allowed; - background-color: none; - border-color: @d7grey !important; - .ScheduleToggle-switch { - background-color: @d7grey !important; - cursor: not-allowed; - } - } -} - -.ScheduleToggle-switch { - color: @default-link; - background-color: @default-bg; - border-left: 1px solid @default-link; - text-align: center; - text-transform: uppercase; - font-size: 11px; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - padding: 0px 5px; - border-top: 0px; - border-bottom: 0px; - border-right: 0px; - height: 16px; - line-height: 16px; -} - -.ScheduleToggle.is-on { - border-color: @default-link; - background-color: @default-bg; - justify-content: flex-start; -} - -.ScheduleToggle-switch.is-on { - background-color: @default-link; - color: @default-bg; - border-left: 0; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - padding: 0 7px; -} - -.ScheduleToggle-switch:hover { - background-color: @default-tertiary-bg; -} - -.ScheduleToggle.is-on:hover { - border-color: @default-link-hov; -} - -.ScheduleToggle-switch.is-on:hover { - background-color: @default-link-hov; -} diff --git a/awx/ui/client/src/scheduler/scheduled-jobs.list.js b/awx/ui/client/src/scheduler/scheduled-jobs.list.js deleted file mode 100644 index 709a98bd3c90..000000000000 --- a/awx/ui/client/src/scheduler/scheduled-jobs.list.js +++ /dev/null @@ -1,86 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['i18n', function(i18n) { - return { - - name: 'schedules', - iterator: 'schedule', - editTitle: i18n._('SCHEDULED JOBS'), - hover: true, - well: false, - emptyListText: i18n._('No schedules exist'), - - fields: { - enabled: { - label: '', - columnClass: 'List-staticColumn--toggle', - type: 'toggle', - ngClick: "toggleSchedule($event, schedule.id)", - nosort: true, - awToolTip: "{{ schedule.play_tip }}", - ngDisabled: "!schedule.summary_fields.user_capabilities.edit", - dataTipWatch: "schedule.play_tip", - dataPlacement: 'top' - }, - name: { - label: i18n._('Name'), - columnClass: 'col-lg-4 col-md-5 col-sm-5 col-xs-7 List-staticColumnAdjacent', - sourceModel: 'unified_job_template', - sourceField: 'name', - // ngBind: 'schedule.summary_fields.unified_job_template.name', - ngClick: "editSchedule(schedule)", - awToolTip: "{{ schedule.nameTip | sanitize}}", - dataTipWatch: 'schedule.nameTip', - dataPlacement: "top", - }, - type: { - label: i18n._('Type'), - noLink: true, - columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs", - sourceModel: 'unified_job_template', - sourceField: 'unified_job_type', - ngBind: 'schedule.type_label', - searchField: 'unified_job_template__polymorphic_ctype__model' - }, - next_run: { - label: i18n._('Next Run'), - noLink: true, - columnClass: "col-lg-3 col-md-2 col-sm-3 hidden-xs", - filter: "longDate", - key: true - } - }, - - actions: { }, - - fieldActions: { - - columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-5', - "edit": { - mode: "all", - ngClick: "editSchedule(schedule)", - awToolTip: i18n._("Edit the schedule"), - dataPlacement: "top", - ngShow: 'schedule.summary_fields.user_capabilities.edit' - }, - "view": { - mode: "all", - ngClick: "editSchedule(schedule)", - awToolTip: i18n._("View the schedule"), - dataPlacement: "top", - ngShow: '!schedule.summary_fields.user_capabilities.edit' - }, - "delete": { - mode: 'all', - ngClick: 'deleteSchedule(schedule.id)', - awToolTip: i18n._('Delete the schedule'), - dataPlacement: 'top', - ngShow: 'schedule.summary_fields.user_capabilities.delete' - } - } - };}]; diff --git a/awx/ui/client/src/scheduler/scheduler.partial.html b/awx/ui/client/src/scheduler/scheduler.partial.html deleted file mode 100644 index cf51d106cec2..000000000000 --- a/awx/ui/client/src/scheduler/scheduler.partial.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
-
diff --git a/awx/ui/client/src/scheduler/schedulerAdd.controller.js b/awx/ui/client/src/scheduler/schedulerAdd.controller.js deleted file mode 100644 index 5c87f3c484cc..000000000000 --- a/awx/ui/client/src/scheduler/schedulerAdd.controller.js +++ /dev/null @@ -1,436 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$filter', '$state', '$stateParams', '$http', 'Wait', - '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', 'GetBasePath', - 'Rest', 'ParentObject', 'JobTemplateModel', '$q', 'Empty', 'SchedulePost', - 'ProcessErrors', 'SchedulerInit', '$location', 'PromptService', 'RRuleToAPI', 'moment', - 'WorkflowJobTemplateModel', 'TemplatesStrings', 'rbacUiControlService', - function($filter, $state, $stateParams, $http, Wait, - $scope, $rootScope, CreateSelect2, ParseTypeChange, GetBasePath, - Rest, ParentObject, JobTemplate, $q, Empty, SchedulePost, - ProcessErrors, SchedulerInit, $location, PromptService, RRuleToAPI, moment, - WorkflowJobTemplate, TemplatesStrings, rbacUiControlService - ) { - - var base = $scope.base || $location.path().replace(/^\//, '').split('/')[0], - scheduler, - job_type; - - var schedule_url = ParentObject.related.schedules || `${ParentObject.related.inventory_source}schedules`; - if (ParentObject){ - $scope.parentObject = ParentObject; - let scheduleEndpoint = ParentObject.endpoint|| ParentObject.related.schedules || `${ParentObject.related.inventory_source}schedules`; - $scope.canAdd = false; - rbacUiControlService.canAdd(scheduleEndpoint) - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - } - let processSchedulerEndDt = function(){ - // set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight - var dt = new Date($scope.schedulerUTCTime); - // increment date by 1 day - dt.setDate(dt.getDate() + 1); - var month = $filter('schZeroPad')(dt.getMonth() + 1, 2), - day = $filter('schZeroPad')(dt.getDate(), 2); - $scope.$parent.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear(); - }; - - $scope.preventCredsWithPasswords = true; - $scope.strings = TemplatesStrings; - - /* - * This is a workaround for the angular-scheduler library inserting `ll` into fields after an - * invalid entry and never unsetting them. Presumably null is being truncated down to 2 chars - * in that case. - * - * Because this same problem exists in the edit mode and because there's no inheritence, this - * block of code is duplicated in both add/edit controllers pending a much needed broader - * refactoring effort. - */ - $scope.timeChange = () => { - if (!Number($scope.schedulerStartHour)) { - $scope.schedulerStartHour = '00'; - } - - if (!Number($scope.schedulerStartMinute)) { - $scope.schedulerStartMinute = '00'; - } - - if (!Number($scope.schedulerStartSecond)) { - $scope.schedulerStartSecond = '00'; - } - - $scope.scheduleTimeChange(); - }; - - $scope.saveSchedule = function() { - SchedulePost({ - scope: $scope, - url: schedule_url, - scheduler: scheduler, - promptData: $scope.promptData, - mode: 'add' - }).then(() => { - Wait('stop'); - $state.go("^", null, {reload: true}); - }); - }; - - $scope.prompt = () => { - $scope.promptData.triggerModalOpen = true; - }; - - $scope.formCancel = function() { - $state.go("^"); - }; - - // initial end @ midnight values - $scope.schedulerEndHour = "00"; - $scope.schedulerEndMinute = "00"; - $scope.schedulerEndSecond = "00"; - $scope.parentObject = ParentObject; - - $scope.hideForm = true; - - // extra_data field is not manifested in the UI when scheduling a Management Job - if ($state.current.name === 'templates.editJobTemplate.schedules.add'){ - $scope.parseType = 'yaml'; - - let jobTemplate = new JobTemplate(); - - $q.all([jobTemplate.optionsLaunch(ParentObject.id), jobTemplate.getLaunch(ParentObject.id)]) - .then((responses) => { - let launchConf = responses[1].data; - - let watchForPromptChanges = () => { - let promptValuesToWatch = [ - 'promptData.prompts.inventory.value', - 'promptData.prompts.jobType.value', - 'promptData.prompts.verbosity.value', - 'missingSurveyValue' - ]; - - $scope.$watchGroup(promptValuesToWatch, function() { - let missingPromptValue = false; - if ($scope.missingSurveyValue) { - missingPromptValue = true; - } else if (!$scope.promptData.prompts.inventory.value || !$scope.promptData.prompts.inventory.value.id) { - missingPromptValue = true; - } - $scope.promptModalMissingReqFields = missingPromptValue; - }); - }; - - if (launchConf.ask_variables_on_launch) { - $scope.extraVars = ParentObject.extra_vars === '' ? '---' : ParentObject.extra_vars; - - ParseTypeChange({ - scope: $scope, - variable: 'extraVars', - parse_variable: 'parseType', - field_id: 'SchedulerForm-extraVars' - }); - } else { - $scope.noVars = true; - } - - if (!launchConf.survey_enabled && - !launchConf.ask_inventory_on_launch && - !launchConf.ask_credential_on_launch && - !launchConf.ask_verbosity_on_launch && - !launchConf.ask_job_type_on_launch && - !launchConf.ask_limit_on_launch && - !launchConf.ask_tags_on_launch && - !launchConf.ask_skip_tags_on_launch && - !launchConf.ask_diff_mode_on_launch && - !launchConf.survey_enabled && - !launchConf.credential_needed_to_start && - !launchConf.inventory_needed_to_start && - launchConf.passwords_needed_to_start.length === 0 && - launchConf.variables_needed_to_start.length === 0) { - $scope.showPromptButton = false; - } else { - $scope.showPromptButton = true; - - // Ignore the fact that variables might be promptable on launch - // Promptable variables will happen in the schedule form - launchConf.ignore_ask_variables = true; - - if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory')) { - $scope.promptModalMissingReqFields = true; - } - - if (launchConf.survey_enabled) { - // go out and get the survey questions - jobTemplate.getSurveyQuestions(ParentObject.id) - .then((surveyQuestionRes) => { - - let processed = PromptService.processSurveyQuestions({ - surveyQuestions: surveyQuestionRes.data.spec - }); - - $scope.missingSurveyValue = processed.missingSurveyValue; - - $scope.promptData = { - launchConf: responses[1].data, - launchOptions: responses[0].data, - surveyQuestions: processed.surveyQuestions, - template: ParentObject.id, - prompts: PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data - }), - }; - - $scope.$watch('promptData.surveyQuestions', () => { - let missingSurveyValue = false; - _.each($scope.promptData.surveyQuestions, (question) => { - if (question.required && (Empty(question.model) || question.model === [])) { - missingSurveyValue = true; - } - }); - $scope.missingSurveyValue = missingSurveyValue; - }, true); - - watchForPromptChanges(); - }); - } else { - $scope.promptData = { - launchConf: responses[1].data, - launchOptions: responses[0].data, - template: ParentObject.id, - prompts: PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data - }), - }; - - watchForPromptChanges(); - } - } - }); - } else if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.add'){ - let workflowJobTemplate = new WorkflowJobTemplate(); - - $q.all([workflowJobTemplate.optionsLaunch(ParentObject.id), workflowJobTemplate.getLaunch(ParentObject.id)]) - .then((responses) => { - let launchConf = responses[1].data; - - let watchForPromptChanges = () => { - $scope.$watch('missingSurveyValue', function() { - $scope.promptModalMissingReqFields = $scope.missingSurveyValue ? true : false; - }); - }; - - if(!launchConf.survey_enabled) { - $scope.showPromptButton = false; - } else { - $scope.showPromptButton = true; - - if(launchConf.survey_enabled) { - // go out and get the survey questions - workflowJobTemplate.getSurveyQuestions(ParentObject.id) - .then((surveyQuestionRes) => { - - let processed = PromptService.processSurveyQuestions({ - surveyQuestions: surveyQuestionRes.data.spec - }); - - $scope.missingSurveyValue = processed.missingSurveyValue; - - $scope.promptData = { - launchConf: responses[1].data, - launchOptions: responses[0].data, - surveyQuestions: processed.surveyQuestions, - template: ParentObject.id, - prompts: PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data - }), - }; - - $scope.$watch('promptData.surveyQuestions', () => { - let missingSurveyValue = false; - _.each($scope.promptData.surveyQuestions, (question) => { - if(question.required && (Empty(question.model) || question.model === [])) { - missingSurveyValue = true; - } - }); - $scope.missingSurveyValue = missingSurveyValue; - }, true); - - watchForPromptChanges(); - }); - } - else { - $scope.promptData = { - launchConf: responses[1].data, - launchOptions: responses[0].data, - template: ParentObject.id, - prompts: PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data - }), - }; - - watchForPromptChanges(); - } - } - }); - } - - if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.add' || - $state.current.name === 'projects.edit.schedules.add' || - $state.current.name === 'inventories.edit.inventory_sources.edit.schedules.add' - ){ - $scope.noVars = true; - } - - job_type = $scope.parentObject.job_type; - if (!Empty($stateParams.id) && base !== 'system_job_templates' && base !== 'inventories' && !schedule_url) { - schedule_url = GetBasePath(base) + $stateParams.id + '/schedules/'; - } else if (base === "inventories"){ - if (!schedule_url){ - Rest.setUrl(GetBasePath('groups') + $stateParams.id + '/'); - Rest.get() - .then(function (data) { - schedule_url = data.data.related.inventory_source + 'schedules/'; - }).catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get inventory group info. GET returned status: ' + - response.status - }); - }); - } - } else if (base === 'system_job_templates') { - schedule_url = GetBasePath(base) + $stateParams.id + '/schedules/'; - $scope.cleanupJob = true; - } - - Wait('start'); - $('#form-container').empty(); - scheduler = SchedulerInit({ scope: $scope, requireFutureStartTime: false }); - let timeZonesAPI = () => { - return $http.get(`/api/v2/schedules/zoneinfo/`); - }; - // set API timezones to scheduler object - timeZonesAPI().then(({data}) => { - scheduler.scope.timeZones = data; - scheduler.scope.schedulerTimeZone = _.find(data, (zone) => { - return zone.name === scheduler.scope.current_timezone.name; - }); - $scope.scheduleTimeChange(); - }); - if ($scope.schedulerUTCTime) { - // The UTC time is already set - processSchedulerEndDt(); - } else { - // We need to wait for it to be set by angular-scheduler because the following function depends - // on it - var schedulerUTCTimeWatcher = $scope.$watch('schedulerUTCTime', function(newVal) { - if (newVal) { - // Remove the watcher - schedulerUTCTimeWatcher(); - processSchedulerEndDt(); - } - }); - } - - let previewList = _.debounce(function(req) { - $http.post('/api/v2/schedules/preview/', {'rrule': req}) - .then(({data}) => { - $scope.preview_list = data; - let parsePreviewList = (tz) => { - return data[tz].map(function(date) { - date = date.replace(/Z/, ''); - return moment.parseZone(date).format("MM-DD-YYYY HH:mm:ss"); - }); - }; - for (let tz in data) { - $scope.preview_list.isEmpty = data[tz].length === 0; - $scope.preview_list[tz] = parsePreviewList(tz); - } - }); - }, 300); - - $scope.$on("setPreviewPane", (event) => { - let rrule = event.currentScope.rrule.toString(); - let req = RRuleToAPI(rrule, $scope); - previewList(req); - }); - - scheduler.inject('form-container', false); - scheduler.injectDetail('occurrences', false); - scheduler.clear(); - $scope.$on("htmlDetailReady", function() { - $scope.hideForm = false; - $scope.$on("formUpdated", function() { - $rootScope.$broadcast("loadSchedulerDetailPane"); - }); - $scope.$watchGroup(["schedulerName", - "schedulerStartDt", - "schedulerStartHour", - "schedulerStartMinute", - "schedulerStartSecond", - "schedulerTimeZone", - "schedulerFrequency", - "schedulerInterval", - "monthlyRepeatOption", - "monthDay", - "monthlyOccurrence", - "monthlyWeekDay", - "yearlyRepeatOption", - "yearlyMonth", - "yearlyMonthDay", - "yearlyOccurrence", - "yearlyWeekDay", - "yearlyOtherMonth", - "schedulerEnd", - "schedulerOccurrenceCount", - "schedulerEndDt", - "schedulerEndHour", - "schedulerEndMinute", - "schedularEndSecond" - ], function() { - $scope.$emit("formUpdated"); - }, true); - - $scope.$watch("weekDays", function() { - $scope.$emit("formUpdated"); - }, true); - - Wait('stop'); - }); - $scope.showRRuleDetail = false; - - $('#scheduler-tabs li a').on('shown.bs.tab', function(e) { - if ($(e.target).text() === 'Details') { - if (!scheduler.isValid()) { - $('#scheduler-tabs a:first').tab('show'); - } - } - }); - - var callSelect2 = function() { - CreateSelect2({ - element: '.MakeSelect2', - multiple: false - }); - $("#schedulerTimeZone").select2({ - width:'100%', - containerCssClass: 'Form-dropDown', - placeholder: 'SEARCH' - }); - }; - - $scope.$on("updateSchedulerSelects", function() { - callSelect2(); - }); - callSelect2(); -}]; diff --git a/awx/ui/client/src/scheduler/schedulerDatePicker.directive.js b/awx/ui/client/src/scheduler/schedulerDatePicker.directive.js deleted file mode 100644 index bcd4cc031d07..000000000000 --- a/awx/ui/client/src/scheduler/schedulerDatePicker.directive.js +++ /dev/null @@ -1,100 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/* jshint unused: vars */ - -export default - [ 'moment', - 'templateUrl', - function(moment, templateUrl) { - require('bootstrap-datepicker'); - return { - restrict: 'E', - scope: { - date: '=', - minDate: '=', - autoUpdate: '=?', - inputClass: '&', - disabled: '=?' - }, - templateUrl: templateUrl('system-tracking/date-picker/date-picker'), - link: function(scope, element, attrs) { - var lang = window.navigator.languages ? - window.navigator.languages[0] : - (window.navigator.language || - window.navigator.userLanguage); - moment.locale(lang); - // We need to make sure this _never_ recurses, which sometimes happens - // with two-way binding. - var mustUpdateValue = true; - scope.autoUpdate = scope.autoUpdate === false ? false : true; - - // convert the passed current date into the correct moment locale - scope.$watch('date', function(newValue) { - if (newValue) { - mustUpdateValue = false; - scope.dateValueMoment = moment(newValue, ['MM/DD/YYYY'], moment.locale()); - scope.dateValue = scope.dateValueMoment.format('L'); - element.find(".DatePicker").datepicker('update', scope.dateValue); - } - }, true); - - // as the date picker value changes, convert back to - // the english date to pass back into the scheduler lib - scope.$watch('dateValue', function(newValue) { - scope.dateValueMoment = moment(newValue, ['L'], moment.locale()); - scope.date = scope.dateValueMoment.locale('en').format('L'); - mustUpdateValue = true; - }); - - var localeData = - moment.localeData(); - var dateFormat = momentFormatToDPFormat(localeData._longDateFormat.L); - var localeKey = momentLocaleToDPLocale(moment.locale()); - - element.find(".DatePicker").addClass("input-prepend date"); - element.find(".DatePicker").find(".DatePicker-icon").addClass("add-on"); - element.find(".DatePicker").datepicker({ - autoclose: true, - language: localeKey, - format: dateFormat - }); - - function momentLocaleToDPLocale(localeKey) { - var parts = localeKey.split('-'); - - if (parts.length === 2) { - var lastPart = parts[1].toUpperCase(); - return [parts[0], lastPart].join('-'); - } else { - return localeKey; - } - - } - - function momentFormatToDPFormat(momentFormat) { - var resultFormat = momentFormat; - - function lowerCase(str) { - return str.toLowerCase(); - } - - resultFormat = resultFormat.replace(/D{1,2}/, lowerCase); - - if (/MMM/.test(resultFormat)) { - resultFormat = resultFormat.replace('MMM', 'M'); - } else { - resultFormat = resultFormat.replace(/M{1,2}/, 'm'); - } - - resultFormat = resultFormat.replace(/Y{2,4}/, lowerCase); - - return resultFormat; - } - } - }; - } - ]; diff --git a/awx/ui/client/src/scheduler/schedulerDatePicker.partial.html b/awx/ui/client/src/scheduler/schedulerDatePicker.partial.html deleted file mode 100644 index 728285096f47..000000000000 --- a/awx/ui/client/src/scheduler/schedulerDatePicker.partial.html +++ /dev/null @@ -1,10 +0,0 @@ -
- - -
diff --git a/awx/ui/client/src/scheduler/schedulerEdit.controller.js b/awx/ui/client/src/scheduler/schedulerEdit.controller.js deleted file mode 100644 index 3a2d3cd1876f..000000000000 --- a/awx/ui/client/src/scheduler/schedulerEdit.controller.js +++ /dev/null @@ -1,475 +0,0 @@ -export default ['$filter', '$state', '$stateParams', 'Wait', '$scope', 'moment', -'$rootScope', '$http', 'CreateSelect2', 'ParseTypeChange', 'ParentObject', 'ProcessErrors', 'Rest', -'GetBasePath', 'SchedulerInit', 'SchedulePost', 'JobTemplateModel', '$q', 'Empty', 'PromptService', 'RRuleToAPI', -'WorkflowJobTemplateModel', 'TemplatesStrings', 'scheduleResolve', 'timezonesResolve', -function($filter, $state, $stateParams, Wait, $scope, moment, - $rootScope, $http, CreateSelect2, ParseTypeChange, ParentObject, ProcessErrors, Rest, - GetBasePath, SchedulerInit, SchedulePost, JobTemplate, $q, Empty, PromptService, RRuleToAPI, - WorkflowJobTemplate, TemplatesStrings, scheduleResolve, timezonesResolve -) { - - let schedule, scheduler, scheduleCredentials = []; - - $scope.preventCredsWithPasswords = true; - - // initial end @ midnight values - $scope.schedulerEndHour = "00"; - $scope.schedulerEndMinute = "00"; - $scope.schedulerEndSecond = "00"; - $scope.parentObject = ParentObject; - $scope.isEdit = true; - $scope.hideForm = true; - $scope.parseType = 'yaml'; - - $scope.strings = TemplatesStrings; - - $scope.processSchedulerEndDt = function(){ - // set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight - var dt = new Date($scope.schedulerUTCTime); - // increment date by 1 day - dt.setDate(dt.getDate() + 1); - var month = $filter('schZeroPad')(dt.getMonth() + 1, 2), - day = $filter('schZeroPad')(dt.getDate(), 2); - $scope.$parent.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear(); - }; - - $scope.formCancel = function() { - $state.go("^"); - }; - - /* - * This is a workaround for the angular-scheduler library inserting `ll` into fields after an - * invalid entry and never unsetting them. Presumably null is being truncated down to 2 chars - * in that case. - * - * Because this same problem exists in the edit mode and because there's no inheritence, this - * block of code is duplicated in both add/edit controllers pending a much needed broader - * refactoring effort. - */ - $scope.timeChange = () => { - if (!Number($scope.schedulerStartHour)) { - $scope.schedulerStartHour = '00'; - } - - if (!Number($scope.schedulerStartMinute)) { - $scope.schedulerStartMinute = '00'; - } - - if (!Number($scope.schedulerStartSecond)) { - $scope.schedulerStartSecond = '00'; - } - - $scope.scheduleTimeChange(); - }; - - $scope.saveSchedule = function() { - schedule.extra_data = $scope.extraVars; - SchedulePost({ - scope: $scope, - url: GetBasePath('schedules') + parseInt($stateParams.schedule_id) + '/', - scheduler: scheduler, - mode: 'edit', - schedule: schedule, - promptData: $scope.promptData, - priorCredentials: scheduleCredentials - }).then(() => { - Wait('stop'); - $state.go("^", null, {reload: true}); - }); - }; - - $scope.prompt = () => { - $scope.promptData.triggerModalOpen = true; - }; - - var callSelect2 = function() { - CreateSelect2({ - element: '.MakeSelect2', - multiple: false - }); - $("#schedulerTimeZone").select2({ - width:'100%', - containerCssClass: 'Form-dropDown', - placeholder: 'SEARCH' - }); - }; - - $scope.$on("updateSchedulerSelects", function() { - callSelect2(); - }); - - let previewList = _.debounce(function(req) { - $http.post('/api/v2/schedules/preview/', {'rrule': req}) - .then(({data}) => { - $scope.preview_list = data; - let parsePreviewList = (tz) => { - return data[tz].map(function(date) { - date = date.replace(/Z/, ''); - return moment.parseZone(date).format("MM-DD-YYYY HH:mm:ss"); - }); - }; - for (let tz in data) { - $scope.preview_list.isEmpty = data[tz].length === 0; - $scope.preview_list[tz] = parsePreviewList(tz); - } - }); - }, 300); - - $scope.$on("setPreviewPane", (event) => { - let rrule = event.currentScope.rrule.toString(); - let req = RRuleToAPI(rrule, $scope); - previewList(req); - }); - - Wait('start'); - - //sets the timezone dropdown to the timezone specified by the API - function setTimezone () { - $scope.schedulerTimeZone = _.find($scope.timeZones, function(x) { - return x.name === scheduleResolve.timezone; - }); - } - - // sets the UNTIL portion of the schedule form after the angular-scheduler - // sets it, but this function reads the 'until' key/value pair directly - // from the schedule GET response. - function setUntil (scheduler) { - let { until } = scheduleResolve; - if(until !== ''){ - const date = moment(until); - const endDt = moment.parseZone(date).format("MM/DD/YYYY"); - const endHour = date.format('HH'); - const endMinute = date.format('mm'); - const endSecond = date.format('ss'); - scheduler.scope.schedulerEndDt = endDt; - scheduler.scope.schedulerEndHour = endHour; - scheduler.scope.schedulerEndMinute = endMinute; - scheduler.scope.schedulerEndSecond = endSecond; - } - } - - function init() { - schedule = scheduleResolve; - - try { - schedule.extra_data = JSON.parse(schedule.extra_data); - } catch(e) { - // do nothing - } - - $scope.extraVars = (scheduleResolve.extra_data === '' || _.isEmpty(scheduleResolve.extra_data)) ? '---' : '---\n' + jsyaml.safeDump(scheduleResolve.extra_data); - - if (_.has(schedule, 'summary_fields.unified_job_template.unified_job_type') && - schedule.summary_fields.unified_job_template.unified_job_type === 'system_job'){ - $scope.cleanupJob = true; - } - - $scope.schedule_obj = scheduleResolve; - - $('#form-container').empty(); - scheduler = SchedulerInit({ scope: $scope, requireFutureStartTime: false }); - - scheduler.scope.timeZones = timezonesResolve; - setTimezone(); - - scheduler.inject('form-container', false); - scheduler.injectDetail('occurrences', false); - - if (!/DTSTART/.test(schedule.rrule)) { - schedule.rrule += ";DTSTART=" + schedule.dtstart.replace(/\.\d+Z$/,'Z'); - } - schedule.rrule = schedule.rrule.replace(/ RRULE:/,';'); - schedule.rrule = schedule.rrule.replace(/DTSTART:/,'DTSTART='); - $scope.$on("htmlDetailReady", function() { - scheduler.setRRule(schedule.rrule); - scheduler.setName(schedule.name); - setTimezone(); - setUntil(scheduler); - $scope.hideForm = false; - - $scope.$watchGroup(["schedulerName", - "schedulerStartDt", - "schedulerStartHour", - "schedulerStartMinute", - "schedulerStartSecond", - "schedulerTimeZone", - "schedulerFrequency", - "schedulerInterval", - "monthlyRepeatOption", - "monthDay", - "monthlyOccurrence", - "monthlyWeekDay", - "yearlyRepeatOption", - "yearlyMonth", - "yearlyMonthDay", - "yearlyOccurrence", - "yearlyWeekDay", - "yearlyOtherMonth", - "schedulerEnd", - "schedulerOccurrenceCount", - "schedulerEndDt", - "schedulerEndHour", - "schedulerEndMinute", - "schedulerEndSecond" - ], function() { - $rootScope.$broadcast("loadSchedulerDetailPane"); - }, true); - - $scope.$watch("weekDays", function() { - $rootScope.$broadcast("loadSchedulerDetailPane"); - }, true); - - $rootScope.$broadcast("loadSchedulerDetailPane"); - Wait('stop'); - }); - - $scope.showRRuleDetail = false; - scheduler.setRRule(schedule.rrule); - scheduler.setName(schedule.name); - $rootScope.breadcrumb.schedule_name = $scope.schedulerName; - $rootScope.breadcrumb[`${$scope.parentObject.type}_name`] = $scope.parentObject.name; - $scope.noVars = true; - scheduler.scope.timeZones = timezonesResolve; - scheduler.scope.schedulerTimeZone = scheduleResolve.timezone; - if ($scope.cleanupJob){ - $scope.schedulerPurgeDays = Number(schedule.extra_data.days); - } - - if ($state.current.name === 'templates.editJobTemplate.schedules.edit' || $scope.parentObject.type === 'job_template'){ - - let jobTemplate = new JobTemplate(); - - Rest.setUrl(scheduleResolve.related.credentials); - - $q.all([jobTemplate.optionsLaunch(ParentObject.id), jobTemplate.getLaunch(ParentObject.id), Rest.get()]) - .then((responses) => { - let launchOptions = responses[0].data, - launchConf = responses[1].data; - - scheduleCredentials = responses[2].data.results; - - let watchForPromptChanges = () => { - let promptValuesToWatch = [ - 'promptData.prompts.inventory.value', - 'promptData.prompts.jobType.value', - 'promptData.prompts.verbosity.value', - 'missingSurveyValue' - ]; - - $scope.$watchGroup(promptValuesToWatch, function() { - let missingPromptValue = false; - if ($scope.missingSurveyValue) { - missingPromptValue = true; - } else if (!$scope.promptData.prompts.inventory.value || !$scope.promptData.prompts.inventory.value.id) { - missingPromptValue = true; - } - $scope.promptModalMissingReqFields = missingPromptValue; - }); - }; - - let prompts = PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data, - currentValues: scheduleResolve - }); - - let defaultCredsWithoutOverrides = []; - - const credentialHasScheduleOverride = (templateDefaultCred) => { - let credentialHasOverride = false; - scheduleCredentials.forEach((scheduleCred) => { - if (templateDefaultCred.credential_type === scheduleCred.credential_type) { - if ( - (!templateDefaultCred.vault_id && !scheduleCred.inputs.vault_id) || - (templateDefaultCred.vault_id && scheduleCred.inputs.vault_id && templateDefaultCred.vault_id === scheduleCred.inputs.vault_id) - ) { - credentialHasOverride = true; - } - } - }); - - return credentialHasOverride; - }; - - if (_.has(launchConf, 'defaults.credentials')) { - launchConf.defaults.credentials.forEach((defaultCred) => { - if (!credentialHasScheduleOverride(defaultCred)) { - defaultCredsWithoutOverrides.push(defaultCred); - } - }); - } - - prompts.credentials.value = defaultCredsWithoutOverrides.concat(scheduleCredentials); - - if (launchConf.ask_variables_on_launch) { - // the extra vars codemirror is ONLY shown if the - // schedule is for a JT and the JT has - // ask_variables_on_launch = true. - $scope.extraVars = ParentObject.extra_vars === '' ? '---' : ParentObject.extra_vars; - $scope.noVars = false; - ParseTypeChange({ - scope: $scope, - variable: 'extraVars', - parse_variable: 'parseType', - field_id: 'SchedulerForm-extraVars' - }); - } else { - $scope.noVars = true; - } - - if (!launchConf.survey_enabled && - !launchConf.ask_inventory_on_launch && - !launchConf.ask_credential_on_launch && - !launchConf.ask_verbosity_on_launch && - !launchConf.ask_job_type_on_launch && - !launchConf.ask_limit_on_launch && - !launchConf.ask_tags_on_launch && - !launchConf.ask_skip_tags_on_launch && - !launchConf.ask_diff_mode_on_launch && - !launchConf.survey_enabled && - !launchConf.credential_needed_to_start && - !launchConf.inventory_needed_to_start && - launchConf.passwords_needed_to_start.length === 0 && - launchConf.variables_needed_to_start.length === 0) { - $scope.showPromptButton = false; - } else { - $scope.showPromptButton = true; - - // Ignore the fact that variables might be promptable on launch - // Promptable variables will happen in the schedule form - launchConf.ignore_ask_variables = true; - - if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has(scheduleResolve, 'summary_fields.inventory')) { - $scope.promptModalMissingReqFields = true; - } - - if (responses[1].data.survey_enabled) { - // go out and get the survey questions - jobTemplate.getSurveyQuestions(ParentObject.id) - .then((surveyQuestionRes) => { - - let processed = PromptService.processSurveyQuestions({ - surveyQuestions: surveyQuestionRes.data.spec, - extra_data: _.cloneDeep(scheduleResolve.extra_data) - }); - - $scope.missingSurveyValue = processed.missingSurveyValue; - - $scope.extraVars = (processed.extra_data === '' || _.isEmpty(processed.extra_data)) ? '---' : '---\n' + jsyaml.safeDump(processed.extra_data); - - ParseTypeChange({ - scope: $scope, - variable: 'extraVars', - parse_variable: 'parseType', - field_id: 'SchedulerForm-extraVars', - readOnly: !$scope.schedule_obj.summary_fields.user_capabilities.edit - }); - - $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - surveyQuestions: surveyQuestionRes.data.spec, - template: ParentObject.id - }; - - $scope.$watch('promptData.surveyQuestions', () => { - let missingSurveyValue = false; - _.each($scope.promptData.surveyQuestions, (question) => { - if (question.required && (Empty(question.model) || question.model === [])) { - missingSurveyValue = true; - } - }); - $scope.missingSurveyValue = missingSurveyValue; - }, true); - - watchForPromptChanges(); - }); - } else { - $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - template: ParentObject.id - }; - watchForPromptChanges(); - } - } - }); - } else if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.edit' || $scope.parentObject.type === 'workflow_job_template') { - let workflowJobTemplate = new WorkflowJobTemplate(); - - $q.all([workflowJobTemplate.optionsLaunch(ParentObject.id), workflowJobTemplate.getLaunch(ParentObject.id)]) - .then((responses) => { - let launchOptions = responses[0].data, - launchConf = responses[1].data; - - let watchForPromptChanges = () => { - $scope.$watch('missingSurveyValue', function() { - $scope.promptModalMissingReqFields = $scope.missingSurveyValue ? true : false; - }); - }; - - let prompts = PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data, - currentValues: scheduleResolve - }); - - if(!launchConf.survey_enabled) { - $scope.showPromptButton = false; - } else { - $scope.showPromptButton = true; - - if(responses[1].data.survey_enabled) { - // go out and get the survey questions - workflowJobTemplate.getSurveyQuestions(ParentObject.id) - .then((surveyQuestionRes) => { - - let processed = PromptService.processSurveyQuestions({ - surveyQuestions: surveyQuestionRes.data.spec, - extra_data: _.cloneDeep(scheduleResolve.extra_data) - }); - - $scope.missingSurveyValue = processed.missingSurveyValue; - - $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - surveyQuestions: surveyQuestionRes.data.spec, - template: ParentObject.id - }; - - $scope.$watch('promptData.surveyQuestions', () => { - let missingSurveyValue = false; - _.each($scope.promptData.surveyQuestions, (question) => { - if(question.required && (Empty(question.model) || question.model === [])) { - missingSurveyValue = true; - } - }); - $scope.missingSurveyValue = missingSurveyValue; - }, true); - - watchForPromptChanges(); - }); - } - else { - $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - template: ParentObject.id - }; - watchForPromptChanges(); - } - } - }); - - } - } - - init(); - - callSelect2(); -}]; diff --git a/awx/ui/client/src/scheduler/schedulerForm.block.less b/awx/ui/client/src/scheduler/schedulerForm.block.less deleted file mode 100644 index d40eb0e15e76..000000000000 --- a/awx/ui/client/src/scheduler/schedulerForm.block.less +++ /dev/null @@ -1,68 +0,0 @@ -/** @define SchedulerForm */ - -.SchedulerForm-formGroup { - padding-right: 0px; -} - -.SchedulerForm-inputGroup--date { - width: 100%; -} - -#SchedulerFormTarget .DatePicker { - max-height: 31px; -} - -#SchedulerFormTarget .DatePicker-icon { - padding-top: 4px; -} - -@media (min-width: 901px) { - .SchedulerForm-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: ~"calc(33% - 32px)"; - margin-right: 50px; - } - - .SchedulerForm-formGroup:nth-child(3n+3) { - flex: 0 0 auto; - margin-bottom: 25px; - margin-right: 0px; - } -} - -@media (min-width: 651px) and (max-width: 900px) { - .SchedulerForm-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: ~"calc(50% - 25px)"; - margin-right: 50px; - } - - .SchedulerForm-formGroup:nth-child(2n+2) { - flex: 0 0 auto; - margin-bottom: 25px; - margin-right: 0px; - } -} - -@media (max-width: 650px) { - .SchedulerForm-formGroup { - flex: 0 0 auto; - margin-bottom: 25px; - width: 100%; - margin-right: 0px; - } -} - -.SchedulerForm-promptSaveTooltip { - position: absolute; - height: 100%; - display: block; - margin-left: 20px; - width: ~"calc(100% - 20px)"; -} - -.SchedulerForm-promptSave { - position: relative; -} diff --git a/awx/ui/client/src/scheduler/schedulerForm.partial.html b/awx/ui/client/src/scheduler/schedulerForm.partial.html deleted file mode 100644 index 8afed91a0ca3..000000000000 --- a/awx/ui/client/src/scheduler/schedulerForm.partial.html +++ /dev/null @@ -1,690 +0,0 @@ -
-
-
{{ schedulerName || "ADD SCHEDULE"}}
-
{{ schedulerName || "EDIT SCHEDULE"}}
-
-
- -
-
-
-
- -
- - -
- A schedule name is required. -
-
-
- -
- - -
-
-
-
-
- -
- - - : - - - - : - - -
-
- The time must be in HH24:MM:SS format. -
-
-
- - - -
-
- - -
-
-
-
- Frequency Details
-
-
- - - -
- Please provide a value between 1 and 999. -
-
-
-
- -
- -
- The day must be between 1 and 31. -
-
-
-
- -
-
- - -
-
-
-
- * - -
-
- - -
-
- The day must be between 1 and 31. -
-
-
-
- -
-
- - - -
-
-
- -
-
- - - - - - - -
-
-
- Please select one or more days. -
-
-
- -
- -
-
-
- - -
- Please provide a value between 1 and 999. -
-
-
- -
- - -
-
- Please provide a valid date. -
-
-
- -
- - - : - - - - : - - -
-
- The time must be in HH24:MM:SS format. -
-
-
-
-
-
-
-

- The scheduler options are invalid, incomplete, or a date is in the past. -

-
-
- -
- {{ rrule_nlp_description }} -
-
- -
- - - -
-
-
    -
  • - {{ occurrence }} UTC -
  • -
-
    -
  • - {{ occurrence }} -
  • -
- -
-
- -
- -
-
-
-
- - - -
-
- -
-
- -
diff --git a/awx/ui/client/src/scheduler/schedulerFormDetail.block.less b/awx/ui/client/src/scheduler/schedulerFormDetail.block.less deleted file mode 100644 index e05bbb89d31c..000000000000 --- a/awx/ui/client/src/scheduler/schedulerFormDetail.block.less +++ /dev/null @@ -1,72 +0,0 @@ -/** @define SchedulerFormDetail */ - -.SchedulerFormDetail-container { - padding: 15px; - border: 1px solid @b7grey; - border-radius: 5px; - margin-bottom: 20px; -} - -.SchedulerFormDetail-container--error { - border-color: @default-err; -} - -.SchedulerFormDetail-errorText { - text-align: center; - margin-bottom: 0px; - color: @default-err; -} - -.SchedulerFormDetail-label { - text-transform: uppercase; - color: @default-interface-txt; - margin-bottom: 15px; -} - -.SchedulerFormDetail-nlp { - margin-bottom: 10px; -} - -.SchedulerFormDetail-occurrenceHeader { - display: flex; - flex-wrap: wrap; -} - -.SchedulerFormDetail-labelOccurrence { - font-size: 13px; - font-weight: normal; - margin-bottom: 10px; - margin-right: 20px; -} - -.SchedulerFormDetail-labelDetail { - font-size: 12px; - text-transform: none; -} - -.SchedulerFormDetail-dateFormats { - text-transform: uppercase; - font-size: 13px; - color: @default-interface-txt; -} - -.SchedulerFormDetail-dateFormatsLabel { - font-weight: normal; - margin-right: 5px; -} - -.SchedulerFormDetail-radioLabel { - margin-top: -3px !important; - color: @default-data-txt !important; -} - -.SchedulerFormDetail-radioButton { - margin-top: 2px !important; - color: @default-interface-txt !important; -} - -.SchedulerFormDetail-occurrenceList { - margin-top: 10px; - padding-left: 0px; - list-style-type: none; -} diff --git a/awx/ui/client/src/scheduler/schedulerList.controller.js b/awx/ui/client/src/scheduler/schedulerList.controller.js deleted file mode 100644 index e09566a79753..000000000000 --- a/awx/ui/client/src/scheduler/schedulerList.controller.js +++ /dev/null @@ -1,198 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Schedules - * @description This controller's for schedules - */ - - -export default [ - '$filter', '$scope', '$location', '$stateParams', 'ScheduleList', 'Rest', - 'rbacUiControlService', - 'ToggleSchedule', 'DeleteSchedule', '$q', '$state', 'Dataset', 'ParentObject', 'UnifiedJobsOptions', - function($filter, $scope, $location, $stateParams, - ScheduleList, Rest, - rbacUiControlService, - ToggleSchedule, DeleteSchedule, - $q, $state, Dataset, ParentObject, UnifiedJobsOptions) { - - var base, scheduleEndpoint, - list = ScheduleList; - - init(); - - function init() { - if (ParentObject){ - $scope.parentObject = ParentObject; - scheduleEndpoint = ParentObject.endpoint|| ParentObject.related.schedules || `${ParentObject.related.inventory_source}schedules`; - $scope.canAdd = false; - rbacUiControlService.canAdd(scheduleEndpoint) - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - } - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - $scope.unified_job_options = UnifiedJobsOptions.actions.GET; - - // _.forEach($scope[list.name], buildTooltips); - } - - $scope.isValid = (schedule) => { - let type = schedule.summary_fields.unified_job_template.unified_job_type; - switch(type){ - case 'job': - return _.every(['project', 'inventory'], _.partial(_.has, schedule.related)); - case 'project_update': - return _.has(schedule, 'related.project'); - case 'inventory_update': - return _.has(schedule, 'related.inventory'); - default: - return true; - } - }; - - $scope.$on(`${list.iterator}_options`, function(event, data){ - $scope.options = data.data.actions.GET; - optionsRequestDataProcessing(); - }); - - $scope.$watchCollection(`${$scope.list.name}`, function() { - optionsRequestDataProcessing(); - } - ); - - // iterate over the list and add fields like type label, after the - // OPTIONS request returns, or the list is sorted/paginated/searched - function optionsRequestDataProcessing(){ - $scope[list.name].forEach(function(item, item_idx) { - var itm = $scope[list.name][item_idx]; - - // Set the item type label - if (list.fields.type && $scope.unified_job_options && - $scope.unified_job_options.hasOwnProperty('type')) { - $scope.unified_job_options.type.choices.every(function(choice) { - if (choice[0] === itm.summary_fields.unified_job_template.unified_job_type) { - itm.type_label = choice[1]; - return false; - } - return true; - }); - } - buildTooltips(itm); - - if (!$state.is('jobs.schedules')){ - if($state.current.name.endsWith('.add')) { - itm.linkToDetails = `^.edit({schedule_id:schedule.id})`; - } - else if($state.current.name.endsWith('.edit')) { - itm.linkToDetails = `.({schedule_id:schedule.id})`; - } - else { - itm.linkToDetails = `.edit({schedule_id:schedule.id})`; - } - } - - }); - } - - function buildTooltips(schedule) { - var job = schedule.summary_fields.unified_job_template; - if (schedule.enabled) { - schedule.play_tip = 'Schedule is active. Click to stop.'; - schedule.status = 'active'; - schedule.status_tip = 'Schedule is active. Click to stop.'; - } else { - schedule.play_tip = 'Schedule is stopped. Click to activate.'; - schedule.status = 'stopped'; - schedule.status_tip = 'Schedule is stopped. Click to activate.'; - } - - schedule.nameTip = $filter('sanitize')(schedule.name); - // include the word schedule if the schedule name does not include the word schedule - if (schedule.name.indexOf("schedule") === -1 && schedule.name.indexOf("Schedule") === -1) { - schedule.nameTip += " schedule"; - } - schedule.nameTip += " for "; - if (job.name.indexOf("job") === -1 && job.name.indexOf("Job") === -1) { - schedule.nameTip += "job "; - } - schedule.nameTip += $filter('sanitize')(job.name); - schedule.nameTip += ". Click to edit schedule."; - } - - $scope.refreshSchedules = function() { - $state.go('.', null, { reload: true }); - }; - - $scope.addSchedule = function() { - if($state.current.name.endsWith('.edit')) { - $state.go('^.add'); - } - if(!$state.current.name.endsWith('.add')) { - $state.go('.add'); - } - }; - - $scope.editSchedule = function(schedule) { - if ($state.is('jobs.schedules')){ - $state.go('jobs.schedules.edit', {schedule_id: schedule.id}); - } - else { - if($state.current.name.endsWith('.add')) { - $state.go('^.edit', { schedule_id: schedule.id }); - } - else if($state.current.name.endsWith('.edit')) { - $state.go('.', { schedule_id: schedule.id }); - } - else { - $state.go('.edit', { schedule_id: schedule.id }); - } - } - }; - - $scope.toggleSchedule = function(event, id) { - try { - $(event.target).tooltip('hide'); - } catch (e) { - // ignore - } - ToggleSchedule({ - scope: $scope, - id: id - }); - }; - - $scope.deleteSchedule = function(id) { - DeleteSchedule({ - scope: $scope, - id: id - }); - }; - - base = $location.path().replace(/^\//, '').split('/')[0]; - - if (base === 'management_jobs') { - $scope.base = base = 'system_job_templates'; - } - if ($stateParams.job_type) { - $scope.job_type = $stateParams.job_type; - } - - $scope.refreshJobs = function() { - $state.go('.', null, { reload: true }); - }; - - $scope.formCancel = function() { - $state.go('^', null, { reload: true }); - }; - } -]; diff --git a/awx/ui/client/src/scheduler/schedulertime.block.less b/awx/ui/client/src/scheduler/schedulertime.block.less deleted file mode 100644 index 64a87a46e736..000000000000 --- a/awx/ui/client/src/scheduler/schedulertime.block.less +++ /dev/null @@ -1,36 +0,0 @@ -/** @define SchedulerTime */ - -.SchedulerTime { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -span.ui-spinner.ui-widget.ui-widget-content.ui-corner-all { - flex: 1; -} - -.SchedulerTime-separator { - margin-left: 3px; - margin-right: 3px; - margin-top: 3px; -} - -.SchedulerTime-utc { - flex: 1; - display: flex; - flex-direction: column; - margin-left: 20px; - margin-top: -2px; - font-size: 12px; -} - -.SchedulerTime-utcLabel { - flex: 1; - font-weight: normal; - margin-bottom: 0; -} - -.SchedulerTime-utcTime { - flex: 1; -} diff --git a/awx/ui/client/src/scheduler/schedules.list.js b/awx/ui/client/src/scheduler/schedules.list.js deleted file mode 100644 index c1e3e541853a..000000000000 --- a/awx/ui/client/src/scheduler/schedules.list.js +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['i18n', function(i18n) { - return { - - name: 'schedules', - iterator: 'schedule', - selectTitle: '', - editTitle: 'SCHEDULES', - listTitle: '{{parentObject | sanitize}} || SCHEDULES', - index: false, - hover: true, - - fields: { - invalid: { - columnClass: "List-staticColumn--invalidBar", - label: '', - type: 'invalid', - nosort: true, - awToolTip: i18n._("Resources are missing from this template."), - dataPlacement: 'right', - ngShow: '!isValid(schedule)' - }, - toggleSchedule: { - ngDisabled: "!schedule.summary_fields.user_capabilities.edit", - label: '', - columnClass: 'List-staticColumn--toggle', - type: "toggle", - ngClick: "toggleSchedule($event, schedule.id)", - awToolTip: "{{ schedule.play_tip }}", - dataTipWatch: "schedule.play_tip", - dataPlacement: "right", - nosort: true, - }, - name: { - key: true, - label: i18n._('Name'), - uiSref: "{{schedule.linkToDetails}}", - columnClass: "col-md-3 col-sm-3 col-xs-6" - }, - dtstart: { - label: i18n._('First Run'), - filter: "longDate", - columnClass: "List-staticColumn--schedulerTime hidden-sm hidden-xs" - }, - next_run: { - label: i18n._('Next Run'), - filter: "longDate", - columnClass: "List-staticColumn--schedulerTime hidden-xs" - }, - dtend: { - label: i18n._('Final Run'), - filter: "longDate", - columnClass: "List-staticColumn--schedulerTime hidden-xs" - }, - }, - - actions: { - refresh: { - mode: 'all', - awToolTip: i18n._("Refresh the page"), - ngClick: "refreshSchedules()", - actionClass: 'btn List-buttonDefault', - ngShow: "socketStatus == 'error'", - buttonContent: i18n._('REFRESH') - }, - add: { - mode: 'all', - ngClick: 'addSchedule()', - awToolTip: i18n._('Add a new schedule'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd' - } - }, - - fieldActions: { - edit: { - label: i18n._('Edit'), - ngClick: "editSchedule(schedule)", - icon: 'icon-edit', - awToolTip: i18n._('Edit schedule'), - dataPlacement: 'top', - ngShow: 'schedule.summary_fields.user_capabilities.edit' - }, - view: { - label: i18n._('View'), - ngClick: "editSchedule(schedule)", - awToolTip: i18n._('View schedule'), - dataPlacement: 'top', - ngShow: '!schedule.summary_fields.user_capabilities.edit' - }, - "delete": { - label: i18n._('Delete'), - ngClick: "deleteSchedule(schedule.id)", - icon: 'icon-trash', - awToolTip: i18n._('Delete schedule'), - dataPlacement: 'top', - ngShow: 'schedule.summary_fields.user_capabilities.delete' - } - } - };}]; diff --git a/awx/ui/client/src/scheduler/schedules.route.js b/awx/ui/client/src/scheduler/schedules.route.js deleted file mode 100644 index 965b42f97d25..000000000000 --- a/awx/ui/client/src/scheduler/schedules.route.js +++ /dev/null @@ -1,369 +0,0 @@ -import { N_ } from '../i18n'; -import {templateUrl} from '../shared/template-url/template-url.factory'; -import editScheduleResolve from './editSchedule.resolve'; - -const jobTemplatesSchedulesListRoute = { - searchPrefix: 'schedule', - name: 'templates.editJobTemplate.schedules', - route: '/schedules', - data: { - activityStream: true, - activityStreamTarget: 'job_template', - activityStreamId: 'id' - }, - ncyBreadcrumb: { - label: N_('SCHEDULES') - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$q', - function(Rest, GetBasePath, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('job_templates') + $stateParams.job_template_id + '/schedules/'; - return list; - } - ] - }, - views: { - related: { - templateProvider: function(ScheduleList, generateList){ - ScheduleList.title = false; - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - return html; - }, - controller: 'schedulerListController' - } - } -}; - -const jobTemplatesSchedulesAddRoute = { - name: 'templates.editJobTemplate.schedules.add', - route: '/add', - views: { - 'scheduler@templates': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - label: N_('CREATE SCHEDULE') - } -}; - -const jobTemplatesSchedulesEditRoute = { - name: 'templates.editJobTemplate.schedules.edit', - route: '/:schedule_id', - views: { - 'scheduler@templates': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - label: "{{breadcrumb.schedule_name}}" - }, - resolve: editScheduleResolve() -}; - -// workflows -const workflowSchedulesRoute = { - searchPrefix: 'schedule', - name: 'templates.editWorkflowJobTemplate.schedules', - route: '/schedules', - data: { - activityStream: true, - activityStreamTarget: 'job_template', - activityStreamId: 'id' - }, - ncyBreadcrumb: { - label: N_('SCHEDULES') - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('workflow_job_templates')}${$stateParams.workflow_job_template_id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('workflow_job_templates')}${$stateParams.workflow_job_template_id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('workflow_job_templates') + $stateParams.workflow_job_template_id + '/schedules/'; - return list; - } - ] - }, - views: { - related: { - templateProvider: function(ScheduleList, generateList){ - ScheduleList.title = false; - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - return html; - }, - controller: 'schedulerListController' - } - } -}; - -const workflowSchedulesAddRoute = { - name: 'templates.editWorkflowJobTemplate.schedules.add', - route: '/add', - views: { - 'scheduler@templates': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - label: N_('CREATE SCHEDULE') - } -}; - -const workflowSchedulesEditRoute = { - name: 'templates.editWorkflowJobTemplate.schedules.edit', - route: '/:schedule_id', - views: { - 'scheduler@templates': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - label: '{{breadcrumb.schedule_name}}' - }, - resolve: editScheduleResolve() -}; - -const projectsSchedulesListRoute = { - searchPrefix: 'schedule', - name: 'projects.edit.schedules', - route: '/schedules', - data: { - activityStream: true, - activityStreamTarget: 'project', - activityStreamId: 'id' - }, - ncyBreadcrumb: { - label: N_('SCHEDULES') - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('projects')}${$stateParams.project_id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('projects')}${$stateParams.project_id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('projects') + $stateParams.project_id + '/schedules/'; - return list; - } - ] - }, - views: { - related: { - templateProvider: function(ScheduleList, generateList){ - ScheduleList.title = false; - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - return html; - }, - controller: 'schedulerListController' - } - } -}; - -const projectsSchedulesAddRoute = { - name: 'projects.edit.schedules.add', - route: '/add', - ncyBreadcrumb: { - label: N_('CREATE SCHEDULE') - }, - views: { - 'scheduler@projects': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - } -}; - -const projectsSchedulesEditRoute = { - name: 'projects.edit.schedules.edit', - route: '/:schedule_id', - ncyBreadcrumb: { - label: "{{breadcrumb.schedule_name}}" - }, - views: { - 'scheduler@projects': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - resolve: editScheduleResolve() -}; - -const jobsSchedulesRoute = { - searchPrefix: 'schedule', - name: 'jobs.schedules', - route: '/schedules', - params: { - schedule_search: { - value: { - next_run__isnull: 'false', - order_by: 'unified_job_template__polymorphic_ctype__model' - }, - dynamic: true - } - }, - data: { - activityStream: false, - }, - ncyBreadcrumb: { - parent: 'jobs', - label: N_('SCHEDULES') - }, - resolve: { - ScheduleList: ['ScheduledJobsList', function(list){ - return list; - }], - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath('schedules'); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['GetBasePath', (GetBasePath) =>{return {endpoint:GetBasePath('schedules')}; }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }] - }, - views: { - 'schedulesList@jobs': { - templateProvider: function(ScheduleList, generateList){ - let html = generateList.build({ - list: ScheduleList, - mode: 'edit', - title: false - }); - return html; - }, - controller: 'schedulerListController' - } - } -}; - -// the /#/jobs/schedules/:schedule_id state needs to know about the type of -// resource is being scheduled. -const parentResolve = { - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', 'scheduleResolve', - function($stateParams, Rest, GetBasePath, scheduleResolve){ - let path = scheduleResolve.related.unified_job_template; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - } - ] -}; - -const jobsSchedulesEditRoute = { - name: 'jobs.schedules.edit', - route: '/:schedule_id', - ncyBreadcrumb: { - parent: 'jobs.schedules', - label: "{{breadcrumb.schedule_name}}" - }, - views: { - 'scheduler@jobs': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - resolve: _.merge(editScheduleResolve(), parentResolve) -}; - -export { - jobTemplatesSchedulesListRoute, - jobTemplatesSchedulesAddRoute, - jobTemplatesSchedulesEditRoute, - workflowSchedulesRoute, - workflowSchedulesAddRoute, - workflowSchedulesEditRoute, - projectsSchedulesListRoute, - projectsSchedulesAddRoute, - projectsSchedulesEditRoute, - jobsSchedulesRoute, - jobsSchedulesEditRoute -}; diff --git a/awx/ui/client/src/scheduler/spinnerInput.block.less b/awx/ui/client/src/scheduler/spinnerInput.block.less deleted file mode 100644 index 1f9a44437c51..000000000000 --- a/awx/ui/client/src/scheduler/spinnerInput.block.less +++ /dev/null @@ -1,5 +0,0 @@ -/** @define SpinnerInput */ - -.SpinnerInput { - width: ~"calc(100% - 26px)"; -} diff --git a/awx/ui/client/src/shared/Modal.js b/awx/ui/client/src/shared/Modal.js deleted file mode 100644 index 6e7c73ae8ce7..000000000000 --- a/awx/ui/client/src/shared/Modal.js +++ /dev/null @@ -1,250 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name shared.function:Modal - * @description - * Modal.js - * - * Create a draggable, resizable modal dialog using jQueryUI. - * - * - */ - - -export default -angular.module('ModalDialog', ['Utilities']) - - /** - * @ngdoc method - * @name shared.function:Modal#CreateDialog - * @methodOf shared.function:Modal - * @description - * CreateDialog({ - * id: - id attribute value of the target DOM element - * scope: - Required, $scope associated with the #id DOM element - * buttons: - Required, Array of button objects. See example below. - * width: - Desired width of modal dialog on open. Defaults to 500. - * height: - Desired height of modal on open. Defaults to 600. - * minWidth: - Minimum width that must be maintained regardless of reize attempts. Defaults to 400. - * title: - Modal window title, optional - * onResizeStop: - Function to call when user stops resizing the dialog, optional - * onClose: - Function to call after window closes, optional - * onOpen: - Function to call after window opens, optional - * beforeDestroy: - Function to call during onClose and prior to destroying the window - * callback: - String to pass to scope.$emit() after dialog is created, optional - * }) - * - * Note that the dialog will be created but not opened. It's up to the caller to open it. Use callback - * option to respond to dialog created event. - */ - .factory('CreateDialog', ['Empty', function(Empty) { - - return function(params) { - - let scope = params.scope, - buttonSet = params.buttons, - width = params.width || 500, - height = params.height || 600, - minWidth = params.minWidth || 300, - title = params.title || '', - onResizeStop = params.onResizeStop, - onClose = params.onClose, - onOpen = params.onOpen, - _allowInteraction = params._allowInteraction, - callback = params.callback, - beforeDestroy = params.beforeDestroy, - closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape, - resizable = (params.resizable === undefined) ? false : params.resizable, - draggable = (params.draggable === undefined) ? true : params.draggable, - dialogClass = params.dialogClass, - forms = _.chain([params.form]).flatten().compact().value(), - buttons, - id = params.id, - position = (params.position === undefined) ? { my: "center", at: "center", of: window } : params.position, - x, y, wh, ww; - - function updateButtonStatus(isValid) { - $('.ui-dialog[aria-describedby="' + id + '"]').find('.btn-primary').prop('disabled', !isValid); - } - - if (Empty(buttonSet)) { - // Default button object - buttonSet = [{ - label: "OK", - onClick: function() { - scope.modalOK(); - }, - icon: "", - "class": "btn btn-primary", - "id": "dialog-ok-button" - }]; - } - - buttons = {}; - buttonSet.forEach( function(btn) { - buttons[btn.label] = btn.onClick; - }); - - // Set modal dimensions based on viewport width - ww = $(document).width(); - wh = $(document).height(); - x = (width > ww) ? ww - 10 : width; - y = height === "auto" ? "auto" : ((height > wh) ? wh - 10 : height); - - // Create the modal - $('#' + id).dialog({ - buttons: buttons, - modal: true, - width: x, - height: y, - autoOpen: false, - minWidth: minWidth, - title: title, - closeOnEscape: closeOnEscape, - resizable: resizable, - draggable: draggable, - dialogClass: dialogClass, - position: position, - create: function () { - // Fix the close button - $('.ui-dialog[aria-describedby="' + id + '"]').find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).html(''); - - setTimeout(function() { - // Make buttons bootstrapy - $('.ui-dialog[aria-describedby="' + id + '"]').find('.ui-dialog-buttonset button').each(function () { - var txt = $(this).text(), self = $(this); - buttonSet.forEach(function(btn) { - if (txt === btn.label) { - self.attr({ "class": btn['class'], "id": btn.id }); - if (btn.icon) { - self.empty().html(' ' + btn.label); - } - } - }); - }); - }, 300); - - if (forms.length > 0) { - forms.map(function(form_ctrl) { - scope.$watch(form_ctrl.$name + '.$valid', updateButtonStatus); - }); - } - - setTimeout(function() { - scope.$apply(function() { - scope.$emit(callback); - }); - }, 300); - }, - resizeStop: function () { - // for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100% - var dialog = $('.ui-dialog[aria-describedby="' + id + '"]'), - titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(), - buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(), - content = dialog.find('#' + id); - content.width(dialog.width() - 28); - content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) }); - if (onResizeStop) { - onResizeStop(); - } - }, - close: function () { - // Destroy on close - $('.tooltip').each(function () { - // Remove any lingering tooltip
elements - $(this).remove(); - }); - $('.popover').each(function () { - // remove lingering popover
elements - $(this).remove(); - }); - if (beforeDestroy) { - beforeDestroy(); - } - $('#' + id).dialog('destroy'); - $('#' + id).hide(); - if (onClose) { - onClose(); - } - }, - open: function () { - $('.tooltip').each(function () { - // Remove any lingering tooltip
elements - $(this).remove(); - }); - $('.popover').each(function () { - // remove lingering popover
elements - $(this).remove(); - }); - if (onOpen) { - onOpen(); - } - }, - _allowInteraction: _allowInteraction - }); - }; - }]) - - /** - * TextareaResize({ - * scope: - $scope associated with the textarea element - * textareaId: - id attribute value of the textarea - * modalId: - id attribute of the
element used to create the modal - * formId: - id attribute of the textarea's parent form - * parse: - if true, call ParseTypeChange and replace textarea with codemirror editor - * fld: - optional, form field name - * bottom_margin: - optional, integer value for additional margin to leave below the textarea - * onChange; - optional, function to call when the textarea value changes - * }) - * - * Use to resize a textarea field contained on a modal. Has only been tested where the - * form contains 1 textarea and the the textarea is at the bottom of the form/modal. - * - **/ - .factory('TextareaResize', ['ParseTypeChange', 'Wait', function(ParseTypeChange, Wait){ - return function(params) { - - var scope = params.scope, - textareaId = params.textareaId, - modalId = params.modalId, - formId = params.formId, - fld = params.fld, - parse = (params.parse === undefined) ? true : params.parse, - bottom_margin = (params.bottom_margin) ? params.bottom_margin : 0, - onChange = params.onChange, - textarea, - formHeight, model, windowHeight, offset, rows; - - function waitStop() { - Wait('stop'); - } - - // Attempt to create the largest textarea field that will fit on the window. Minimum - // height is 6 rows, so on short windows you will see vertical scrolling - textarea = $('#' + textareaId); - if (scope.codeMirror) { - model = textarea.attr('ng-model'); - scope[model] = scope.codeMirror.getValue(); - scope.codeMirror.destroy(); - } - textarea.attr('rows', 1); - formHeight = $('#' + formId).height(); - windowHeight = $('#' + modalId).height() - 20; //leave a margin of 20px - offset = Math.floor(windowHeight - formHeight - bottom_margin); - rows = Math.floor(offset / 20); - rows = (rows < 6) ? 6 : rows; - textarea.attr('rows', rows); - while(rows > 6 && ($('#' + formId).height() > $('#' + modalId).height() + bottom_margin)) { - rows--; - textarea.attr('rows', rows); - } - if (parse) { - ParseTypeChange({ scope: scope, field_id: textareaId, onReady: waitStop, variable: fld, onChange: onChange }); - } - }; - }]); diff --git a/awx/ui/client/src/shared/Utilities.js b/awx/ui/client/src/shared/Utilities.js deleted file mode 100644 index 301a7eae9dfd..000000000000 --- a/awx/ui/client/src/shared/Utilities.js +++ /dev/null @@ -1,951 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -/** - * @ngdoc function - * @name shared.function:Utilities - * @description - * Utility functions - * - */ - -/* jshint devel:true */ - - - -export default -angular.module('Utilities', ['RestServices', 'Utilities']) - -/** - * @ngdoc method - * @name shared.function:Utilities#Empty - * @methodOf shared.function:Utilities - * @description Empty() - * - * Test if a value is 'empty'. Returns true if val is null | '' | undefined. - * Only works on non-Ojbect types. - * - */ -.factory('Empty', [ - function() { - return function(val) { - return (val === null || val === undefined || val === '') ? true : false; - }; - } -]) - -/** - * @ngdoc method - * @name shared.function:Utilities#ToggleClass - * @methodOf shared.function:Utilities - * @description - */ -.factory('ToggleClass', function() { - return function(selector, cssClass) { - // Toggles the existance of a css class on a given element - if ($(selector) && $(selector).hasClass(cssClass)) { - $(selector).removeClass(cssClass); - } else if ($(selector)) { - $(selector).addClass(cssClass); - } - }; -}) - - -/** - * @ngdoc method - * @name shared.function:Utilities#Alert - * @methodOf shared.function:Utilities - * @description Pass in the header and message you want displayed on TB modal dialog found in index.html. - * Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success, - * alert-info...). Pass an optional function(){}, if you want a specific action to occur when user - * clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. - */ -.factory('Alert', ['$rootScope', '$filter', function($rootScope, $filter) { - return function(hdr, msg, cls, action, secondAlert, disableButtons, backdrop, customStyle) { - var scope = $rootScope.$new(), - alertClass, local_backdrop; - if (customStyle !== true) { - msg = $filter('sanitize')(msg); - } - if (secondAlert) { - - $('#alertHeader2').html(hdr); - $('#alert2-modal-msg').html(msg); - - alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - local_backdrop = (backdrop === undefined) ? "static" : backdrop; - - $('#alert2-modal-msg').attr({ "class": "alert " + alertClass }); - $('#alert-modal2').modal({ - show: true, - keyboard: true, - backdrop: local_backdrop - }); - scope.disableButtons2 = (disableButtons) ? true : false; - - $('#alert-modal2').on('hidden.bs.modal', function() { - if (action) { - action(); - } - }); - $('#alert-modal2').on('shown.bs.modal', function() { - $('#alert2_ok_btn').focus(); - }); - $(document).bind('keydown', function(e) { - if (e.keyCode === 27 || e.keyCode === 13) { - e.preventDefault(); - $('#alert-modal2').modal('hide'); - } - }); - } else { - - $('#alertHeader').html(hdr); - $('#alert-modal-msg').html(msg); - alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - local_backdrop = (backdrop === undefined) ? "static" : backdrop; - - $('#alert-modal-msg').attr({ "class": "alert " + alertClass }); - $('#alert-modal').modal({ - show: true, - keyboard: true, - backdrop: local_backdrop - }); - - $('#alert-modal').on('hidden.bs.modal', function() { - if (action) { - action(); - } - $('.modal-backdrop').remove(); - }); - $('#alert-modal').on('shown.bs.modal', function() { - $('#alert_ok_btn').focus(); - }); - $(document).bind('keydown', function(e) { - if (e.keyCode === 27 || e.keyCode === 13) { - e.preventDefault(); - $('#alert-modal').modal('hide'); - } - }); - - scope.disableButtons = (disableButtons) ? true : false; - } - }; -}]) - -/** - * @ngdoc method - * @name shared.function:Utilities#ProcessErrors - * @methodOf shared.function:Utilities - * @description For handling errors that are returned from the API - */ -.factory('ProcessErrors', ['$rootScope', '$cookies', '$log', '$location', 'Alert', 'Wait', - function($rootScope, $cookies, $log, $location, Alert, Wait) { - return function(scope, data, status, form, defaultMsg) { - var field, fieldErrors, msg, keys; - Wait('stop'); - $log.debug('Debug status: ' + status); - $log.debug('Debug data: '); - $log.debug(data); - if (defaultMsg.msg) { - $log.debug('Debug: ' + defaultMsg.msg); - } - if (status === 403) { - if (data && data.detail) { - msg = data.detail; - } else { - msg = 'The API responded with a 403 Access Denied error. Please contact your system administrator.'; - } - Alert(defaultMsg.hdr, msg); - } else if (status === 409) { - Alert('Conflict', data.conflict || "Resource currently in use."); - } else if (status === 410) { - Alert('Deleted Object', 'The requested object was previously deleted and can no longer be accessed.'); - } else if ((status === 'Session is expired') || (status === 401 && data.detail && data.detail === 'Token is expired') || - (status === 401 && data && data.detail && data.detail === 'Invalid token')) { - if ($rootScope.sessionTimer) { - $rootScope.sessionTimer.expireSession('idle'); - } - $location.url('/login'); - } else if (data && data.non_field_errors) { - Alert('Error!', data.non_field_errors); - } else if (data && data.detail) { - Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); - } else if (data && data.__all__) { - if (typeof data.__all__ === 'object' && Array.isArray(data.__all__)) { - Alert('Error!', data.__all__[0]); - } else { - Alert('Error!', data.__all__); - } - } else if (form) { //if no error code is detected it begins to loop through to see where the api threw an error - fieldErrors = false; - for (field in form.fields) { - if (data[field] && form.fields[field].tab) { - // If the form is part of a tab group, activate the tab - $('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show'); - } - if (form.fields[field].realName) { - if (data[form.fields[field].realName]) { - scope[field + '_api_error'] = data[form.fields[field].realName][0]; - //scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false); - $('[name="' + form.fields[field].realName + '"]').addClass('ng-invalid'); - $('html, body').animate({scrollTop: $('[name="' + form.fields[field].realName + '"]').offset().top}, 0); - fieldErrors = true; - } - } - if (form.fields[field].sourceModel) { - if (data[field]) { - scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = - data[field][0]; - //scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false); - $('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').addClass('ng-invalid'); - $('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').ScrollTo({ "onlyIfOutside": true, "offsetTop": 100 }); - fieldErrors = true; - } - } else { - if (data[field]) { - scope[field + '_api_error'] = data[field][0]; - //scope[form.name + '_form'][field].$setValidity('apiError', false); - $('[name="' + field + '"]').addClass('ng-invalid'); - $('html, body').animate({scrollTop: $('[name="' + field + '"]').offset().top}, 0); - fieldErrors = true; - } - } - } - if ((!fieldErrors) && defaultMsg) { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } else if (typeof data === 'object' && data !== null) { - if (Object.keys(data).length > 0) { - keys = Object.keys(data); - msg = ""; - _.forOwn(data, function(value, key) { - if (Array.isArray(data[key])) { - msg += `${key}: ${data[key][0]}`; - } else { - msg += `${key} : ${value} `; - } - }); - Alert(defaultMsg.hdr, msg); - } else { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } else { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - }; - } -]) - -/** - * @ngdoc method - * @name shared.function:Utilities#HelpDialog - * @methodOf shared.function:Utilities - * @description Display a help dialog - * - * HelpDialog({ defn: }) - * discuss difference b/t this and other modal windows/dialogs - */ -.factory('HelpDialog', ['$rootScope', '$compile', '$location', 'Store', - function($rootScope, $compile, $location, Store) { - return function(params) { - - var defn = params.defn, - current_step = params.step, - autoShow = params.autoShow || false, - scope = (params.scope) ? params.scope : $rootScope.$new(); - - function setButtonMargin() { - var width = ($('.ui-dialog[aria-describedby="help-modal-dialog"] .ui-dialog-buttonpane').innerWidth() / 2) - $('#help-next-button').outerWidth() - 93; - $('#help-next-button').css({ 'margin-right': width + 'px' }); - } - - function showHelp(step) { - - var e, btns, ww, width, height, isOpen = false; - current_step = step; - - function buildHtml(step) { - var html = ''; - html += "

" + step.intro + "

\n"; - if (step.img) { - html += "
\n"; - html += "\n" : ""; - html += "" + step.box + "
"; - html += (autoShow && step.autoOffNotice) ? "
\n" : ""; - return html; - } - - width = (defn.story.width) ? defn.story.width : 510; - height = (defn.story.height) ? defn.story.height : 600; - - // Limit modal width to width of viewport - ww = $(document).width(); - width = (width > ww) ? ww : width; - - try { - isOpen = $('#help-modal-dialog').dialog('isOpen'); - } catch (err) { - // ignore - } - - e = angular.element(document.getElementById('help-modal-dialog')); - e.empty().html(buildHtml(defn.story.steps[current_step])); - setTimeout(function() { scope.$apply(function() { $compile(e)(scope); }); }); - - if (!isOpen) { - // Define buttons based on story length - btns = []; - if (defn.story.steps.length > 1) { - btns.push({ - text: "Prev", - click: function() { - if (current_step - 1 === 0) { - $('#help-prev-button').prop('disabled', true); - } - if (current_step - 1 < defn.story.steps.length - 1) { - $('#help-next-button').prop('disabled', false); - } - showHelp(current_step - 1); - }, - disabled: true - }); - btns.push({ - text: "Next", - click: function() { - if (current_step + 1 > 0) { - $('#help-prev-button').prop('disabled', false); - } - if (current_step + 1 >= defn.story.steps.length - 1) { - $('#help-next-button').prop('disabled', true); - } - showHelp(current_step + 1); - } - }); - } - btns.push({ - text: "Close", - click: function() { - $('#help-modal-dialog').dialog('close'); - } - }); - - $('.overlay').css({ - width: $(document).width(), - height: $(document).height() - }).fadeIn(); - - // Show the dialog - $('#help-modal-dialog').dialog({ - position: { - my: "center top", - at: "center top+150", - of: 'body' - }, - title: defn.story.hdr, - width: width, - height: height, - buttons: btns, - closeOnEscape: true, - show: 500, - hide: 500, - resizable: false, - close: function() { - $('.overlay').hide(); - $('#help-modal-dialog').empty(); - } - }); - - // Make the buttons look like TB and add FA icons - $('.ui-dialog-buttonset button').each(function() { - var c, h, i, l; - l = $(this).text(); - if (l === 'Close') { - h = "fa-times"; - c = "btn btn-default"; - i = "help-close-button"; - $(this).attr({ - 'class': c, - 'id': i - }).html(" Close"); - } else if (l === 'Prev') { - h = "fa-chevron-left"; - c = "btn btn-primary"; - i = "help-prev-button"; - $(this).attr({ - 'class': c, - 'id': i - }).html(" Prev"); - } else { - h = "fa-chevron-right"; - c = "btn btn-primary"; - i = "help-next-button"; - $(this).attr({ - 'class': c, - 'id': i - }).html("Next ").css({ - 'margin-right': '20px' - }); - } - }); - - $('.ui-dialog[aria-describedby="help-modal-dialog"]').find('.ui-dialog-titlebar button') - .empty().attr({ - 'class': 'close' - }).text('x'); - - // If user clicks the checkbox, update local storage - $('#auto-off-checkbox').click(function() { - if ($('input[name="auto-off-checkbox"]:checked').length) { - Store('inventoryAutoHelp', 'off'); - } else { - Store('inventoryAutoHelp', 'on'); - } - }); - - setButtonMargin(); - } - } - - showHelp(0); - }; - } -]) - - -/** - * @ngdoc method - * @name shared.function:Utilities#ReturnToCaller - * @methodOf shared.function:Utilities - * @description - * Split the current path by '/' and use the array elements from 0 up to and - * including idx as the new path. If no idx value supplied, use 0 to length - 1. - * - */ -.factory('ReturnToCaller', ['$location', 'Empty', - function($location, Empty) { - return function(idx) { - var paths = $location.path().replace(/^\//, '').split('/'), - newpath = '', - i; - idx = (Empty(idx)) ? paths.length - 1 : idx + 1; - for (i = 0; i < idx; i++) { - newpath += '/' + paths[i]; - } - $location.path(newpath); - }; - } -]) - - -/** - * @ngdoc method - * @name shared.function:Utilities#FormatDate - * @methodOf shared.function:Utilities - * @description - * Wrapper for data filter- an attempt to insure all dates display in - * the same format. Pass in date object or string. See: http://docs.angularjs.org/api/ng.filter:date - */ -.factory('FormatDate', ['$filter', - function($filter) { - return function(dt) { - return $filter('longDate')(dt); - }; - } -]) - -/** - * @ngdoc method - * @name shared.function:Utilities#Wait - * @methodOf shared.function:Utilities - * @description - * Display a spinning icon in the center of the screen to freeze the - * UI while waiting on async things to complete (i.e. API calls). - * Wait('start' | 'stop'); - * - */ -.factory('Wait', ['$rootScope', - function($rootScope) { - - return function(directive) { - var docw, doch, spinnyw, spinnyh; - if (directive === 'start' && !$rootScope.waiting) { - $rootScope.waiting = true; - docw = $(window).width(); - doch = $(window).height(); - spinnyw = $('.spinny').width(); - spinnyh = $('.spinny').height(); - $('.overlay').css({ - width: $(document).width(), - height: $(document).height() - }).fadeIn(); - $('.spinny').css({ - bottom: 15, - right: 15 - }).fadeIn(400); - } else if (directive === 'stop' && $rootScope.waiting) { - $('.spinny, .overlay').fadeOut(400, function() { - $rootScope.waiting = false; - }); - } - }; - } -]) - -.factory('HideElement', [ - function() { - return function(selector, action) { - // Fade-in a cloack or vail or a specific element - var target = $(selector), - width = target.css('width'), - height = target.css('height'), - position = target.position(), - parent = target.parent(), - borderRadius = target.css('border-radius'), - backgroundColor = target.css('background-color'), - margin = target.css('margin'), - padding = target.css('padding'); - - parent.append("
"); - $('#curtain-div').show(0, action); - }; - } -]) - -.factory('ShowElement', [ - function() { - return function() { - // And Fade-out the cloack revealing the element - $('#curtain-div').fadeOut(500, function() { - $(this).remove(); - }); - }; - } -]) - -/** - * @ngdoc method - * @name shared.function:Utilities#CreateSelect2 - * @methodOf shared.function:Utilities - * @description Make a regular select drop down a select2 dropdown - * To make a `` - -
- -
- ${uploadedText} - Current logo -
- -
`, - - link: function(scope) { - var fieldKey = scope.key; - var filePickerText = angular.element(document.getElementById('filePickerText')); - var filePickerError = angular.element(document.getElementById('filePickerError')); - var filePickerButton = angular.element(document.getElementById('filePickerButton')); - var filePicker = angular.element(document.getElementById('filePicker')); - - scope.imagePresent = global.$AnsibleConfig.custom_logo || false; - scope.imageData = $rootScope.custom_logo; - - scope.$on('loginUpdated', function() { - scope.imagePresent = global.$AnsibleConfig.custom_logo; - scope.imageData = $rootScope.custom_logo; - }); - - scope.$watch('imagePresent', (val) => { - if(val){ - filePickerButton.html(removeText); - } - else{ - filePickerButton.html(browseText); - } - }); - - scope.$on(fieldKey+'_reverted', function(e) { - scope.update(e, true); - }); - - scope.update = function(e, flag) { - if(scope.$parent[fieldKey] || flag ) { - e.preventDefault(); - scope.$parent[fieldKey] = ''; - filePickerButton.html(browseText); - filePickerText.val(''); - filePicker.context.value = ""; - scope.imagePresent = false; - } - else { - // Nothing exists so open file picker - } - }; - - scope.fileChange = function(file) { - filePickerError.html(''); - - ConfigurationUtils.imageProcess(file[0]) - .then(function(result) { - scope.$parent[fieldKey] = result; - filePickerText.val(file[0].name); - filePickerButton.html(removeText); - }).catch(function(error) { - filePickerText.html(file[0].name); - filePickerError.text(error); - }).finally(function() { - - }); - }; - - } - }; -}]) - - -.directive('surveyCheckboxes', function() { - return { - restrict: 'E', - require: 'ngModel', - scope: { ngModel: '=ngModel' }, - template: '
' + - '' + - '
', - link: function(scope, element, attrs, ctrl) { - scope.cbModel = {}; - ctrl.$setValidity('reqCheck', true); - angular.forEach(scope.ngModel.value, function(value) { - scope.cbModel[value] = true; - - }); - - if (scope.ngModel.required === true && scope.ngModel.value.length === 0) { - ctrl.$setValidity('reqCheck', false); - } - - ctrl.$parsers.unshift(function(viewValue) { - for (var c in scope.cbModel) { - if (scope.cbModel[c]) { - ctrl.$setValidity('checkbox', true); - } - } - ctrl.$setValidity('checkbox', false); - - return viewValue; - }); - - scope.update = function() { - var val = []; - angular.forEach(scope.cbModel, function(v, k) { - if (v) { - val.push(k); - } - }); - if (val.length > 0) { - scope.ngModel.value = val; - scope.$parent[scope.ngModel.name] = val; - ctrl.$setValidity('checkbox', true); - ctrl.$setValidity('reqCheck', true); - } else if (scope.ngModel.required === true) { - ctrl.$setValidity('checkbox', false); - } - }; - } - }; -}) - -// the disableRow directive disables table row click events -.directive('disableRow', function() { - return { - restrict: 'A', - link: function(scope, element, attrs) { - element.bind('click', function(event) { - if (scope.$eval(attrs.disableRow)) { - event.preventDefault(); - } - return; - }); - } - }; -}) - - -.directive('awSurveyQuestion', function() { - return { - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - var values = viewValue.split(" "), - result = "", - i; - result += values[0].charAt(0).toUpperCase() + values[0].substr(1) + ' '; - for (i = 1; i < values.length; i++) { - result += values[i] + ' '; - } - result = result.trim(); - if (result !== viewValue) { - ctrl.$setViewValue(result); - ctrl.$render(); - } - return result; - }); - } - }; -}) - -.directive('awMin', ['Empty', function(Empty) { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elem, attr, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - var min = (attr.awMin) ? scope.$eval(attr.awMin) : -Infinity; - if (!Empty(min) && !Empty(viewValue) && Number(viewValue) < min) { - ctrl.$setValidity('awMin', false); - return viewValue; - } else { - ctrl.$setValidity('awMin', true); - return viewValue; - } - }); - } - }; -}]) - -.directive('awMax', ['Empty', function(Empty) { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elem, attr, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - var max = (attr.awMax) ? scope.$eval(attr.awMax) : Infinity; - if (!Empty(max) && !Empty(viewValue) && Number(viewValue) > max) { - ctrl.$setValidity('awMax', false); - return viewValue; - } else { - ctrl.$setValidity('awMax', true); - return viewValue; - } - }); - } - }; -}]) - -.directive('awRange', ['Empty', function(Empty) { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elem, attr, ctrl) { - - let checkRange = function(viewValue){ - ctrl.$setValidity('awRangeMin', true); - ctrl.$setValidity('awRangeMax', true); - var max = (attr.rangeMax) ? scope.$eval(attr.rangeMax) : Infinity; - var min = (attr.rangeMin) ? scope.$eval(attr.rangeMin) : -Infinity; - if (!Empty(max) && !Empty(viewValue) && Number(viewValue) > max) { - ctrl.$setValidity('awRangeMax', false); - } - else if(!Empty(min) && !Empty(viewValue) && Number(viewValue) < min) { - ctrl.$setValidity('awRangeMin', false); - } - return viewValue; - }; - - scope.$watch(attr.rangeMin, function () { - checkRange(scope.$eval(attr.ngModel)); - }); - - scope.$watch(attr.rangeMax, function () { - checkRange(scope.$eval(attr.ngModel)); - }); - - ctrl.$parsers.unshift(function(viewValue) { - return checkRange(viewValue); - }); - } - }; -}]) - -.directive('smartFloat', function() { - var FLOAT_REGEXP = /(^\-?\d+)?((\.|\,)\d+)?$/; - return { - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - if (viewValue === '' || FLOAT_REGEXP.test(viewValue)) { - ctrl.$setValidity('float', true); - return parseFloat(viewValue.replace(',', '.')); - } else { - ctrl.$setValidity('float', false); - return undefined; - } - }); - } - }; -}) - -// integer Validate that input is of type integer. Taken from Angular developer -// guide, form examples. Add min and max directives, and this will check -// entered values is within the range. -// -// Use input type of 'text'. Use of 'number' casuses browser validation to -// override/interfere with this directive. -.directive('integer', function() { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - ctrl.$setValidity('min', true); - ctrl.$setValidity('max', true); - if (/^\-?\d*$/.test(viewValue)) { - // it is valid - ctrl.$setValidity('integer', true); - if (viewValue === '-' || viewValue === '-0' || viewValue === null) { - ctrl.$setValidity('integer', false); - return viewValue; - } - if (elm.attr('min') && - parseInt(viewValue, 10) < parseInt(elm.attr('min'), 10)) { - ctrl.$setValidity('min', false); - return viewValue; - } - if (elm.attr('max') && (parseInt(viewValue, 10) > parseInt(elm.attr('max'), 10))) { - ctrl.$setValidity('max', false); - return viewValue; - } - return viewValue; - } - // Invalid, return undefined (no model update) - ctrl.$setValidity('integer', false); - return viewValue; - }); - } - }; -}) - -//the awSurveyVariableName directive checks if the field contains any spaces. -// this could be elaborated in the future for other things we want to check this field against -.directive('awSurveyVariableName', function() { - var FLOAT_REGEXP = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/; - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - ctrl.$setValidity('required', true); // we only want the error message for incorrect characters to be displayed - ctrl.$parsers.unshift(function(viewValue) { - if (viewValue.length !== 0) { - if (FLOAT_REGEXP.test(viewValue) && viewValue.indexOf(' ') === -1) { //check for a spaces - ctrl.$setValidity('variable', true); - return viewValue; - } else { - ctrl.$setValidity('variable', false); // spaces found, therefore throw error. - return viewValue; - } - } else { - ctrl.$setValidity('variable', true); // spaces found, therefore throw error. - return viewValue; - } - }); - } - }; -}) - -// -// awRequiredWhen: { reqExpression: "", init: "true|false" } -// -// Make a field required conditionally using an expression. If the expression evaluates to true, the -// field will be required. Otherwise, the required attribute will be removed. -// -.directive('awRequiredWhen', function() { - return { - require: 'ngModel', - compile: function(tElem) { - return { - pre: function preLink() { - let label = $(tElem).closest('.form-group').find('label').first(); - $(label).prepend('*'); - }, - post: function postLink( scope, elm, attrs, ctrl ) { - function updateRequired() { - var isRequired = scope.$eval(attrs.awRequiredWhen); - - var viewValue = elm.val(), - label, validity = true; - label = $(elm).closest('.form-group').find('label').first(); - - if (isRequired && (elm.attr('required') === null || elm.attr('required') === undefined)) { - $(elm).attr('required', 'required'); - if(!$(label).find('span.Form-requiredAsterisk').length){ - $(label).prepend('*'); - } - } else if (!isRequired) { - elm.removeAttr('required'); - if (!attrs.awrequiredAlwaysShowAsterisk) { - $(label).find('span.Form-requiredAsterisk').remove(); - } - } - if (isRequired && (viewValue === undefined || viewValue === null || viewValue === '')) { - validity = false; - } - ctrl.$setValidity('required', validity); - } - - scope.$watchGroup([attrs.awRequiredWhen, $(elm).attr('name')], function() { - // watch for the aw-required-when expression to change value - updateRequired(); - }); - - if (attrs.awrequiredInit !== undefined && attrs.awrequiredInit !== null) { - // We already set a watcher on the attribute above so no need to call updateRequired() in here - scope[attrs.awRequiredWhen] = attrs.awrequiredInit; - } - } - }; - } - }; -}) - -// awPlaceholder: Dynamic placeholder set to a scope variable you want watched. -// Value will be place in field placeholder attribute. -.directive('awPlaceholder', [function() { - return { - require: 'ngModel', - link: function(scope, elm, attrs) { - $(elm).attr('placeholder', scope[attrs.awPlaceholder]); - scope.$watch(attrs.awPlaceholder, function(newVal) { - $(elm).attr('placeholder', newVal); - }); - } - }; -}]) - -// lookup Validate lookup value against API -.directive('awlookup', ['Rest', 'GetBasePath', '$q', '$state', function(Rest, GetBasePath, $q, $state) { - return { - require: 'ngModel', - link: function(scope, elm, attrs, fieldCtrl) { - let query, - basePath, - defer = $q.defer(), - autopopulateLookup, - modelKey = attrs.ngModel, - modelName = attrs.source, - watcher = attrs.awRequiredWhen || undefined, - watchBasePath, - awLookupWhen = attrs.awLookupWhen; - - if (attrs.autopopulatelookup !== undefined) { - autopopulateLookup = JSON.parse(attrs.autopopulatelookup); - } else { - autopopulateLookup = true; - } - - // The following block of code is for instances where the - // lookup field is reused by varying sub-forms. Example: The groups - // form will change it's credential lookup based on the - // source type. The basepath the lookup should utilize is dynamic - // in this case. You'd configure the "watchBasePath" key on the - // field's configuration in the form configuration field. - if (attrs.watchbasepath !== undefined) { - watchBasePath = attrs.watchbasepath; - scope.$watch(watchBasePath, (newValue) => { - if(newValue !== undefined && fieldIsAutopopulatable()){ - _doAutoPopulate(); - } - }); - } - - function _doAutoPopulate() { - let query = '?role_level=use_role'; - - if (attrs.watchbasepath !== undefined && scope[attrs.watchbasepath] !== undefined) { - basePath = scope[attrs.watchbasepath]; - if (attrs.watchbasepath !== "projectBasePath") { - query = '&role_level=use_role'; - } else { - query = ''; - } - } - else { - basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); - let switchType = attrs.awlookuptype ? attrs.awlookuptype : modelName; - - switch(switchType) { - case 'credential': - query = '?credential_type__kind=ssh&role_level=use_role'; - break; - case 'scm_credential': - query = '?credential_type__kind=scm&role_level=use_role'; - break; - case 'network_credential': - query = '?credential_type__kind=net&role_level=use_role'; - break; - case 'insights_credential': - query = '?credential_type__kind=insights&role_level=use_role'; - break; - case 'organization': - query = '?role_level=admin_role'; - break; - case 'inventory_script': - query = '?role_level=admin_role&organization=' + scope.$resolve.inventoryData.summary_fields.organization.id; - break; - } - - } - - Rest.setUrl(`${basePath}` + query); - Rest.get() - .then(({data}) => { - if (data.count === 1) { - scope[modelKey] = data.results[0].name; - scope[modelName] = data.results[0].id; - } - }); - } - - if (fieldIsAutopopulatable()) { - _doAutoPopulate(); - } - - // This checks to see if the field meets the criteria to - // autopopulate: - // Population rules: - // - add form only - // - lookup is required - // - lookup is not promptable - // - user must only have access to 1 item the lookup is for - function fieldIsAutopopulatable() { - if (autopopulateLookup === false) { - return false; - } - if (scope.mode === "add") { - if(watcher){ - scope.$watch(watcher, () => { - if(Boolean(scope.$eval(watcher)) === true){ - - // if we get here then the field is required - // by way of awRequiredWhen - // and is a candidate for autopopulation - - _doAutoPopulate(); - } - }); - } - else if (attrs.required === true) { - return true; - } - else { - return false; - } - } - else { - return false; - } - } - - // query the API to see if field value corresponds to a valid resource - // .ng-pending will be applied to the directive element while the request is outstanding - // form.$pending will contain object reference to any ngModelControllers with outstanding requests - fieldCtrl.$asyncValidators.validResource = function(modelValue, viewValue) { - - if(awLookupWhen === undefined || (awLookupWhen !== undefined && Boolean(scope.$eval(awLookupWhen)) === true)) { - applyValidationStrategy(viewValue, fieldCtrl); - } - else { - defer.resolve(); - } - - return defer.promise; - }; - - function applyValidationStrategy(viewValue, ctrl) { - - // use supplied data attributes to build an endpoint, query, resolve outstanding promise - function applyValidation(viewValue) { - basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); - query = elm.attr('data-query'); - query = query.replace(/\:value/, encodeURIComponent(viewValue)); - - let base = attrs.awlookuptype ? attrs.awlookuptype : ctrl.$name.split('_name')[0]; - if (attrs.watchbasepath !== undefined && scope[attrs.watchbasepath] !== undefined) { - basePath = scope[attrs.watchbasepath]; - query += '&role_level=use_role'; - query = query.replace('?', '&'); - } - else { - switch(base) { - case 'credential': - query += '&kind=ssh&role_level=use_role'; - break; - case 'scm_credential': - query += '&kind=scm&role_level=use_role'; - break; - case 'network_credential': - query += '&kind=net&role_level=use_role'; - break; - case 'cloud_credential': - query += '&cloud=true&role_level=use_role'; - break; - case 'organization': - if ($state.current.name.includes('inventories')) { - query += '&role_level=inventory_admin_role'; - } else if ($state.current.name.includes('templates.editWorkflowJobTemplate')) { - query += '&role_level=workflow_admin_role'; - } else if ($state.current.name.includes('projects')) { - query += '&role_level=project_admin_role'; - } else { - query += '&role_level=admin_role'; - } - break; - case 'inventory_script': - query += '&role_level=admin_role&organization=' + scope.$resolve.inventoryData.summary_fields.organization.id; - break; - default: - query += '&role_level=use_role'; - } - } - - Rest.setUrl(`${basePath}${query}`); - // https://github.com/ansible/ansible-tower/issues/3549 - // capturing both success/failure conditions in .then() promise - // when #3549 is resolved, this will need to be partitioned into success/error or then/catch blocks - return Rest.get() - .then((res) => { - if (res.data.results.length > 0) { - scope[elm.attr('data-source')] = res.data.results[0].id; - return setValidity(ctrl, true); - } else { - scope[elm.attr('data-source')] = null; - return setValidity(ctrl, false); - } - }); - } - - function setValidity(ctrl, validity){ - var isRequired; - if (attrs.required) { - isRequired = true; - } else { - isRequired = false; - } - if (attrs.awRequiredWhen) { - if (attrs.awRequiredWhen.charAt(0) === "!") { - isRequired = !scope[attrs.awRequiredWhen.slice(1, attrs.awRequiredWhen.length)]; - } else { - isRequired = scope[attrs.awRequiredWhen]; - } - } - if (!isRequired && (viewValue === undefined || viewValue === undefined || viewValue === "")) { - validity = true; - } - ctrl.$setValidity('awlookup', validity); - return defer.resolve(validity); - } - - // Three common cases for clarity: - - // 1) Field is not required & pristine. Pass validation & skip async $pending state - // 2) Field is required. Always validate & use async $pending state - // 3) Field is not required, but is not $pristine. Always validate & use async $pending state - - // case 1 - if (!ctrl.$validators.required && ctrl.$pristine) { - return setValidity(ctrl, true); - } - // case 2 & 3 - else { - return applyValidation(viewValue); - } - } - } - }; -}]) - -// -// awValidUrl -// -.directive('awValidUrl', [function() { - return { - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - ctrl.$parsers.unshift(function(viewValue) { - var validity = true, - rgx, rgx2; - if (viewValue !== '') { - ctrl.$setValidity('required', true); - rgx = /^(https|http|ssh)\:\/\//; - rgx2 = /\@/g; - if (!rgx.test(viewValue) || rgx2.test(viewValue)) { - validity = false; - } - } - ctrl.$setValidity('awvalidurl', validity); - - return viewValue; - }); - } - }; -}]) - -/* - * Enable TB tooltips. To add a tooltip to an element, include the following directive in - * the element's attributes: - * - * aw-tool-tip="<< tooltip text here >>" - * - * Include the standard TB data-XXX attributes to controll a tooltip's appearance. We will - * default placement to the left and delay to the config setting. - */ -.directive('awToolTip', ['$transitions', function($transitions) { - return { - link: function(scope, element, attrs) { - var delay = { show: 200, hide: 0 }, - placement, - container, - stateChangeWatcher; - if (attrs.awTipPlacement) { - placement = attrs.awTipPlacement; - } else { - placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left'; - } - - container = attrs.container ? attrs.container : 'body'; - - var template; - - let tooltipInnerClass = (attrs.tooltipInnerClass || attrs.tooltipinnerclass) ? (attrs.tooltipInnerClass || attrs.tooltipinnerclass) : ''; - let tooltipOuterClass = attrs.tooltipOuterClass ? attrs.tooltipOuterClass : ''; - - template = ''; - - // This block helps clean up tooltips that may get orphaned by a click event - $(element).on('mouseenter', function(event) { - - var elem = $(event.target).parent(); - if (elem[0].nodeName === "SOURCE-SUMMARY-POPOVER") { - $('.popover').popover('hide'); - } - - if (stateChangeWatcher) { - // Un-bind - we don't want a bunch of listeners firing - stateChangeWatcher(); - } - - stateChangeWatcher = $transitions.onStart({}, function() { - // Go ahead and force the tooltip setTimeout to expire (if it hasn't already fired) - $(element).tooltip('hide'); - // Clean up any existing tooltips including this one - $('.tooltip').each(function() { - $(this).remove(); - }); - }); - }); - - $(element).on('hidden.bs.tooltip', function() { - // TB3RC1 is leaving behind tooltip
elements. This will remove them - // after a tooltip fades away. If not, they lay overtop of other elements and - // honk up the page. - $('.tooltip').each(function() { - $(this).remove(); - }); - }); - - $(element).tooltip({ - placement: placement, - delay: delay, - html: true, - title: attrs.awToolTip, - container: container, - trigger: 'hover', - template: template - }); - - if (attrs.tipWatch) { - // Add dataTipWatch: 'variable_name' - scope.$watch(attrs.tipWatch, function(newVal) { - // Where did fixTitle come from?: - // http://stackoverflow.com/questions/9501921/change-twitter-bootstrap-tooltip-content-on-click - $(element).tooltip('hide').attr('data-original-title', newVal).tooltip('fixTitle'); - }); - } - } - }; -}]) - -/* - * Enable TB pop-overs. To add a pop-over to an element, include the following directive in - * the element's attributes: - * - * aw-pop-over="<< pop-over html here >>" - * - * Include the standard TB data-XXX attributes to controll the pop-over's appearance. We will - * default placement to the left, delay to 0 seconds, content type to HTML, and title to 'Help'. - */ -.directive('awPopOver', ['$compile', function($compile) { - return function(scope, element, attrs) { - var placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left', - title = (attrs.overTitle) ? attrs.overTitle : (attrs.popoverTitle) ? attrs.popoverTitle : 'Help', - container = (attrs.container !== undefined) ? attrs.container : false, - trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manual', - template = '', - id_to_close = ""; - - if (element[0].id) { - template = ''; - } - - scope.triggerPopover = function(e) { - showPopover(e); - }; - - if (attrs.awPopOverWatch) { - $(element).popover({ - placement: placement, - delay: 0, - title: title, - content: function() { - return scope[attrs.awPopOverWatch]; - }, - trigger: trigger, - html: true, - container: container, - template: template - }); - } else { - $(element).popover({ - placement: placement, - delay: 0, - title: title, - content: attrs.awPopOver, - trigger: trigger, - html: true, - container: container, - template: template - }); - } - $(element).attr('tabindex', -1); - - $(element).one('click', showPopover); - - function bindPopoverDismiss() { - $('body').one('click.popover' + id_to_close, function(e) { - if ($(e.target).parents(id_to_close).length === 0) { - // case: you clicked to open the popover and then you - // clicked outside of it...hide it. - $(element).popover('hide'); - } else { - // case: you clicked to open the popover and then you - // clicked inside the popover - bindPopoverDismiss(); - } - }); - } - - $(element).on('shown.bs.popover', function() { - bindPopoverDismiss(); - $(document).on('keydown.popover', dismissOnEsc); - }); - - $(element).on('hidden.bs.popover', function() { - $(element).off('click', dismissPopover); - $(element).off('click', showPopover); - $('body').off('click.popover.' + id_to_close); - $(element).one('click', showPopover); - $(document).off('keydown.popover', dismissOnEsc); - }); - - function showPopover(e) { - e.stopPropagation(); - - var self = $(element); - - // remove tool-tip - try { - element.tooltip('hide'); - } catch (ex) { - // ignore - } - - // this is called on the help-link (over and over again) - $('.help-link, .help-link-white').each(function() { - if (self.attr('id') !== $(this).attr('id')) { - try { - // not sure what this does different than the method above - $(this).popover('hide'); - } catch (e) { - // ignore - } - } - }); - - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - $('.tooltip').each(function() { - // close any lingering tool tips - $(this).hide(); - }); - - // set id_to_close of the actual open element - id_to_close = "#" + $(element).attr('id') + "_popover_container"; - - // $(element).one('click', dismissPopover); - - $(element).popover('toggle'); - - $('.popover').each(function() { - $compile($(this))(scope); //make nested directives work! - }); - } - - function dismissPopover(e) { - e.stopPropagation(); - $(element).popover('hide'); - } - - function dismissOnEsc(e) { - if (e.keyCode === 27) { - $(element).popover('hide'); - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - // $(this).remove(); - }); - } - } - - }; -}]) - -// -// Enable jqueryui slider widget on a numeric input field -// -// -// -.directive('awSlider', [function() { - return { - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - var name = elm.attr('name'); - $('#' + name + '-slider').slider({ - value: 0, - step: 1, - min: elm.attr('min'), - max: elm.attr('max'), - disabled: (elm.attr('readonly')) ? true : false, - slide: function(e, u) { - ctrl.$setViewValue(u.value); - ctrl.$setValidity('required', true); - ctrl.$setValidity('min', true); - ctrl.$setValidity('max', true); - ctrl.$dirty = true; - ctrl.$render(); - if (!scope.$$phase) { - scope.$digest(); - } - } - }); - - $('#' + name + '-number').change(function() { - $('#' + name + '-slider').slider('value', parseInt($(this).val(), 10)); - }); - - } - }; -}]) - -// -// Enable jqueryui spinner widget on a numeric input field -// -// -// -.directive('awSpinner', [function() { - return { - require: 'ngModel', - link: function(scope, elm, attrs, ctrl) { - var disabled, opts; - disabled = elm.attr('data-disabled'); - opts = { - value: 0, - step: 1, - min: elm.attr('min'), - max: elm.attr('max'), - numberFormat: "d", - disabled: (elm.attr('readonly')) ? true : false, - icons: { - down: "Form-numberInputButton fa fa-angle-down", - up: "Form-numberInputButton fa fa-angle-up" - }, - spin: function(e, u) { - ctrl.$setViewValue(u.value); - ctrl.$setValidity('required', true); - ctrl.$setValidity('min', true); - ctrl.$setValidity('max', true); - ctrl.$dirty = true; - ctrl.$render(); - if (scope.job_template_form) { - // need a way to find the parent form and mark it dirty - scope.job_template_form.$dirty = true; - } - if (!scope.$$phase) { - scope.$digest(); - } - } - }; - - // hack to get ngDisabled to work - if (attrs.ngDisabled) { - scope.$watch(attrs.ngDisabled, function(val) { - opts.disabled = (val === true) ? true : false; - $(elm).spinner(opts); - }); - } - - if (disabled) { - opts.disabled = true; - } - $(elm).spinner(opts); - $('.ui-icon').text(''); - $(".ui-icon").removeClass('ui-icon ui-icon-triangle-1-n ui-icon-triangle-1-s'); - $(elm).on("click", function() { - $(elm).select(); - }); - } - }; -}]) - -/* - * Make an element draggable. Used on inventory groups tree. - * - * awDraggable: boolean || {{ expression }} - * - */ -.directive('awDraggable', [function() { - return function(scope, element, attrs) { - - if (attrs.awDraggable === "true") { - var containment = attrs.containment; //provide dataContainment:"#id" - $(element).draggable({ - containment: containment, - scroll: true, - revert: "invalid", - helper: "clone", - start: function(e, ui) { - ui.helper.addClass('draggable-clone'); - }, - zIndex: 100, - cursorAt: { left: -1 } - }); - } - }; -}]) - -// Toggle switch inspired by http://www.bootply.com/92189 -.directive('awToggleButton', [function() { - return function(scope, element) { - $(element).click(function() { - var next, choice; - $(this).find('.btn').toggleClass('active'); - if ($(this).find('.btn-primary').size() > 0) { - $(this).find('.btn').toggleClass('btn-primary'); - } - if ($(this).find('.btn-danger').size() > 0) { - $(this).find('.btn').toggleClass('btn-danger'); - } - if ($(this).find('.btn-success').size() > 0) { - $(this).find('.btn').toggleClass('btn-success'); - } - if ($(this).find('.btn-info').size() > 0) { - $(this).find('.btn').toggleClass('btn-info'); - } - $(this).find('.btn').toggleClass('btn-default'); - - // Add data-after-toggle="functionName" to the btn-group, and we'll - // execute here. The newly active choice is passed as a parameter. - if ($(this).attr('data-after-toggle')) { - next = $(this).attr('data-after-toggle'); - choice = $(this).find('.active').text(); - setTimeout(function() { - scope.$apply(function() { - scope[next](choice); - }); - }); - } - - }); - }; -}]) - -// -// Support dropping files on an element. Used on credentials page for SSH/RSA private keys -// Inspired by https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications -// -.directive('awDropFile', ['Alert', function(Alert) { - return { - require: 'ngModel', - link: function(scope, element, attrs, ctrl) { - $(element).on('dragenter', function(e) { - e.stopPropagation(); - e.preventDefault(); - }); - $(element).on('dragover', function(e) { - e.stopPropagation(); - e.preventDefault(); - }); - $(element).on('drop', function(e) { - var dt, files, reader; - e.stopPropagation(); - e.preventDefault(); - dt = e.originalEvent.dataTransfer; - files = dt.files; - reader = new FileReader(); - reader.onload = function() { - ctrl.$setViewValue(reader.result); - ctrl.$render(); - ctrl.$setValidity('required', true); - ctrl.$dirty = true; - if (!scope.$$phase) { - scope.$digest(); - } - }; - reader.onerror = function() { - Alert('Error', 'There was an error reading the selected file.'); - }; - if (files[0].size < 10000) { - reader.readAsText(files[0]); - } else { - Alert('Error', 'There was an error reading the selected file.'); - } - }); - } - }; -}]) - -.directive('awPasswordToggle', [function() { - return { - restrict: 'A', - link: function(scope, element) { - $(element).click(function() { - var buttonInnerHTML = $(element).html(); - if (buttonInnerHTML.indexOf("Show") > -1) { - $(element).html("Hide"); - $(element).closest('.input-group').find('input').first().attr("type", "text"); - } else { - $(element).html("Show"); - $(element).closest('.input-group').find('input').first().attr("type", "password"); - } - }); - } - }; -}]) - -.directive('awEnterKey', [function() { - return { - restrict: 'A', - link: function(scope, element, attrs) { - element.bind("keydown keypress", function(event) { - var keyCode = event.which || event.keyCode; - if (keyCode === 13) { - scope.$apply(function() { - scope.$eval(attrs.awEnterKey); - }); - event.preventDefault(); - } - }); - } - }; -}]) - -.directive('awTruncateBreadcrumb', ['BreadCrumbService', function(BreadCrumbService) { - return { - restrict: 'A', - scope: { - breadcrumbStep: '=' - }, - link: function(scope) { - scope.$watch('breadcrumbStep.ncyBreadcrumbLabel', function(){ - BreadCrumbService.truncateCrumbs(); - }); - } - }; -}]) - -.directive('awRequireMultiple', ['Empty', function(Empty) { - return { - require: 'ngModel', - link: function postLink(scope, element, attrs, ngModel) { - // Watch for changes to the required attribute - attrs.$observe('required', function() { - ngModel.$validate(); - }); - - ngModel.$validators.multipleSelect = function (modelValue) { - if(attrs.required) { - if(angular.isArray(modelValue)) { - // Checks to make sure at least one value in the array - return _.some(modelValue, function(arrayVal) { - return !Empty(arrayVal); - }); - } else { - return !Empty(modelValue); - } - } else { - return true; - } - }; - } - }; -}]); diff --git a/awx/ui/client/src/shared/download-standard-out.block.less b/awx/ui/client/src/shared/download-standard-out.block.less deleted file mode 100644 index 0efdb3001af3..000000000000 --- a/awx/ui/client/src/shared/download-standard-out.block.less +++ /dev/null @@ -1,28 +0,0 @@ -/** @define DownloadStandardOut */ - -.DownloadStandardOut { - color: @default-bg !important; -} - -.DownloadStandardOut--onStandardOutPage { - margin-top: -3px; - margin-right: -9px; - float: right; -} - -.DownloadStandardOut--onModal { - margin-bottom: 10px; - float: right; -} - -.DownloadStandardOut-icon { - color: @default-bg; -} - -.DownloadStandardOut-icon--withText { - margin-right: 5px; -} - -.DownloadStandardOut-pre { - width: 100%; -} diff --git a/awx/ui/client/src/shared/features/features.controller.js b/awx/ui/client/src/shared/features/features.controller.js deleted file mode 100644 index 198ac661d254..000000000000 --- a/awx/ui/client/src/shared/features/features.controller.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$rootScope', function ($rootScope) { - - this.isFeatureEnabled = function(feature){ - if(_.isEmpty($rootScope.features)){ - return false; - } else{ - return $rootScope.features[feature] || false; - } - }; -}]; diff --git a/awx/ui/client/src/shared/features/features.directive.js b/awx/ui/client/src/shared/features/features.directive.js deleted file mode 100644 index 341afba0a2df..000000000000 --- a/awx/ui/client/src/shared/features/features.directive.js +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc overview - * @name features - * @scope - * @description enables/disables features based on license - * - * @ngdoc directive - * @name features.directive:awFeature - * @description The aw-feature directive works by taking in a string - * that maps to a license feature, and removes that feature from the - * DOM if it is a feature not supported by the user's license. - * For example, adding `aw-feature="system-tracking"` will enable or disable - * the system tracking button based on the license configuration on the - * /config endpoint. - * - * -*/ -import featureController from './features.controller'; - -export default [ '$rootScope', function($rootScope) { - return { - restrict: 'A', - controller: featureController, - link: function (scope, element, attrs, controller){ - if(attrs.awFeature.length > 0){ - $rootScope.featuresConfigured.promise.then(function() { - if(!controller.isFeatureEnabled(attrs.awFeature)){ - element.remove(); - } - }); - } - } - - }; -}]; diff --git a/awx/ui/client/src/shared/features/features.service.js b/awx/ui/client/src/shared/features/features.service.js deleted file mode 100644 index b4fa6b6b3b94..000000000000 --- a/awx/ui/client/src/shared/features/features.service.js +++ /dev/null @@ -1,35 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$rootScope', 'ConfigService', -function ($rootScope, ConfigService) { - return { - get: function(){ - if (_.isEmpty($rootScope.features)) { - var config = ConfigService.get(); - if(config){ - $rootScope.features = config.license_info.features; - if($rootScope.featuresConfigured){ - $rootScope.featuresConfigured.resolve($rootScope.features); - } - return $rootScope.features; - } - } - else{ - return $rootScope.features; - } - }, - - featureEnabled: function(feature) { - if($rootScope.features && $rootScope.features[feature] && $rootScope.features[feature] === true) { - return true; - } - else { - return false; - } - } - }; -}]; diff --git a/awx/ui/client/src/shared/features/main.js b/awx/ui/client/src/shared/features/main.js deleted file mode 100644 index 62dea24b43ec..000000000000 --- a/awx/ui/client/src/shared/features/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import awFeatureDirective from './features.directive'; -import FeaturesService from './features.service'; - -export default - angular.module('features', []) - .directive('awFeature', awFeatureDirective) - .service('FeaturesService', FeaturesService); diff --git a/awx/ui/client/src/shared/filters/append.filter.js b/awx/ui/client/src/shared/filters/append.filter.js deleted file mode 100644 index 1493cf59972e..000000000000 --- a/awx/ui/client/src/shared/filters/append.filter.js +++ /dev/null @@ -1,15 +0,0 @@ -export default function() { - return function(string, append) { - if (string) { - if (append) { - return string + append; - } - else { - return string; - } - } - else { - return ""; - } - }; -} diff --git a/awx/ui/client/src/shared/filters/capitalize.filter.js b/awx/ui/client/src/shared/filters/capitalize.filter.js deleted file mode 100644 index 859dd367e16a..000000000000 --- a/awx/ui/client/src/shared/filters/capitalize.filter.js +++ /dev/null @@ -1,12 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default [function() { - return function(input) { - input = input.charAt(0).toUpperCase() + input.substr(1).toLowerCase(); - return input; - }; - }]; diff --git a/awx/ui/client/src/shared/filters/format-epoch.filter.js b/awx/ui/client/src/shared/filters/format-epoch.filter.js deleted file mode 100644 index 9d8fee351f53..000000000000 --- a/awx/ui/client/src/shared/filters/format-epoch.filter.js +++ /dev/null @@ -1,14 +0,0 @@ -export default -[ 'moment', - function(moment) { - return function(seconds, formatStr) { - if (!formatStr) { - formatStr = 'll LT'; - } - - var millis = seconds * 1000; - - return moment(millis).format(formatStr); - }; - } -]; diff --git a/awx/ui/client/src/shared/filters/is-empty.filter.js b/awx/ui/client/src/shared/filters/is-empty.filter.js deleted file mode 100644 index a0ece767f1b6..000000000000 --- a/awx/ui/client/src/shared/filters/is-empty.filter.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default function() { - return function (obj) { - var key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - return false; - } - } - return true; - }; - } diff --git a/awx/ui/client/src/shared/filters/long-date.filter.js b/awx/ui/client/src/shared/filters/long-date.filter.js deleted file mode 100644 index f2d058e3b24d..000000000000 --- a/awx/ui/client/src/shared/filters/long-date.filter.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default ['moment', function(moment) { - return function(input) { - var date; - if(input === null || input === undefined){ - return ""; - }else { - date = moment(input); - return date.format('l LTS'); - } - }; - }]; diff --git a/awx/ui/client/src/shared/filters/main.js b/awx/ui/client/src/shared/filters/main.js deleted file mode 100644 index 2298bb0723b4..000000000000 --- a/awx/ui/client/src/shared/filters/main.js +++ /dev/null @@ -1,17 +0,0 @@ -import prepend from './prepend.filter'; -import append from './append.filter'; -import isEmpty from './is-empty.filter'; -import capitalize from './capitalize.filter'; -import longDate from './long-date.filter'; -import sanitize from './xss-sanitizer.filter'; -import formatEpoch from './format-epoch.filter'; - -export default - angular.module('stringFilters', []) - .filter('prepend', prepend) - .filter('append', append) - .filter('isEmpty', isEmpty) - .filter('capitalize', capitalize) - .filter('longDate', longDate) - .filter('sanitize', sanitize) - .filter('formatEpoch', formatEpoch); diff --git a/awx/ui/client/src/shared/filters/prepend.filter.js b/awx/ui/client/src/shared/filters/prepend.filter.js deleted file mode 100644 index 93bad2889d1a..000000000000 --- a/awx/ui/client/src/shared/filters/prepend.filter.js +++ /dev/null @@ -1,15 +0,0 @@ -export default function() { - return function(string, prepend) { - if (string) { - if(prepend) { - return prepend + string; - } - else { - return string; - } - } - else { - return ""; - } - }; -} diff --git a/awx/ui/client/src/shared/filters/xss-sanitizer.filter.js b/awx/ui/client/src/shared/filters/xss-sanitizer.filter.js deleted file mode 100644 index ef1c16d32d03..000000000000 --- a/awx/ui/client/src/shared/filters/xss-sanitizer.filter.js +++ /dev/null @@ -1,12 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default [function() { - return function(input) { - input = $("").text(input)[0].innerHTML; - return input; - }; - }]; diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js deleted file mode 100644 index 574e8e834279..000000000000 --- a/awx/ui/client/src/shared/form-generator.js +++ /dev/null @@ -1,2027 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - - /** - * @ngdoc function - * @name shared.function:form-generator - * @description - * - * Generate form HTML from a form object. Form objects are found in /forms. - * - * #Generate and Inject Form - * - * To generate a form and inject it into the DOM the default method call is: - * - * ``` - * GenerateForm.inject(form, { mode: 'edit', related: true, scope: $scope}); - * ``` - * Expects 2 parameters where the first is a reference to a form object, and the second is an object of key/value parameter pairs. Returns the $scope object associated with the generated HTML. - * - * Parameters that can be passed: - * - * | Parameter | Required | Description | - * | --------- | -------- | ----------- | - * | html | | String of HTML to be injected. Overrides HTML that would otherwise be generated using the form object. (Not sure if this is actually used anywhere.) | - * | id | | The ID attribute value of the DOM elment that will receive the generated HTML. If provided, form generator will inject the HTML it genertates into the DOM element identified by the string value provided. Do not preceed the value with '#' | - * | mode | Y | 'add', 'edit' or 'modal'. Use add when creating new data - creating a new orgranization, for example. Use edit when modifying existing data. Modal is deprecated. Use the 'id' option to inject a form into a modal dialog. | - * | scope | | Reference to $scope object. Will be passed to $compile and associated with any angular directives contained within the generated HTML. | - * | showButtons | | true or false. If false, buttons defined in the buttons object will not be included in the generated HTML. | - * - * #Generate HTML Only - * - * To generate the HTML only and not inject it into the DOM use the buildHTML() method: - * - * ``` - * GenerateForm.buildHTML(JobVarsPromptForm, { mode: 'edit', modal: true, scope: scope }); - * ``` - * - * Pass the same parameters as above. Returns a string containing the generated HTML. - * - * #Reset Form - * - * Call GenerateFrom.reset() to clear user input, remove error messages and return the angular form object back to a pristine state. This is should be called when the user clicks the Reset button. - * - * #Form definitions - * - * See forms/*.js for examples. - * - * The form object can have the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | collapse | true or false. If true, places the form inside a jQueryUI accordion | - * | collapseMode | 'add' or 'edit'. If the value of the mode parameter passed into .inject() or .buildHTML() matches collapseMode, the <form> will be placed in an accordion. | - * | collapseOpen | true or false. If true, the accordion will be open the first time the user views the form, or if no state information is found in local storage for the accordion. Subsequent views will depend on accordion state found in local storage. Each time user opens/closes an accordion the state is saved in local storage. | - * | collapseOpenFirst | true or false. If true, the collapse will be open everytime the accordion is viewed, regardless of state data found in local storage. | - * | collapseTitle | Text to use in the <h3> element of the accordion. Typically this will be 'Properties' | - * | name | Name to give the form object. Used to create the id and name attribute values in the
element. | - * | showActions | true or false. By default actions found in the actions object will be displayed at the top of the page. If set to false, actions will not be displayed. | - * | twoColumns | true or false. By default fields are placed in a single vertical column following the Basic Example in the [Bootstrap form documentation](http://getbootstrap.com/css/#forms). Set to true for a 2 column layout as seen on the Job Templates detail page.| - * | well | true or false. If true, wraps the with <div class="aw-form-well"></div> | - * - * The form object will contain a fields object to hold the definiation of each field in the form. Attributes on a field object determine the HTML generated for the actual <input> or <textarea> element. Fields can have the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | awPopOver | Adds aw-pop-over directive. Set to a string containing the text or html to be evaluated by the directive. | - * | awPopOverWatch | Causes the awPopOver directive to add a $scope.$watch on the specified scop variable. When the value of the variable changes the popover text will be updated with the change. | - * | awRequiredWhen | Adds aw-required-when directive. Set to an object to be evaluated by the directive. | - * | capitalize | true or false. If true, apply the 'capitalize' filter to the field. | - * | class | String cotaining one or more CSS class values. | - * | column | If the twoColumn option is being used, supply an integer value of 1 or 2 representing the column in which to place the field. 1 places the field in the left column, and 2 places it on the right. | - * | dataContainer | Used with awPopOver. String providing the containment parameter. | - * | dataPlacement | Used with awPopOver and awToolTip. String providing the placement parameter (i.e. left, right, top, bottom, etc.). | - * | dataTitle | Used with awPopOver. String value for the title of the popover. | - * | default | Default value to place in the field when the form is in 'add' mode. | - * | defaultText | Default value to put into a select input. | - * | falseValue | For radio buttons and checkboxes. Value to set the model to when the checkbox or radio button is not selected. | - * | genMD5 | true or false. If true, places the field in an input group with a button that when clicked replaces the field contents with an MD5 has key. Used with host_config_key on the job templates detail page. | - * | integer | Adds the integer directive to validate that the value entered is of type integer. Add min and max to supply lower and upper range bounds to the entered value. | - * | label | Text to use as <label> element for the field | - * | ngChange | Adds ng-change directive. Set to the JS expression to be evaluated by ng-change. | - * | ngClick | Adds ng-click directive. Set to the JS expression to be evaluated by ng-click. | - * | ngHide | Adds ng-hide directive. Set to the JS expression to be evaluated by ng-hide. | - * | ngShow | Adds ng-show directive. Set to the JS expression to be evaluated by ng-show. | - - * | readonly | Defaults to false. When true the readonly attribute is set, disallowing changes to field content. | - * | required | boolean. Adds required flag to form field | - * | rows | Integer value used to set the row attribute for a textarea. | - * | sourceModel | Used in conjunction with sourceField when the data for the field is part of the summary_fields object returned by the API. Set to the name of the summary_fields object that contains the field. For example, the job_templates object returned by the API contains summary_fields.inventory. | - * | sourceField | String containing the summary_field.object.field name from the API summary_field object. For example, if a fields should be associated to the summary_fields.inventory.name, set the sourceModel to 'inventory' and the sourceField to 'name'. | - * | spinner | true or false. If true, adds aw-spinner directive. Optionally add min and max attributes to control the range of allowed values. | - * | type | String containing one of the following types defined in buildField: alertblock, hidden, text, password, email, textarea, select, number, checkbox, checkbox_group, radio, radio_group, lookup, custom. | - * | trueValue | For radio buttons and checkboxes. Value to set the model to when the checkbox or radio button is selected. | - * | hasShowInputButton (sensitive type only) | This creates a button next to the input that toggles the input as text and password types. | - * The form object contains a buttons object for defining any buttons to be included in the generated HTML. Generally all forms will have a Reset and a Submit button. If no buttons should be generated define buttons as an empty object, or set the showButtons option to false. - * - * The icon used for the button is determined by SelectIcon() found in js/shared/generator-helpers.js. - * - * | Attribute | Description | - * | --------- | ----------- | - * | class | If the name of the button is reset or save, the class is automatically set to the correct bootstrap btn class for the color. Otherwise, provide a string with any classes to be added to the <button> element. | - * | label | For reset and save buttons the label is automatically set. For other types of buttons set label to the text string that should appear in the button. | - * | ngClick | Adds the ng-click directive to the button. Set to the JS expression for the ng-click directive to evaluate. | - * | ngDisabled | Only partially implemented at this point. For buttons other than reset, the ng-disabled directive is always added. The button will be disabled when the form is in an invalid state. | - * - * The form object may contain an actions object. The action object can contain one or more button definitions for buttons to appear in the top-right corner of the form. This may include activity stream, refresh, properties, etc. Each button object defined in actions may have the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | awToolTip | Text or html to display in the button tooltip. Adds the aw-tool-tip directive. | - * | class | Optional classes to add to the <button> element. | - * | dataPlacement | Set the placement attribute of the tooltip - left, right, top, bottom, etc. | - * | ngClick | Set to the JS expression to be evaluated by the ng-click directive. | - * | mode | Set to edit or add, depending on which mode the button | - * | - * - * The form object may contain a related object. The related object contains one or more list objects defining sublists to display in accordions. For example, the Organization form contains a related users list and admins list. - * - * As originally conceived sublists were stored inside the form definition without regard to any list definitions found in the lists folder. In other words, lists/Users.js is completely different from the related.users object found in forms/Organizations.js. In reality they - * are very similar and lists/Users.js should be used to generate the users sublist on the organizations detail page. - * - * One approach to making this work and using list definintion inside a from was implemented in forms/JobTemplates.js. In controllers/JobTemplates.js within JobTemplatesEdit() the form object is created by calling the JobTemplateForm() method found in forms/JobTemplates.js. The - * method injects the SchedulesList and CompletedJobsList into the form object as related sets. Going forward this approach or similar should be used whenever a sublist needs to be added to a form. - * - * #Variable editing - * - * If the field type is textarea and the name is one of variables, extra_vars, inventory_variables or source_vars, then the parse type radio button group is added. This is the radio button group allowing the user to switch between JSON and YAML. - * - * Applying CodeMirror to the text area is handled by ParseTypeChange() found in helpers/Parse.js. Within the controller will be a call to ParseTypeChange that creates the CodeMirror object and sets up the required $scope methods for handles getting, setting and type conversion. - */ - -import GeneratorHelpers from './generator-helpers'; -import listGenerator from './list-generator/main'; - -export default -angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerator.name]) - -.factory('GenerateForm', ['$rootScope', '$compile', 'generateList', - 'Attr', 'Icon', 'Column', - 'NavigationLink', 'HelpCollapse', 'Empty', 'SelectIcon', - 'ActionButton', 'MessageBar', '$log', 'i18n', - function ($rootScope, $compile, GenerateList, - Attr, Icon, Column, NavigationLink, HelpCollapse, - Empty, SelectIcon, ActionButton, MessageBar, $log, i18n) { - return { - - setForm: function (form) { this.form = form; }, - - attr: Attr, - - icon: Icon, - - accordion_count: 0, - - scope: null, - - has: function (key) { - return (this.form[key] && this.form[key] !== null && this.form[key] !== undefined) ? true : false; - }, - // Not a very good way to do this - // Form sub-states expect to target ui-views related@stateName & modal@stateName - // Also wraps mess of generated HTML in a .Panel - wrapPanel(html, ignorePanel){ - if(ignorePanel) { - return ` -
-
- ${html} -
-
-
`; - } - else { - return ` -
- ${MessageBar(this.form)} -
- ${html} -
-
-
`; - } - }, - - inject: function (form, options) { - // - // Use to inject the form as html into the view. View MUST have an ng-bind for 'htmlTemplate'. - // Returns scope of form. - // - - var element, fld, set, show, self = this; - - if (options.modal) { - if (options.modal_body_id) { - element = angular.element(document.getElementById(options.modal_body_id)); - } else { - // use default dialog - element = angular.element(document.getElementById('form-modal-body')); - } - } else { - if (options.id) { - element = angular.element(document.getElementById(options.id)); - } else { - element = angular.element(document.getElementById('htmlTemplate')); - } - } - - this.mode = options.mode; - this.modal = (options.modal) ? true : false; - this.setForm(form); - - if (options.html) { - element.html(options.html); - } else { - element.html(this.build(options)); - } - - if (options.scope) { - this.scope = options.scope; - } else { - this.scope = element.scope(); - } - - if (options.mode) { - this.scope.mode = options.mode; - } - - if(options.mode === 'edit' && this.form.related && - !_.isEmpty(this.form.related)){ - var tabs = [this.form.name], that = this; - tabs.push(Object.keys(this.form.related)); - tabs = _.flatten(tabs); - _.map(tabs, function(itm){ - that.scope.$parent[itm+"Selected"] = false; - }); - this.scope.$parent[this.form.name+"Selected"] = true; - - - this.scope.$parent.toggleFormTabs = function($event){ - _.map(tabs, function(itm){ - that.scope.$parent[itm+"Selected"] = false; - }); - that.scope.$parent[$event.target.id.split('_tab')[0]+"Selected"] = true; - }; - - } - - for (fld in form.fields) { - this.scope[fld + '_field'] = form.fields[fld]; - this.scope[fld + '_field'].name = fld; - } - - for (fld in form.headerFields){ - this.scope[fld + '_field'] = form.headerFields[fld]; - this.scope[fld + '_field'].name = fld; - } - - $compile(element)(this.scope); - - if (!options.html) { - // Reset the scope to prevent displaying old data from our last visit to this form - for (fld in form.fields) { - this.scope[fld] = null; - } - for (set in form.related) { - this.scope[set] = null; - } - // if (((!options.modal) && options.related) || this.form.forceListeners) { - // this.addListeners(); - // } - if (options.mode === 'add') { - this.applyDefaults(form, this.scope); - } - } - - // Remove any lingering tooltip and popover
elements - $('.tooltip').each(function () { - $(this).remove(); - }); - - $('.popover').each(function () { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - - try { - $('#help-modal').empty().dialog('destroy'); - } catch (e) { - //ignore any errors should the dialog not be initialized - } - - if (options.modal) { - $rootScope.flashMessage = null; - this.scope.formModalActionDisabled = false; - this.scope.formModalInfo = false; //Disable info button for default modal - if (form) { - if (options.modal_title_id) { - this.scope[options.modal_title_id] = (options.mode === 'add') ? form.addTitle : form.editTitle; - } else { - this.scope.formModalHeader = (options.mode === 'add') ? form.addTitle : form.editTitle; //Default title for default modal - } - } - if (options.modal_selector) { - $(options.modal_selector).modal({ - show: true, - backdrop: 'static', - keyboard: true - }); - $(options.modal_selector).on('shown.bs.modal', function () { - $(options.modal_select + ' input:first').focus(); - }); - $(options.modal_selector).on('hidden.bs.modal', function () { - $('.tooltip').each(function () { - // Remove any lingering tooltip and popover
elements - $(this).remove(); - }); - - $('.popover').each(function () { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - }); - } else { - show = (options.show_modal === false) ? false : true; - $('#form-modal').modal({ - show: show, - backdrop: 'static', - keyboard: true - }); - $('#form-modal').on('shown.bs.modal', function () { - $('#form-modal input:first').focus(); - }); - $('#form-modal').on('hidden.bs.modal', function () { - $('.tooltip').each(function () { - // Remove any lingering tooltip and popover
elements - $(this).remove(); - }); - - $('.popover').each(function () { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - }); - } - $(document).bind('keydown', function (e) { - if (e.keyCode === 27) { - if (options.modal_selector) { - $(options.modal_selector).modal('hide'); - } - $('#prompt-modal').modal('hide'); - $('#form-modal').modal('hide'); - } - }); - } - - if (self.scope && !self.scope.$$phase) { - setTimeout(function() { - if (self.scope) { - self.scope.$digest(); - } - }, 100); - } - - return self.scope; - - }, - - buildHTML: function(form, options) { - // Get HTML without actually injecting into DOM. Caller is responsible for any injection. - // Example: - // html = GenerateForm.buildHTML(JobVarsPromptForm, { mode: 'edit', modal: true, scope: scope }); - - this.mode = options.mode; - //this.modal = (options.modal) ? true : false; - this.setForm(form); - return this.build(options); - }, - - applyDefaults: function (form, scope, ignoreMode) { - if(!ignoreMode) { - // Note: This is a hack. Ideally, mode should be set in each -.controller.js - // The mode is needed by the awlookup directive to auto-populate form fields when there is a - // single related resource. - scope.mode = this.mode; - } - - for (var fld in form.fields) { - if (form.fields[fld]['default'] || form.fields[fld]['default'] === 0) { - if (form.fields[fld].type === 'select' && scope[fld + '_options']) { - scope[fld] = scope[fld + '_options'][form.fields[fld]['default']]; - } else { - scope[fld] = form.fields[fld]['default']; - } - } - } - }, - - reset: function () { - // The form field values cannot be reset with jQuery. Each field is tied to a model, so to clear the field - // value, you have to clear the model. - - var fld, scope = this.scope, - form = this.form; - - if (scope[form.name + '_form']) { - scope[form.name + '_form'].$setPristine(); - } - - function resetField(f, fld) { - // f is the field object, fld is the key - - if (f.type === 'checkbox_group') { - for (var i = 0; i < f.fields.length; i++) { - scope[f.fields[i].name] = ''; - scope[f.fields[i].name + '_api_error'] = ''; - scope[form.name + '_form'][f.fields[i].name].$setValidity('apiError', true); - } - } else { - scope[fld] = ''; - scope[fld + '_api_error'] = ''; - } - if (f.sourceModel) { - scope[f.sourceModel + '_' + f.sourceField] = ''; - scope[f.sourceModel + '_' + f.sourceField + '_api_error'] = ''; - if (scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField]) { - scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setValidity('apiError', true); - } - } - if (f.type === 'lookup' && scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField]) { - scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setPristine(); - scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setValidity('apiError', true); - } - if (scope[form.name + '_form'][fld]) { - scope[form.name + '_form'][fld].$setPristine(); - scope[form.name + '_form'][fld].$setValidity('apiError', true); - } - if (f.awPassMatch && scope[form.name + '_form'][fld]) { - scope[form.name + '_form'][fld].$setValidity('awpassmatch', true); - } - if (f.subCheckbox) { - scope[f.subCheckbox.variable] = false; - } - } - - for (fld in form.fields) { - resetField(form.fields[fld], fld); - } - if (form.statusFields) { - for (fld in form.statusFields) { - resetField(form.statusFields[fld], fld); - } - } - if (this.mode === 'add') { - this.applyDefaults(form, scope); - } - }, - - checkAutoFill: function(params) { - var fld, model, newVal, type, - scope = (params && params.scope) ? params.scope : this.scope; - for (fld in this.form.fields) { - if (this.form.fields[fld].type === 'text' || this.form.fields[fld].type === 'textarea') { - type = (this.form.fields[fld].type === 'text') ? 'input' : 'textarea'; - model = scope[this.form.name + '_form'][fld]; - newVal = $(type + '[name="' + fld + '"]').val(); - if (newVal && model && model.$viewValue !== newVal) { - model.$setViewValue(newVal); - } - } - } - }, - - genID: function () { - var id = new Date(); - return id.getTime(); - }, - - headerField: function (fld, field) { - var html = ''; - if (field.label) { - html += "\n"; - } - html += "
"; - } else if (field.type === 'html') { - html += field.html; - } - return html; - }, - - - buildField: function (fld, field, options, form) { - var i, fldWidth, offset, html = '', error_message, - horizontal = (this.form.horizontal) ? true : false; - - function getFieldWidth() { - var x; - if (form.formFieldSize) { - x = form.formFieldSize; - } else if (field.xtraWide) { - x = "col-lg-10"; - } else if (field.column) { - x = "col-lg-8"; - } else if (!form.formFieldSize && options.modal) { - x = "col-lg-10"; - } else { - x = "col-lg-6"; - } - return x; - } - - function getLabelWidth() { - var x; - if (form.formLabelSize) { - x = form.formLabelSize; - } else if (field.column) { - x = "col-lg-4"; - } else if (!form.formLabelSize && options.modal) { - x = "col-lg-2"; - } else { - x = "col-lg-2"; - } - return x; - } - - function buildId(field, fld, form) { - var html = ''; - if (field.id) { - html += Attr(field, 'id'); - } else { - html += "id=\"" + form.name + "_" + fld + "\" "; - } - return html; - } - - function buildCheckbox(form, field, fld, idx, includeLabel) { - var html = '', - label = (includeLabel !== undefined && includeLabel === false) ? false : true; - - if (label) { - html += ""; - html += "\n"; - } - - return html; - } - - if (field.type === 'toggle'){ - html += "
ON
OFF
"; - } - - if (field.type === 'alertblock') { - html += "
\n"; - html += "
\n"; - html += "
×\n" : ""; - html += field.alertTxt; - html += "
\n"; - html += "
\n"; - html += "
\n"; - } - - if ((!field.readonly) || (field.readonly && options.mode === 'edit')) { - - if((field.excludeMode === undefined || field.excludeMode !== options.mode) && field.type !== 'alertblock' && field.type !== 'workflow-chart') { - - html += "
${definedInFileMessage}` : ``; - - // toggle switches - if(field.type === 'toggleSwitch') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngModel: field.subCheckbox.variable, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - - html += `
`; - html += ` - -
`; - } - - //text fields - if (field.type === 'text' || field.type === 'password' || field.type === 'email') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngModel: field.subCheckbox.variable, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - - html += "
\n" : ""; - - if (field.control === null || field.control === undefined || field.control) { - html += "\n"; - html += "\n
\n"; - } - - if (field.genMD5) { - html += "\n
\n"; - } - - // Add error messages - if (field.required || field.awRequiredWhen) { - error_message = i18n._('Please enter a value.'); - html += "
" + (field.requiredErrorMsg ? field.requiredErrorMsg : error_message) + "
\n"; - } - if (field.type === "email") { - error_message = i18n._('Please enter a valid email address.'); - html += "
${error_message}
`; - } - if (field.awPassMatch) { - error_message = i18n._('This value does not match the password you entered previously. Please confirm that password.'); - html += "
${error_message}
`; - } - if (field.awValidUrl) { - error_message = i18n._("Please enter a URL that begins with ssh, http or https. The URL may not contain the '@' character."); - html += "
${error_message}
`; - } - - html += "
\n"; - - // Add help panel(s) - html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : ''; - - html += "
\n"; - } - - //fields with sensitive data that needs to be obfuscated from view - if (field.type === 'sensitive') { - field.showInputInnerHTML = i18n._("Show"); - field.inputType = "password"; - - html += "\t" + label(); - if (field.hasShowInputButton) { - var tooltip = i18n._("Toggle the display of plaintext."); - html += "\
\n"; - // TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field. - html += "\n"; - html += "
\n"; - } - if (field.type === "email") { - error_message = i18n._("Please enter a valid email address."); - html += "
${error_message}
`; - } - if (field.awPassMatch) { - error_message = i18n._("This value does not match the password you entered previously. Please confirm that password."); - html += "
${error_message}
`; - } - if (field.awValidUrl) { - error_message = i18n._("Please enter a URL that begins with ssh, http or https. The URL may not contain the '@' character."); - html += "
${error_message}
`; - } - - html += "
\n
\n"; - - // Add help panel(s) - html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : ''; - } - - //textarea fields - if (field.type === 'textarea') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngModel: field.subCheckbox.variable, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - - html += "
" + (field.requiredErrorMsg ? field.requiredErrorMsg : i18n._("Please enter a value.")) + "
\n"; - } - html += "
\n"; - html += "
\n"; - } - - //select field - if (field.type === 'select') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngShow: field.subCheckbox.ngShow, - ngModel: field.subCheckbox.variable, - ngChange: field.subCheckbox.ngChange, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text - }; - } - - html += label(labelOptions); - - html += "
\n"; - html += "\n"; - html += "
\n"; - - // Add error messages - if (field.required || field.awRequiredWhen) { - html += "
" + (field.requiredErrorMsg ? field.requiredErrorMsg : i18n._("Please select a value.")); - if (field.includePlaybookNotFoundError) { - html += " Playbook {{ job_template_obj.playbook }} not found for project.\n"; - } - html += "
\n"; - } - html += "
\n"; - - // Add help panel(s) - html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : ''; - - html += "
\n"; - } - - //number field - if (field.type === 'number') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngModel: field.subCheckbox.variable, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - - html += "
" + (field.requiredErrorMsg ? field.requiredErrorMsg : i18n._("Please select a value.")) + "
\n"; - } - if (field.integer) { - html += "
" + i18n._("Please enter a number.") + "
\n"; - } - if (field.min !== undefined || field.max !== undefined) { - html += "
"; - if (field.max !== undefined) { - html += i18n.sprintf(i18n._("Please enter a number greater than %d and less than %d."), field.min, field.max); - } else { - html += i18n.sprintf(i18n._("Please enter a number greater than %d."), field.min); - } - html += "
\n"; - } - html += "
\n"; - html += "
\n"; - } - - //checkbox group - if (field.type === 'checkbox_group') { - - html += label(); - - html += "
" + (field.requiredErrorMsg ? field.requiredErrorMsg : i18n._("Please select at least one value.")) + "
\n"; - } - if (field.integer) { - html += "
" + i18n._("Please select a number.") + "
\n"; - } - if (field.min || field.max) { - html += "
" + i18n._("Please select a number between ") + field.min + i18n._(" and ") + - field.max + "
\n"; - } - html += "
\n"; - html += "
\n"; - html += "
\n"; - } - - //checkbox - if (field.type === 'checkbox') { - - if (horizontal) { - fldWidth = getFieldWidth(); - offset = 12 - parseInt(fldWidth.replace(/[A-Z,a-z,-]/g, ''),10); - html += "
\n"; - } - - html += "
\n"; - html += "\n"; - html += "
\n"; - html += "
\n"; - - if (horizontal) { - html += "
\n"; - } - - html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : ''; - } - - //radio group - if (field.type === 'radio_group') { - - html += label(); - - html += "
" + i18n._("Please select a value.") + "
\n"; - } - html += "
\n"; - - // Add help panel(s) - html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : ''; - - html += "
\n"; - } - - // radio button - if (field.type === 'radio') { - - if (horizontal) { - fldWidth = getFieldWidth(); - offset = 12 - parseInt(fldWidth.replace(/[A-Z,a-z,-]/g, ''),10); - html += "
\n"; - } - - html += "
\n"; - html += "
\n"; - html += "
\n"; - - if (horizontal) { - html += "
\n"; - } - } - - //lookup type fields - if (field.type === 'lookup') { - let defaultLookupNgClick = `$state.go($state.current.name + '.${field.sourceModel}', {selected: ${field.sourceModel}})`; - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngModel: field.subCheckbox.variable, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - - html += "
`; - html += "\n"; - html += ``; - html += "\n"; - html += "" + (field.requiredErrorMsg ? field.requiredErrorMsg : i18n._("Please select a value.")) + "
\n"; - html += "
" + i18n._("That value was not found. Please enter or select a valid value.") + "
\n"; - } else { - html += "
" + i18n._("That value was not found. Please enter or select a valid value.") + "
\n"; - } - html += "
\n"; - html += "
\n"; - } - - if (field.type === 'custom') { - let labelOptions = {}; - - if (field.subCheckbox) { - labelOptions.checkbox = { - id: `${this.form.name}_${fld}_ask_chbox`, - ngShow: field.subCheckbox.ngShow, - ngChange: field.subCheckbox.ngChange, - ngModel: field.subCheckbox.variable, - ngDisabled: field.subCheckbox.ngDisabled || field.ngDisabled, - text: field.subCheckbox.text || '' - }; - } - - html += label(labelOptions); - html += "
"; - html += "
"; - html += (options.mode === 'edit') ? this.form.editTitle : this.form.addTitle; - if(this.form.name === "user"){ - html+= "" + i18n._("Admin") + ""; - html+= "" + i18n._("Auditor") + ""; - html+= "LDAP"; - html+= "{{external_account}}"; - } - if(this.form.name === "smartinventory"){ - html+= "" + i18n._("Smart Inventory") + ""; - } - html += "
\n"; - html += "
"; - if(this.form.headerFields){ - var that = this; - _.forEach(this.form.headerFields, function(value, key){ - html += that.buildHeaderField(key, value, options, that.form); - }); - html += "
\n"; - } - else{ html += "
\n"; } - if(this.form.cancelButton !== undefined && this.form.cancelButton === false) { - html += "
"; - html += "
"; - } else { - html += "
"; - html += "
\n"; - } - html += "
"; //end of Form-header - } - - if (!_.isEmpty(this.form.related) || !_.isEmpty(this.form.relatedButtons)) { - var collection, details = i18n._('Details'); - html += "
"; - - if(this.mode === "edit"){ - html += `
` + - `${details}
`; - - for (itm in this.form.related) { - collection = this.form.related[itm]; - html += `
${(collection.title || collection.editTitle)}
`; - } - - for (itm in this.form.relatedButtons) { - button = this.form.relatedButtons[itm]; - - // Build button HTML - html += "
";//tabHolder - } - - if(!_.isEmpty(this.form.related) && this.mode === "edit"){ - html += `
`; - } - - html += "\n"; - html += "
{{ flashMessage }}
\n"; - - var currentSubForm; - var hasSubFormField; - // original, single-column form - section = ''; - group = ''; - for (fld in this.form.fields) { - field = this.form.fields[fld]; - if (!(options.modal && field.excludeModal)) { - if (field.group && field.group !== group) { - if (group !== '') { - html += "
\n"; - } - html += "
\n"; - html += "
" + field.group + "
\n"; - group = field.group; - } - if (field.section && field.section !== section) { - if (section !== '') { - html += "
\n"; - } else { - html += "
\n"; - html += "
\n"; - } - sectionShow = (this.form[field.section + 'Show']) ? " ng-show=\"" + this.form[field.section + 'Show'] + "\"" : ""; - html += "" + field.section + "\n"; - html += "\n"; - section = field.section; - } - - // To hide/show the subform when the value changes on parent - if (field.hasSubForm === true) { - hasSubFormField = fld; - } - - // Add a subform container - if(field.subForm && currentSubForm === undefined) { - currentSubForm = field.subForm; - var subFormTitle = this.form.subFormTitles[field.subForm]; - - html += '
'; - html += ''+ subFormTitle +''; - } - else if (!field.subForm && currentSubForm !== undefined) { - currentSubForm = undefined; - html += '
'; - } - - html += this.buildField(fld, field, options, this.form); - // console.log('*********') - // console.log(html) - - } - } - if (currentSubForm) { - currentSubForm = undefined; - html += '
'; - } - if (section !== '') { - html += "\n\n"; - } - if (group !== '') { - html += "\n"; - } - - html += "\n"; - - //buttons - if ((options.showButtons === undefined || options.showButtons === true) && !this.modal) { - if (this.has('buttons')) { - - html += "
\n"; - } - - for (btn in this.form.buttons) { - if (typeof this.form.buttons[btn] === 'object') { - button = this.form.buttons[btn]; - - // Set default color and label for Save and Reset - if (btn === 'save') { - button.label = i18n._('Save'); - button['class'] = 'Form-saveButton'; - } - if (btn === 'select') { - button.label = i18n._('Select'); - button['class'] = 'Form-saveButton'; - } - if (btn === 'cancel') { - button.label = i18n._('Cancel'); - button['class'] = 'Form-cancelButton'; - } - if (btn === 'close') { - button.label = i18n._('Close'); - button['class'] = 'Form-cancelButton'; - } - if (btn === 'launch') { - button.label = i18n._('Launch'); - button['class'] = 'Form-launchButton'; - } - if (btn === 'add_survey') { - button.label = i18n._('Add Survey'); - button['class'] = 'Form-surveyButton'; - } - if (btn === 'edit_survey') { - button.label = i18n._('Edit Survey'); - button['class'] = 'Form-surveyButton'; - } - if (btn === 'view_survey') { - button.label = i18n._('View Survey'); - button['class'] = 'Form-surveyButton'; - } - if (btn === 'workflow_editor') { - button.label = i18n._('Workflow Editor'); - button['class'] = 'Form-primaryButton'; - } - - // Build button HTML - html += "
\n"; - - if (this.form.horizontal) { - html += "\n"; - } - } - } - - if(!_.isEmpty(this.form.related) && this.mode === "edit"){ - html += ``; - } - - if (this.form.include){ - _.forEach(this.form.include, (template) =>{ - html += `
`; - }); - } - // console.log(html); - return this.wrapPanel(html, options.noPanel); - }, - - buildCollection: function (params) { - // Currently, there are two ways we reference a list definition in a form - // Permissions lists are defined with boilerplate JSON in model.related - // this.GenerateCollection() is shaped around supporting this definition - // Notifications lists contain a reference to the NotificationList object, which contains the list's JSON definition - // However, Notification Lists contain fields that are only rendered by with generateList.build's chain - // @extendme rip out remaining HTML-concat silliness and directivize ¯\_(ツ)_/¯ - this.form = params.form; - var html = '', - collection = this.form.related[params.related]; - - if (collection.generateList) { - html += GenerateList.build({ mode: params.mode, list: collection}); - } - else { - html += this.GenerateCollection({ form: this.form, related: params.related }, {mode: params.mode}); - } - - return html; - }, - - GenerateCollection: function(params, options) { - var html = '', - form = params.form, - itm = params.related, - collection = form.related[itm], - act, fld, cnt, base, fAction, width; - - if (collection.instructions) { - html += "
\n"; - html += "\n"; - html += "Hint: " + collection.instructions + "\n"; - html += "
\n"; - } - - var actionButtons = ""; - Object.keys(collection.actions || {}) - .forEach(act => { - actionButtons += ActionButton(collection - .actions[act]); - }); - var hideOnSuperuser = (hideOnSuperuser === true) ? true : false; - if(actionButtons.length === 0 ){ - // The search bar should be full width if there are no - // action buttons - width = "col-lg-12 col-md-12 col-sm-12 col-xs-12"; - } - else { - width = "col-lg-8 col-md-8 col-sm-8 col-xs-12"; - } - - if(actionButtons.length>0){ - html += `
- ${actionButtons} -
`; - } - - // smart-search directive - html += ` -
- - -
- `; - - - //html += ""; - - // Message for when a search returns no results. This should only get shown after a search is executed with no results. - html += ` -
-
`; - html += i18n._('No records matched your search.'); - html += `
-
- `; - - // Show the "no items" box when loading is done and the user isn't actively searching and there are no results - var emptyListText = (collection.emptyListText) ? collection.emptyListText : i18n._("PLEASE ADD ITEMS TO THIS LIST"); - html += `
`; - html += `
${emptyListText}
`; - html += '
'; - - html += ` -
- System Administrators have access to all ${collection.iterator}s -
- `; - - // Start the list - html += ` -
- - - - `; - html += (collection.index === undefined || collection.index !== false) ? "\n" : ""; - for (fld in collection.fields) { - html += ``; - } - if (collection.fieldActions) { - html += "\n"; - } - html += "\n"; - html += ""; - html += "\n"; - - html += "\n"; - if (collection.index === undefined || collection.index !== false) { - html += "\n"; - } - cnt = 1; - base = (collection.base) ? collection.base : itm; - base = base.replace(/^\//, ''); - for (fld in collection.fields) { - if (!collection.fields[fld].searchOnly) { - cnt++; - html += Column({ - list: collection, - fld: fld, - options: options, - base: base - }); - } - } - - // Row level actions - if (collection.fieldActions) { - html += ""; - html += "\n"; - } - - // Message for loading - html += "\n"; - html += "\n"; - html += "\n"; - - // End List - html += "\n"; - html += "
# - ${collection.fields[fld].label} - Actions
{{ $index + ((" + collection.iterator + "_page - 1) * " + - collection.iterator + "_page_size) + 1 }}.
"; - for (act in collection.fieldActions) { - if (act !== 'columnClass') { - fAction = collection.fieldActions[act]; - html += ""; - } - } - html += "
" + i18n._("Loading...") + "
\n"; - //html += "
\n"; // close well - html += "\n"; // close list-wrapper div - - html += ``; - return html; - }, - }; - - function createCheckbox (options) { - let ngChange = options.ngChange ? `ng-change="${options.ngChange}"` : ''; - let ngDisabled = options.ngDisabled ? `ng-disabled="${options.ngDisabled}"` : ''; - let ngModel = options.ngModel ? `ng-model="${options.ngModel}"` : ''; - let ngShow = options.ngShow ? `ng-show="${options.ngShow}"` : ''; - - return ` - `; - } - } -]); diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js deleted file mode 100644 index de973cff2f63..000000000000 --- a/awx/ui/client/src/shared/generator-helpers.js +++ /dev/null @@ -1,784 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name shared.function:generator-helpers - * @description - * GeneratorHelpers - * - * Functions shared between FormGenerator and ListGenerator - * - */ - import systemStatus from '../smart-status/main'; - - -export default -angular.module('GeneratorHelpers', [systemStatus.name]) - -.factory('Attr', function () { - return function (obj, key, fld) { - var i, s, result, - value = (typeof obj[key] === "string") ? obj[key].replace(/[\'\"]/g, '"') : obj[key]; - - if (/^ng/.test(key)) { - result = 'ng-' + key.replace(/^ng/, '').toLowerCase() + "=\"" + value + "\" "; - } else if (/^data|^aw/.test(key) && key !== 'awPopOver') { - s = ''; - for (i = 0; i < key.length; i++) { - if (/[A-Z]/.test(key.charAt(i))) { - s += '-' + key.charAt(i).toLowerCase(); - } else { - s += key.charAt(i); - } - } - result = s + "=\"" + value + "\" "; - } else { - switch (key) { - // In the cases where we specify trueValue and falseValue, - // the boolean value from the API is getting converted to - // a string. After upgrading to angular 1.4, we need to quote - // the ng-true-value and ng-false-value values so we compare - // them appropriately. - // - case 'trueValue': - result = "ng-true-value=\"'" + value + "'\" "; - break; - case 'falseValue': - result = "ng-false-value=\"'" + value + "'\" "; - break; - case 'awPopOver': - // construct the entire help link - result = "
"; - break; - case 'columnShow': - result = "ng-show=\"" + value + "\" "; - break; - case 'iconName': - result = "icon-name=\"" + value + "\" "; - break; - case 'iconSize': - result = "icon-size=\"" + value + "\" "; - break; - case 'icon': - // new method of constructing icon tag. Replaces Icon method. - result = ""; - break; - case 'autocomplete': - result = "autocomplete=\""; - result += (value) ? 'true' : 'false'; - result += "\" "; - break; - case 'columnClass': - result = 'class="'; - result += value; - result += '"'; - break; - case 'awLookupWhen': - result = "ng-attr-awlookup=\"" + value + "\" "; - break; - default: - result = key + "=\"" + value + "\" "; - } - } - - return result; - - }; -}) - -.factory('Icon', function () { - return function (icon) { - return " "; - }; -}) - -.factory('SelectIcon', ['Icon', - function (Icon) { - return function (params) { - // Common point for matching any type of action to the appropriate - // icon. The intention is to maintain consistent meaning and presentation - // for every icon used in the application. - var icon, - action = params.action, - size = params.size; - switch (action) { - case 'system_tracking': - icon = "fa-crosshairs"; - break; - case 'help': - icon = "fa-question-circle"; - break; - case 'add': - case 'create': - icon = "fa-plus"; - break; - case 'edit': - icon = "fa-pencil"; - break; - case 'delete': - icon = "fa-trash-o"; - break; - case 'group_update': - case 'source_update': - icon = 'fa-refresh'; - break; - case 'inventory_update': - icon = 'fa-refresh'; - break; - case 'scm_update': - icon = 'fa-cloud-download'; - break; - case 'run': - case 'rerun': - case 'submit': - icon = 'icon-launch'; - break; - case 'launch': - icon = 'icon-launch'; - break; - case 'stream': - icon = 'fa-clock-o'; - break; - case 'socket': - icon = 'fa-power-off'; - break; - case 'refresh': - icon = 'fa-refresh'; - break; - case 'close': - icon = 'fa-arrow-left'; - break; - case 'form_submit': - icon = 'fa-check-square-o'; - break; - case 'properties': - icon = "fa-pencil"; - break; - case 'reset': - icon = "fa-undo"; - break; - case 'view': - icon = "fa-search-plus"; - break; - case 'sync_status': - icon = "fa-cloud"; - break; - case 'schedule': - icon = "fa-calendar"; - break; - case 'question_cancel': - icon = 'fa-times'; - break; - case 'job_details': - icon = 'fa-list-ul'; - break; - case 'test': - icon = 'fa-bell-o'; - break; - case 'copy': - icon = "fa-copy"; - break; - case 'insights': - icon = "fa-info"; - break; - case 'network': - icon = "fa-sitemap"; - break; - case 'cancel': - icon = "fa-minus-circle"; - break; - } - icon += (size) ? " " + size : ""; - return Icon(icon); - }; - } -]) - - -.factory('NavigationLink', ['Attr', 'Icon', - function (Attr, Icon) { - return function (link) { - var html = "\n"; - } else { - html = ''; - } - - html += "
\n"; - html += "\n"; - html += "\n"; - html += "
\n"; - html += (params.td === undefined || params.td !== false) ? "\n" : ""; - - return html; - - }; - } -]) - -.factory('BadgeCount', [ - function () { - return function (params) { - // Adds a badge count with optional tooltip - - var list = params.list, - fld = params.fld, - field = list.fields[fld], - html = ''; - html = "\n"; - if (!field.noLink){ - html += ""; - html += "{{ " + list.iterator + '.' + fld + " }}"; - html += ""; - html += (field.badgeLabel) ? " " + field.badgeLabel : ""; - html += "\n"; - html += "\n"; - return html; - }; - } -]) - -.factory('Badge', [ - function () { - return function (field) { - - // Adds an icon(s) with optional tooltip - - var i, html = ''; - - if (field.badges) { - for (i = 0; i < field.badges.length; i++) { - if (field.badges[i].toolTip) { - html += "
"; - if (field.badges[i].toolTip) { - html += ""; - } - html += "\n"; - } - } - else if(field.badgeCustom === true){ - html += field.badgeIcon; - } - else { - if (field.badgeToolTip) { - html += ""; - if (field.badgeToolTip) { - html += ""; - } - html += "\n"; - } - return html; - }; - } -]) - -// List field with multiple icons -.factory('BuildLink', ['Attr', 'Icon', function(Attr, Icon){ - return function(params) { - var html = '', - field = params.field, - list = params.list, - base = params.base, - fld = params.fld; - - if (field.linkTo) { - html += " "; - } else if (field.icon) { - html += Icon(field.icon) + " "; - } - - // Add data binds - if (!field.ngBindHtml && !field.iconOnly && !field.ngEllipsis && (field.showValue === undefined || field.showValue === true)) { - if (field.ngBind) { - html += "{{ " + field.ngBind; - } else { - html += "{{" + list.iterator + "." + fld; - } - if (field.filter) { - html += " | " + field.filter + " }}"; - } - else { - html += " }}"; - } - } - - // Add additional text: - if (field.text) { - html += field.text; - } - html += ""; - if (field.alt_text) { - html += "  " + field.alt_text; - } - return html; - }; -}]) - -.factory('Template', ['Attr', function(Attr) { - return function(field) { - var ngClass = (field.ngClass) ? Attr(field, 'ngClass') : null; - var classList = (field.columnClass) ? Attr(field, 'columnClass') : null; - var ngInclude = (field.ngInclude) ? Attr(field, 'ngInclude') : null; - var attrs = _.compact([ngClass, classList, ngInclude]); - - return ''; - }; -}]) - -.factory('Column', ['i18n', 'Attr', 'Icon', 'DropDown', 'Badge', 'BadgeCount', 'BuildLink', 'Template', - function (i18n, Attr, Icon, DropDown, Badge, BadgeCount, BuildLink, Template) { - return function (params) { - var list = params.list, - fld = params.fld, - options = params.options, - base = params.base, - field = list.fields[fld], - html = '', - classList; - - if (field.type !== undefined && field.type === 'DropDown') { - html = DropDown(params); - } else if (field.type === 'role') { - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - - - `; - } else if (field.type === 'team_roles') { - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - - - `; - } else if (field.type === 'labels') { - let showDelete = field.showDelete === undefined ? true : field.showDelete; - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - - - `; - } else if (field.type === 'related_groups') { - let showDelete = field.showDelete === undefined ? true : field.showDelete; - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - - - `; - } else if (field.type === 'owners') { - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - - `; - } else if (field.type === 'revision') { - classList = (field.columnClass) ? - Attr(field, 'columnClass') : ""; - html += ` - - - `; - } else if (field.type === 'badgeCount') { - html = BadgeCount(params); - } else if (field.type === 'badgeOnly') { - html = Badge(field); - } else if (field.type === 'template') { - html = Template(field); - } else if (field.type === 'toggle') { - html += "
"; - } else if (field.type === 'invalid') { - html += `
`; - html += ""; - html += "
"; - } else { - html += "" : ""; - - //Add ngHide - //html += (field.ngHide) ? "" : ""; - - // Badge - if (options.mode !== 'lookup' && (field.badges || (field.badgeIcon && field.badgePlacement && field.badgePlacement === 'left'))) { - html += Badge(field); - } - - // Add collapse/expand icon --used on job_events page - if (list.hasChildren && field.hasChildren) { - html += ""; - } - - if (list.name === 'groups') { - html += "
"; - } - if (list.name === 'hosts') { - html += "
"; - } - - // Start the Link - if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref || field.uiSref || field.awToolTip || field.awPopOver) && - options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) { - if(field.noLink === true){ - // provide an override here in case we want key=true for sorting purposes but don't want links -- see: portal mode, - } - else if (field.icons) { - field.icons.forEach(function(icon, idx) { - var key, i = field.icons[idx]; - for (key in i) { - field[key] = i[key]; - } - html += BuildLink({ - list: list, - field: field, - fld: fld, - base: field.linkBase || base - }) + ' '; - }); - } - else if(field.smartStatus){ - html += ''; - } - else { - html += BuildLink({ - list: list, - field: field, - fld: fld, - base: field.linkBase || base - }); - } - } - else { - if(field.simpleTip) { - html += ``; - } - // Add icon: - if (field.ngShowIcon) { - html += " "; - } else if (field.icon) { - html += Icon(field.icon) + " "; - } - // Add data binds - if (!field.ngBindHtml && !field.iconOnly && (field.showValue === undefined || field.showValue === true)) { - if (field.ngBind) { - html += "{{ " + field.ngBind; - } else { - html += "{{ " + list.iterator + "." + fld; - } - if (field.filter) { - html += " | " + field.filter + " }}"; - } - else { - html += " }}"; - } - } - // Add additional text: - if (field.text) { - html += field.text; - } - if(field.simpleTip) { - html += ``; - } - } - - if (list.name === 'hosts' || list.name === 'groups') { - html += "
"; - } - - // close ngShow - html += (field.ngShow) ? "" : ""; - - //close ngHide - //html += (field.ngHide) ? "" : ""; - - // Specific to Job Events page -showing event detail/results - html += (field.appendHTML) ? "
\n" : ""; - - // Badge - if (options.mode !== 'lookup' && field.badgeIcon && field.badgePlacement && field.badgePlacement !== 'left') { - html += Badge(field); - } - } - - } - return html += "\n"; - }; - } -]) - -.factory('HelpCollapse', function () { - return function (params) { - - var hdr = params.hdr, - content = params.content, - show = params.show, - ngHide = params.ngHide, - idx = params.idx, - bind = params.bind, - html = ''; - - html += "
\n"; - html += "
\n"; - html += "

\n"; - //html += " " + hdr; - html += hdr; - html += ""; - html += "

\n"; - html += "
\n"; - html += "
\n"; - html += "
- - ${messageBar.message} -
`; - } - return html; - }; -}); diff --git a/awx/ui/client/src/shared/icon/icon.block.less b/awx/ui/client/src/shared/icon/icon.block.less deleted file mode 100644 index 5cff28b209a1..000000000000 --- a/awx/ui/client/src/shared/icon/icon.block.less +++ /dev/null @@ -1,7 +0,0 @@ -/** @define Icon */ - -.Icon { - path, g { - fill: #242424; - } -} diff --git a/awx/ui/client/src/shared/icon/icon.directive.js b/awx/ui/client/src/shared/icon/icon.directive.js deleted file mode 100644 index c38abc7698c0..000000000000 --- a/awx/ui/client/src/shared/icon/icon.directive.js +++ /dev/null @@ -1,46 +0,0 @@ -export default - [ 'templateUrl', - '$rootScope', - function(templateUrl, $rootScope) { - return { - restrict: 'E', - templateUrl: templateUrl('shared/icon/icon'), - scope: { - }, - link: function(scope, element, attrs) { - - function buildSvgs() { - var svg = $('svg', element); - var iconPath = '#' + attrs.name; - - if ($(iconPath).length === 0) { - return; - } - - // Make a copy of the tag to insert its contents into this - // element's svg tag - var content = $(iconPath).clone(); - - // Copy classes & viewBox off the so that we preserve any styling - // when we copy the item inline - var classes = $(iconPath).attr('class'); - - // viewBox needs to be access via native - // javascript's setAttribute function - var viewBox = $(iconPath)[0].getAttribute('viewBox'); - - svg[0].setAttribute('viewBox', viewBox); - svg.attr('class', classes) - .html(content.contents()); - } - - $rootScope.$on('include-svg.svg-ready', function() { - buildSvgs(); - }); - - buildSvgs(); - - } - }; - } - ]; diff --git a/awx/ui/client/src/shared/icon/icon.partial.html b/awx/ui/client/src/shared/icon/icon.partial.html deleted file mode 100644 index 7640e25707ab..000000000000 --- a/awx/ui/client/src/shared/icon/icon.partial.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/awx/ui/client/src/shared/icon/include-svg.directive.js b/awx/ui/client/src/shared/icon/include-svg.directive.js deleted file mode 100644 index dcfa55f0456d..000000000000 --- a/awx/ui/client/src/shared/icon/include-svg.directive.js +++ /dev/null @@ -1,13 +0,0 @@ -export default ['$http', '$rootScope', function($http, $rootScope) { - return { - restrict: 'E', - link: function(scope, element, attrs) { - var path = attrs.href; - - $http.get(path).then(function(response) { - element.append(response.data); - $rootScope.$emit('include-svg.svg-ready'); - }); - } - }; -}]; diff --git a/awx/ui/client/src/shared/icon/main.js b/awx/ui/client/src/shared/icon/main.js deleted file mode 100644 index 87c8a0d474b7..000000000000 --- a/awx/ui/client/src/shared/icon/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import icon from './icon.directive'; -//import includeSvg from './include-svg.directive'; - -export default - angular.module('awIcon', []) - .directive('awIcon', icon); - //.directive('includeSvg', includeSvg); diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js deleted file mode 100644 index b28a6681c0e5..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js +++ /dev/null @@ -1,127 +0,0 @@ -export default ['templateUrl', '$window', function(templateUrl, $window) { - return { - restrict: 'E', - scope: { - instanceGroups: '=' - }, - templateUrl: templateUrl('shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal'), - - link: function(scope, element) { - - $('#instance-groups-modal').on('hidden.bs.modal', function () { - $('#instance-groups-modal').off('hidden.bs.modal'); - $(element).remove(); - }); - - scope.showModal = function() { - $('#instance-groups-modal').modal('show'); - }; - - scope.destroyModal = function() { - $('#instance-groups-modal').modal('hide'); - }; - }, - - controller: ['$scope', '$compile', 'QuerySet', 'GetBasePath','generateList', 'InstanceGroupList', function($scope, $compile, qs, GetBasePath, GenerateList, InstanceGroupList) { - - function init() { - - $scope.instance_group_queryset = { - order_by: 'name', - page_size: 5 - }; - - $scope.instance_group_default_params = { - order_by: 'name', - page_size: 5 - }; - - qs.search(GetBasePath('instance_groups'), $scope.instance_group_queryset) - .then(res => { - $scope.instance_group_dataset = res.data; - $scope.instance_groups = $scope.instance_group_dataset.results; - - let instanceGroupList = _.cloneDeep(InstanceGroupList); - - instanceGroupList.listTitle = false; - instanceGroupList.well = false; - instanceGroupList.multiSelect = true; - instanceGroupList.multiSelectPreview = { - selectedRows: 'igTags', - availableRows: 'instance_groups' - }; - instanceGroupList.fields.name.ngClick = "linkoutInstanceGroup(instance_group)"; - instanceGroupList.fields.name.columnClass = 'col-md-11 col-sm-11 col-xs-11'; - delete instanceGroupList.fields.consumed_capacity; - delete instanceGroupList.fields.jobs_running; - - let html = `${GenerateList.build({ - list: instanceGroupList, - input_type: 'instance-groups-modal-body', - hideViewPerPage: true - })}`; - - $scope.list = instanceGroupList; - $('#instance-groups-modal-body').append($compile(html)($scope)); - - if ($scope.instanceGroups) { - $scope.instance_groups.map( (item) => { - isSelected(item); - }); - } - - $scope.showModal(); - }); - - $scope.$watch('instance_groups', function(){ - angular.forEach($scope.instance_groups, function(instanceGroupRow) { - angular.forEach($scope.igTags, function(selectedInstanceGroup){ - if(selectedInstanceGroup.id === instanceGroupRow.id) { - instanceGroupRow.isSelected = true; - } - }); - }); - }); - - } - - init(); - - function isSelected(item) { - if(_.find($scope.instanceGroups, {id: item.id})){ - item.isSelected = true; - if (!$scope.igTags) { - $scope.igTags = []; - } - $scope.igTags.push(item); - } - return item; - } - - $scope.$on("selectedOrDeselected", function(e, value) { - let item = value.value; - if (value.isSelected) { - if(!$scope.igTags) { - $scope.igTags = []; - } - $scope.igTags.push(item); - } else { - _.remove($scope.igTags, { id: item.id }); - } - }); - - $scope.linkoutInstanceGroup = function(instanceGroup) { - $window.open('/#/instance_groups/' + instanceGroup.id + '/instances','_blank'); - }; - - $scope.cancelForm = function() { - $scope.destroyModal(); - }; - - $scope.saveForm = function() { - $scope.instanceGroups = $scope.igTags; - $scope.destroyModal(); - }; - }] - }; -}]; diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html deleted file mode 100644 index c61af3ab8ba6..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-multiselect.controller.js b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-multiselect.controller.js deleted file mode 100644 index 91b7795a1fc1..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-multiselect.controller.js +++ /dev/null @@ -1,14 +0,0 @@ -export default ['$scope', - function($scope) { - - $scope.instanceGroupsTags = []; - - $scope.$watch('instanceGroups', function() { - $scope.instanceGroupsTags = $scope.instanceGroups; - }, true); - - $scope.deleteTag = function(tag){ - _.remove($scope.instanceGroups, {id: tag.id}); - }; - } -]; \ No newline at end of file diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less deleted file mode 100644 index bbfef9de99ee..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less +++ /dev/null @@ -1,15 +0,0 @@ -#instance-groups-panel { - table { - overflow: hidden; - } - .List-header { - margin-bottom: 20px; - } - .isActive { - border-left: 10px solid @list-row-select-bord; - } - .instances-list, - .instance-jobs-list { - margin-top: 20px; - } -} diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.directive.js b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.directive.js deleted file mode 100644 index cdb781b1d9c1..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.directive.js +++ /dev/null @@ -1,19 +0,0 @@ -import instanceGroupsMultiselectController from './instance-groups-multiselect.controller'; -export default ['templateUrl', '$compile', - function(templateUrl, $compile) { - return { - scope: { - instanceGroups: '=', - fieldIsDisabled: '=' - }, - restrict: 'E', - templateUrl: templateUrl('shared/instance-groups-multiselect/instance-groups'), - controller: instanceGroupsMultiselectController, - link: function(scope) { - scope.openInstanceGroupsModal = function() { - $('#content-container').append($compile('')(scope)); - }; - } - }; - } -]; diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html deleted file mode 100644 index df82cf5d856b..000000000000 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html +++ /dev/null @@ -1,20 +0,0 @@ -
- - - - -
-
- {{ tag.name }} -
-
- -
-
-
-
diff --git a/awx/ui/client/src/shared/layouts/one-plus-one.less b/awx/ui/client/src/shared/layouts/one-plus-one.less deleted file mode 100644 index cc6a0982045c..000000000000 --- a/awx/ui/client/src/shared/layouts/one-plus-one.less +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Large resolution 1/2 + 1/2 width panels -* Small resolution: 100% width panels, stacked -* Options: static height, custom breakpoint -*/ - -.OnePlusOne-container(@height: 100%; @breakpoint: 900px){ - height: ~"calc(100vh - 150px)"; - display: flex; - flex-direction: row; - @media screen and(max-width: @breakpoint){ - flex-direction: column; - height: 100%; - } -} - -.OnePlusOne-panel--left(@height: 100%; @breakpoint: 900px){ - flex: 1 1; - height: @height; - width: 100%; - max-width: 50%; - margin-right: 20px; - .Panel{ - height: 100%; - } - @media screen and (max-width: @breakpoint){ - max-width: 100%; - margin-right: 0px; - height: inherit; - } -} - -.OnePlusOne-panel--right(@height: 100%; @breakpoint: 900px){ - flex: 1 1; - height: @height; - width: 100%; - max-width: 50%; - margin-right: 0px; - .Panel{ - height: 100%; - } - @media screen and (max-width: @breakpoint) { - max-width: 100%; - height: inherit; - } -} - -.OnePlusOne-panelHeader{ - color: @default-interface-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - display: flex; -} diff --git a/awx/ui/client/src/shared/layouts/one-plus-two.less b/awx/ui/client/src/shared/layouts/one-plus-two.less deleted file mode 100644 index c0cde59bcd28..000000000000 --- a/awx/ui/client/src/shared/layouts/one-plus-two.less +++ /dev/null @@ -1,73 +0,0 @@ -/* -* Large resolution: 1/3 + 2/3 width panels -* Small resolution: 100% width panels, stacked -* Options: static height, custom breakpoint -* -* Style conventions -* .ModuleName-component--subComponent -*/ - -.OnePlusTwo-container(@height: 100%; @breakpoint: 900px){ - height: @height; - display: flex; - flex-direction: row; - @media screen and (max-width: @breakpoint){ - flex-direction: column; - } -} - -.OnePlusTwo-left--panel(@height: 100%; @breakpoint: 900px) { - flex: 1 0; - height: @height; - width: 100%; - margin-right: 20px; - .Panel{ - height: 100%; - } - @media screen and (max-width: @breakpoint){ - margin-right: 0px; - height: inherit; - } -} - -.OnePlusTwo-right--panel(@height: 100%; @breakpoint: 900px) { - height: @height; - flex: 2 0; - .Panel{ - height: 100%; - } - @media screen and (max-width: @breakpoint){ - flex-direction: column; - } -} - -.OnePlusTwo-panelHeader { - color: @default-interface-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - display: flex; -} - -.OnePlusTwo-left--details { - margin-top: 25px; -} - -.OnePlusTwo-left--detailsRow { - display: flex; -} - -.OnePlusTwo-left--detailsLabel { - word-wrap: break-word; - width: 170px; - display: inline-block; - color: @default-interface-txt; - text-transform: uppercase; - font-weight: 400; -} - -.OnePlusTwo-left--detailsContent { - display: inline-block; - width: 220px; - word-wrap: break-word; -} diff --git a/awx/ui/client/src/shared/limit-panels/limit-panels.directive.js b/awx/ui/client/src/shared/limit-panels/limit-panels.directive.js deleted file mode 100644 index 2471a1cf2961..000000000000 --- a/awx/ui/client/src/shared/limit-panels/limit-panels.directive.js +++ /dev/null @@ -1,34 +0,0 @@ -export default [function() { - return { - restrict: 'E', - scope: { - maxPanels: '@', - panelContainer: '@' - }, - link: function(scope) { - - const maxPanels = parseInt(scope.maxPanels); - - scope.$watch( - () => angular.element('#' + scope.panelContainer).find('.Panel').length, - () => { - const panels = angular.element('#' + scope.panelContainer).find('.Panel'); - if(panels.length > maxPanels) { - // hide the excess panels - $(panels).each(function( index ) { - if(index+1 > maxPanels) { - $(this).addClass('Panel-hidden'); - } - else { - $(this).removeClass('Panel-hidden'); - } - }); - } else { - // show all the panels - $(panels).removeClass('Panel-hidden'); - } - } - ); - } - }; -}]; diff --git a/awx/ui/client/src/shared/limit-panels/main.js b/awx/ui/client/src/shared/limit-panels/main.js deleted file mode 100644 index 407cb09a95eb..000000000000 --- a/awx/ui/client/src/shared/limit-panels/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import directive from './limit-panels.directive'; - -export default - angular.module('LimitPanelsModule', []) - .directive('awLimitPanels', directive); diff --git a/awx/ui/client/src/shared/list-generator/list-actions.partial.html b/awx/ui/client/src/shared/list-generator/list-actions.partial.html deleted file mode 100644 index 7581e3195d45..000000000000 --- a/awx/ui/client/src/shared/list-generator/list-actions.partial.html +++ /dev/null @@ -1,78 +0,0 @@ - -
-
-
- - - -
- - - -
- -
- - -
- - - -
- -
- diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js deleted file mode 100644 index a1f708876976..000000000000 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ /dev/null @@ -1,604 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name shared.function:list-generator - * @description - * #ListGenerator - * - * Use GenerateList.inject(list_object, { key:value }) to generate HTML from a list object and inject it into the DOM. Returns the $scope of the new list. - * - * Pass in a list object and a JSON object of key:value parameters. List objects are found in lists/*.js. Possible parameters include: - * - * | Parameter | Required | Description | - * | --------- | -------- | ----------- | - * | activityStream | | Used in widgets/stream.js to create the list contained within the activity stream widget. | - * | hdr | | Deprecated. Was used when list generator created the lookup dialog. This was moved to helpers/Lookup.js. | - * | id | | DOM element ID attribute value. Use to inject the list into a custom DOM element. Otherwise, the HTML for a list will be injected into the DOM element with an ID attribute of 'htmlTemplate'. | - * | listSize | | Bootstrap size class to apply to the grid column containing the action buttons, which generally appears to the right of the search widget. Defaults to 'col-lg-8 col-md-6 col-sm-4 col-xs-3'. | - * | mode | Yes | One of 'edit', 'lookup', 'select', or 'summary'. Generally this will be 'edit'. helpers/Lookup.js uses 'lookup' to generate the lookup dialog. The 'select' option is used in certain controllers when multiple objects are being added to a parent object. For example, building a select list of Users that can be added to an Oranization. 'summary' is no longer used. | - * | scope | | If the HTML will be injected into the DOM by list generator, pass in an optional $scope to be used in conjuction with $compile. The list will be associated with the scope value. Otherwise, the scope of the DOM element will be fetched passed to $compile. | - * | showSearch | | true or false. Set to false, if the search widget should not be included in the generated HTML. | - * - * #HTML only - * - * Use the buildHTML() method to get a string containing the generated HTML for a list object. buldHTML() expects the same parameters as the inject method. For example: - * ``` - * var html = GenerateList.buildHTML({ - * mode: 'edit', - * showSearch: false - * }); - * ``` - * - * #List Objects - * - * List objects are found in lists/*.js. Any API endpoint that returns a collection or array is represented with a list object. Examples inlcude Organizations, Credentials, Inventories, etc. - * A list can have the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | index | true or false. If false, the index column, which adds a sequential number to each table row starting with 1, will not be added to the table. | - * | iterator | String containing a descriptive name of a single row in the collection - inventory, organization, credential, etc. Used to generate name and ID attributes in the list HTML. | - * | name | Name of the collection. Generally matches the endpoint name - inventories, organizations, etc. Will match the $scope variable containing the array of rows comprising the collection. | - * | selectTitle | Descriptive title used when mode is 'select'. | - * | selectInstructions | Text and HTML used to create popover for help button when mode is 'select'. | - * | editTitle | Descriptive title used when mode is 'edit'. | - * - * ##Fields - * - * A list contains a fields object. Each column in the list is defined as a separate object within the fields object. A field definition may contain the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | columnClass | String of CSS class names to add to the <td> elemnts of the table column. | - * | columnClick | Adds an ng-click directive to the <td> element. | - * | excludeModal | true or false. If false, the field will not be included in the generated HTML when the mode is 'lookup' | - * | key | true or false. If set to true, helpers/search.js will use the field name as the default sort order when generating the API request. | - * | noLink | true or false. If set to true this will override any 'key', 'linkTo', 'ngClick', or other option that would cause the field to be a link. Used in portal mode and custom inv. script. | - * | label | Text string used as the column header text. | - * | linkTo | Wraps the field value with an <a> element. Set to the value of the href attribute. | - * | ngClick | Wraps the field value with an <a> and adds the ng-click directive. Set to the JS expression that ng-click will evaluate. | - * | nosort | true or false. Setting to false removes the ability to sort the table by the column. | - * | searchOnly | true or false. Set to true if the field should be included in the search widget but not included as a column in the generated HTML <table>. | - * | searchOptions | Array of { name: 'Descriptive Name', value: 'api_value' } objects used to generate <options> for the <select> when searchType is 'select'. | - * | searchType | One of the available search types defined in helpers/search.js. | - * | sourceField | Name of the attribute within summary_fields. that the field maps to in the API response object. Used in conjunction with sourceModel. | - * | sourceModel | Name of the summary_fields object that the field maps to in the API response object. | - * - * ##Field Actions - * - * A list contains a fieldActions object. Each icon found in the Actions column is defined as an object within the fieldActions object. fieldActions can have a columnClass attribute, - * which may contain a string of CSS class names to add to the action <td> element. It may also contain a label attribute, which can be set to false to suppress the Actions column header. - * - * Field action items can have the following attributes: - * - * | Attribute | Description | - * | --------- | ----------- | - * | actionclass | Set to a string containing any CSS classes to add to the button. | - * | awToolTip | Adds the aw-tool-tip directive. Set to the value of the HTML or text to dislay in the tooltip. | - * | buttonContent | String containing button content. HTML is accepted in this string. | - * | dataPlacement | Set to the Bootstrip tooltip placement - right, left, top, bottom, etc. | - * | dataTipWatch | Set to the $scope variable that contains the text and HTML to display in the tooltip. A $scope.$watch will be added to the variable so that anytime its value changes the tooltip will change. | - * | mode | One of 'all' or 'edit'. Will generally be 'all'. Note that field actions are not displayed when the list is in 'lookup' mode. | - * | ngClass | Adds the ng-class directive. Set to the JS expression that ng-class will evaluate. | - * | ngShow | Adds the ng-show directive. Set to the JS expression that ng-show will evaluate. | - * - * ##Actions - * - * A list can contain an actions object. The actions object contains an object for each action button displayed in the top-right corner of the list container. An action can have the same - * attributes as an action defined in fieldAction. Both are actions. Clicking on an action evaluates the JS found in the ngClick attribute. In both cases icon is generated automatically by the SelectIcon() method in js/shared/generator-helpers.js. - * The real difference is that an <a> element is used to generate fieldAction items while a <button> element is used for action items. - */ - -import { templateUrl } from '../../shared/template-url/template-url.factory'; - -export default ['$compile', 'Attr', 'Icon', - 'Column', 'DropDown', 'SelectIcon', 'ActionButton', 'i18n', - function($compile, Attr, Icon, Column, DropDown, - SelectIcon, ActionButton, i18n) { - return { - - setList: function(list) { - this.list = list; - }, - - setOptions: function(options) { - this.options = options; - }, - - attr: Attr, - - icon: Icon, - - has: function(key) { - return (this.form[key] && this.form[key] !== null && this.form[key] !== undefined) ? true : false; - }, - - buildHTML: function(list, options) { - this.setList(list); - return this.build(options); - }, - - build: function(options) { - this.list = options.list; - this.options = options; - - var html = '', - list = this.list, - base, action, fld, cnt, field_action, fAction, itm; - - if (options.mode !== 'lookup') { - // Don't display an empty
if there is no listTitle - if ((options.title !== false && list.title !== false) && list.listTitle !== undefined) { - html += "
"; - html += "
"; - if (list.listTitle && options.listTitle !== false) { - html += "
" + list.listTitle + "
"; - // We want to show the list title badge by default and only hide it when the list config specifically passes a false flag - list.listTitleBadge = (typeof list.listTitleBadge === 'boolean' && list.listTitleBadge === false) ? false : true; - if (list.listTitleBadge) { - html += `{{ ${list.iterator}_dataset.count }}`; - } - } - html += "
"; - if (options.cancelButton === true) { - html += "
"; - html += "
\n"; - } - html += "
"; - } - } - - if (options.mode === 'edit' && list.editInstructions) { - html += "
\n"; - html += "\n"; - html += "Hint: " + list.editInstructions + "\n"; - html += "
\n"; - } - - if (list.multiSelectPreview) { - html += ""; - } - - if (options.instructions) { - html += "
" + options.instructions + "
\n"; - } else if (list.instructions) { - html += "
" + list.instructions + "
\n"; - } - - if (options.mode !== 'lookup' && (list.well === undefined || list.well)) { - html += `
`; - html += (!list.wellOverride) ? "List-well" : ""; - html += `">`; - // List actions - html += "
"; - html += "
"; - html += `
`; - - for (action in list.actions) { - list.actions[action] = _.defaults(list.actions[action], { dataPlacement: "top" }); - } - - html += "
"; - if (list.toolbarAuxAction) { - html += `
${list.toolbarAuxAction}
`; - } - html += "\n
"; - html += "
"; - // End list actions - } - - html += (list.searchRowActions) ? "
" : ""; - if (options.showSearch === undefined || options.showSearch === true) { - let singleSearchParam = list.singleSearchParam && list.singleSearchParam.param ? `single-search-param="${list.singleSearchParam.param}"` : ''; - html += ` -
- - -
- `; - } - if (list.searchRowActions) { - html += "
"; - - var actionButtons = ""; - Object.keys(list.searchRowActions || {}) - .forEach(act => { - actionButtons += ActionButton(list.searchRowActions[act]); - }); - html += ` -
- ${actionButtons} -
- `; - html += "
"; - } - - if (options.showSearch !== false) { - // Message for when a search returns no results. This should only get shown after a search is executed with no results. - html +=` -
-
No records matched your search.
-
- `; - } - - // Show the "no items" box when loading is done and the user isn't actively searching and there are no results - if (options.showEmptyPanel === undefined || options.showEmptyPanel === true){ - html += `
`; - html += (list.emptyListText) ? list.emptyListText : i18n._("PLEASE ADD ITEMS TO THIS LIST"); - html += "
"; - } - - // Add a title and optionally a close button (used on Inventory->Groups) - if (options.mode !== 'lookup' && list.showTitle) { - html += "
"; - html += (options.mode === 'edit' || options.mode === 'summary') ? list.editTitle : list.addTitle; - html += "
\n"; - } - - // table header row - html += "
0\""; - html += (list.awCustomScroll) ? " aw-custom-scroll " : ""; - html += ">\n"; - - function buildTable() { - var extraClasses = list['class']; - var multiSelect = list.multiSelect ? 'multi-select-list' : null; - var multiSelectExtended = list.multiSelectExtended ? 'true' : 'false'; - - if (options.mode === 'summary') { - extraClasses += ' table-summary'; - } - - return $('') - .attr('id', list.name + '_table') - .addClass('List-table') - .addClass(extraClasses) - .attr('multi-select-list', multiSelect) - .attr('is-extended', multiSelectExtended); - - } - - var table = buildTable(); - var innerTable = ''; - - if (!options.skipTableHead) { - innerTable += this.buildHeader(options); - } - - // table body - // gotcha: transcluded elements require custom scope linking - binding to $parent models assumes a very rigid DOM hierarchy - // see: lookup-modal.directive.js for example - innerTable += options.mode === 'lookup' ? `` : `"\n"`; - innerTable += "\n"; - - if (list.index) { - innerTable += "\n"; - } - - if (list.multiSelect) { - innerTable += ''; - } - - // Change layout if a lookup list, place radio buttons before labels - if (options.mode === 'lookup') { - if (options.input_type === "radio") { //added by JT so that lookup forms can be either radio inputs or check box inputs - innerTable += ``; - } - else { // its assumed that options.input_type = checkbox - innerTable += ""; - } - } - - cnt = 2; - base = (list.base) ? list.base : list.name; - base = base.replace(/^\//, ''); - for (fld in list.fields) { - cnt++; - if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) && - !(options.mode === 'lookup' && list.fields[fld].excludeModal === true)) { - innerTable += Column({ - list: list, - fld: fld, - options: options, - base: base - }); - } - } - - if (options.mode === 'select') { - if (options.input_type === "radio") { //added by JT so that lookup forms can be either radio inputs or check box inputs - innerTable += ""; - } else { // its assumed that options.input_type = checkbox - innerTable += ""; - } - } else if ((options.mode === 'edit' || options.mode === 'summary') && list.fieldActions) { - - // Row level actions - - innerTable += "\n"; - } - - innerTable += "\n"; - // End List - innerTable += "\n"; - - table.html(innerTable); - html += table.prop('outerHTML'); - - html += "\n"; - - if (options.mode === 'select' && (options.selectButton === undefined || options.selectButton)) { - html += "
\n"; - html += " \n"; - html += "
\n"; - } - - if (options.paginate === undefined || options.paginate === true) { - let hide_view_per_page = (options.mode === "lookup" || options.hideViewPerPage) ? true : false; - html += ``; - } - - return html; - }, - - buildHeader: function(options) { - var list = this.list, - fld, html; - - function buildSelectAll() { - return $('\n"; - html += "\n"; - if (list.index) { - html += "\n"; - } - - if (list.multiSelect) { - html += buildSelectAll().prop('outerHTML'); - } else if (options.mode === 'lookup') { - html += ""; - } - - if (options.mode !== 'lookup'){ - for (fld in list.fields) { - let customClass = list.fields[fld].columnClass || ''; - html += ``; - } - } - if (options.mode === 'lookup') { - let customClass = list.fields.name.modalColumnClass || ''; - html += ``; - - if(list.fields.info) { - customClass = list.fields.name.modalColumnClass || ''; - const infoHeaderClass = _.get(list.fields.info, 'infoHeaderClass', 'List-tableHeader--info'); - html += ``; - } - } - if (options.mode === 'select') { - html += ""; - } else if (options.mode === 'edit' && list.fieldActions) { - html += "\n"; - } - html += "\n"; - html += "\n"; - return html; - }, - - wrapPanel: function(html){ - return ` -
${html}
`; - }, - - insertFormView: function(){ - return `
`; - }, - - insertSchedulerView: function(){ - return `
`; - } - }; - } -]; diff --git a/awx/ui/client/src/shared/list-generator/main.js b/awx/ui/client/src/shared/list-generator/main.js deleted file mode 100644 index 488179a1bfb8..000000000000 --- a/awx/ui/client/src/shared/list-generator/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import generateList from './list-generator.factory'; -import toolbarButton from './toolbar-button.directive'; -import generatorHelpers from '../generator-helpers'; -import multiSelectList from '../multi-select-list/main'; - -export default - angular.module('listGenerator', [generatorHelpers.name, multiSelectList.name]) - .factory('generateList', generateList) - .directive('toolbarButton', toolbarButton); diff --git a/awx/ui/client/src/shared/list-generator/toolbar-button.directive.js b/awx/ui/client/src/shared/list-generator/toolbar-button.directive.js deleted file mode 100644 index fb9402212c96..000000000000 --- a/awx/ui/client/src/shared/list-generator/toolbar-button.directive.js +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['SelectIcon', function(SelectIcon) { - return { - restrict: 'A', - scope: {}, - link: function(scope, element, attrs) { - - var toolbar = attrs.toolbar; - - if (toolbar) { - //if this is a toolbar button, set some defaults - attrs.class = 'btn-xs btn-primary'; - attrs.iconSize = 'fa-lg'; - } - - element.addClass('btn'); - - // If no class specified, default - // to btn-sm - if (_.isEmpty(attrs.class)) { - element.addClass("btn-sm"); - } else { - element.addClass(attrs.class); - } - - if (attrs.awPopOver) { - element.addClass("help-link-white"); - } - - if (attrs.iconName && _.isEmpty(attrs.id)) { - element.attr("id",attrs.iconName + "_btn"); - } - - if (!_.isEmpty(attrs.img)) { - $("") - .attr("src", $basePath + "assets/" + attrs.img) - .css({ width: "12px", height: "12px" }) - .appendTo(element); - } - - if (!_.isEmpty(attrs.iconClass)) { - $("") - .addClass(attrs.iconClass) - .appendTo(element); - } - else { - var icon = SelectIcon({ - action: attrs.iconName, - size: attrs.iconSize - }); - - $(icon).appendTo(element); - } - - if (!toolbar && !_.isEmpty(attrs.label)) { - element.text(attrs.label); - } - - } - }; -}]; diff --git a/awx/ui/client/src/shared/load-config/load-config.factory.js b/awx/ui/client/src/shared/load-config/load-config.factory.js deleted file mode 100644 index ca12f1739be6..000000000000 --- a/awx/ui/client/src/shared/load-config/load-config.factory.js +++ /dev/null @@ -1,55 +0,0 @@ -export default - function LoadConfig($log, $rootScope, $http, Store) { - return function() { - - - var configSettings = {}; - - var configInit = function() { - // Auto-resolving what used to be found when attempting to load local_setting.json - if ($rootScope.loginConfig) { - $rootScope.loginConfig.resolve('config loaded'); - } - $rootScope.$emit('ConfigReady'); - - // Load new hardcoded settings from above - - global.$AnsibleConfig = configSettings; - Store('AnsibleConfig', global.$AnsibleConfig); - $rootScope.$emit('LoadConfig'); - }; - - // Retrieve the custom logo information - update configSettings from above - $http({ - method: 'GET', - url: '/api/', - }) - .then(function({data}) { - if(data.custom_logo) { - configSettings.custom_logo = true; - $rootScope.custom_logo = data.custom_logo; - } else { - configSettings.custom_logo = false; - } - - if(data.custom_login_info) { - configSettings.custom_login_info = data.custom_login_info; - $rootScope.custom_login_info = data.custom_login_info; - } else { - configSettings.custom_login_info = false; - } - - configInit(); - - }).catch(({error}) => { - $log.debug(error); - configInit(); - }); - - }; - } - -LoadConfig.$inject = - [ '$log', '$rootScope', '$http', - 'Store' - ]; diff --git a/awx/ui/client/src/shared/load-config/main.js b/awx/ui/client/src/shared/load-config/main.js deleted file mode 100644 index 3accf42ffaa5..000000000000 --- a/awx/ui/client/src/shared/load-config/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import LoadConfig from './load-config.factory'; - -export default - angular.module('loadconfig', []) - .factory('LoadConfig', LoadConfig); diff --git a/awx/ui/client/src/shared/lodash-as-promised.js b/awx/ui/client/src/shared/lodash-as-promised.js deleted file mode 100644 index 039a3a98fd25..000000000000 --- a/awx/ui/client/src/shared/lodash-as-promised.js +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -function lodashAsPromised($q) { - - var lodash = _.runInContext(); - var _aw = {}; - var toExtend = - [ 'map', - 'filter', - 'reduce', - 'pluck', - 'compact', - 'xor', - 'groupBy', - 'thru' - ]; - - function log(label, obj) { - /* jshint ignore:start */ - console.log(label, obj); - /* jshint ignore:end */ - return obj; - } - - function _reject(reason) { - return $q.reject(reason); - } - - function _promise(value) { - return $q.when(value); - } - - function _then(promise, fn) { - return promise.then(function(value) { - if (_.isFunction(value.then)) { - return _then(value, fn); - } else { - return fn(value); - } - }); - } - - function _catch(promise, fn) { - return promise.catch(fn); - } - - function _finally(promise, fn) { - return promise.finally(fn); - } - - function thenAll(arr, then, deep) { - var doAll = function (arr) { - var promise = $q.all(arr).then(function (resolvedArr) { - if (deep) { - return lodash(resolvedArr) - .thenMap(function (elem) { - if (_.isArray(elem)) { - return thenAll(elem, null, true); - } else { - return elem; - } - }) - .thenAll() - .value(); - } else { - return resolvedArr; - } - }); - return then ? promise.then(then) : promise; - }; - if (arr.then) { - return arr.then(doAll); - } else { - return doAll(arr); - } - } - - function thenFlatten(array, isShallow, callback, thisArg) { - return thenAll(array, _.partialRight(_.flatten, isShallow, callback, thisArg), true); - } - - function wrapCallback(method, callback, thisArg, collection) { - return method(collection, function(value, index, collection) { - if (_.isUndefined(value)) { - return callback(value, index, collection); - } else if (_.isFunction(value.then)) { - return value.then(_.partialRight(callback, index, collection)); - } else { - return callback(value, index, collection); - } - }, thisArg); - } - - function promiseWrapper(method, collection, callback, thisArg) { - if (_.isFunction(collection.then)) { - return collection.then( - _.partial(wrapCallback, method, callback, thisArg)); - } else { - return $q.all(collection) - .then(function(unwrappedResults) { - return method(unwrappedResults, callback, thisArg); - }); - } - } - - toExtend.forEach(function(fnName) { - var wrappedName = 'then' + _.capitalize(fnName); - _aw[wrappedName] = _.partial(promiseWrapper, _[fnName]); - }); - - _aw.promise = _promise; - _aw.reject = _reject; - _aw.then = _then; - _aw.catch = _catch; - _aw.finally = _finally; - _aw.thenAll = thenAll; - _aw.thenFlatten = thenFlatten; - _aw.log = log; - - lodash.mixin(_aw); - - return lodash; -} - -export default ['$q', lodashAsPromised]; diff --git a/awx/ui/client/src/shared/lookup/lookup-modal.block.less b/awx/ui/client/src/shared/lookup/lookup-modal.block.less deleted file mode 100644 index a0f331ca0f02..000000000000 --- a/awx/ui/client/src/shared/lookup/lookup-modal.block.less +++ /dev/null @@ -1,6 +0,0 @@ -.Lookup .modal-body{ - padding-top: 0px; -} -.Lookup-cancel{ - margin-right: 20px; -} diff --git a/awx/ui/client/src/shared/lookup/lookup-modal.directive.js b/awx/ui/client/src/shared/lookup/lookup-modal.directive.js deleted file mode 100644 index 273dfb9fd9a8..000000000000 --- a/awx/ui/client/src/shared/lookup/lookup-modal.directive.js +++ /dev/null @@ -1,119 +0,0 @@ -export default ['templateUrl', function(templateUrl) { - return { - restrict: 'E', - replace: true, - transclude: true, - scope: false, - templateUrl: templateUrl('shared/lookup/lookup-modal'), - link: function(scope, element, attrs, controller, transcludefn) { - - transcludefn(scope, (clone, linked_scope) => { - // scope.$resolve is a reference to resolvables in stateDefinition.resolve block - // https://ui-router.github.io/docs/latest/interfaces/state.statedeclaration.html#resolve - let list = linked_scope.$resolve.ListDefinition, - Dataset = linked_scope.$resolve.Dataset; - // search init - linked_scope.list = list; - linked_scope[`${list.iterator}_dataset`] = Dataset.data; - linked_scope[list.name] = linked_scope[`${list.iterator}_dataset`].results; - - element.find('.modal-body').append(clone); - - scope.init(element); - - }); - $('#form-modal').modal('show'); - }, - controller: ['$scope', '$state', 'EventService', function($scope, $state, eventService) { - let listeners, modal; - - function clickIsOutsideModal(e) { - const m = modal.getBoundingClientRect(); - const cx = e.clientX; - const cy = e.clientY; - - if (cx < m.left || cx > m.right || cy > m.bottom || cy < m.top) { - return true; - } - - return false; - } - - function clickToHide(event) { - if (clickIsOutsideModal(event)) { - $scope.cancelForm(); - } - } - - $scope.init = function(el) { - let list = $scope.list; - [modal] = el.find('.modal-dialog'); - if($state.params.selected) { - let selection = $scope[list.name].find(({id}) => id === parseInt($state.params.selected)); - $scope.currentSelection = _.pick(selection, 'id', 'name'); - } - $scope.$watch(list.name, function(){ - selectRowIfPresent(); - }); - - $scope.modalTitle = list.iterator.replace(/_/g, ' '); - - listeners = eventService.addListeners([ - [window, 'click', clickToHide] - ]); - }; - - function selectRowIfPresent(){ - let list = $scope.list; - if($scope.currentSelection && $scope.currentSelection.id) { - $scope[list.name].forEach(function(row) { - if (row.id === $scope.currentSelection.id) { - row.checked = 1; - } - }); - } - } - - $scope.saveForm = function() { - eventService.remove(listeners); - let list = $scope.list; - if($scope.currentSelection.name !== null) { - $scope.$parent[`${list.iterator}_name`] = $scope.currentSelection.name; - } - $scope.$parent[list.iterator] = $scope.currentSelection.id; - $state.go('^'); - }; - - $scope.cancelForm = function() { - eventService.remove(listeners); - $state.go('^'); - }; - - $scope.toggle_row = function(selectedRow) { - let list = $scope.list; - let count = 0; - $scope[list.name].forEach(function(row) { - if (row.id === selectedRow.id) { - if (row.checked) { - row.success_class = 'success'; - } else { - row.checked = 1; - row.success_class = ''; - } - $scope.currentSelection = { - name: row.name, - id: row.id - }; - } else { - row.checked = 0; - row.success_class = ''; - } - if (row.checked) { - count++; - } - }); - }; - - }] - }; -}]; diff --git a/awx/ui/client/src/shared/lookup/lookup-modal.partial.html b/awx/ui/client/src/shared/lookup/lookup-modal.partial.html deleted file mode 100644 index a14c6b6116b0..000000000000 --- a/awx/ui/client/src/shared/lookup/lookup-modal.partial.html +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/awx/ui/client/src/shared/lookup/main.js b/awx/ui/client/src/shared/lookup/main.js deleted file mode 100644 index df069649ab35..000000000000 --- a/awx/ui/client/src/shared/lookup/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import directive from './lookup-modal.directive'; - -export default - angular.module('LookupModalModule', []) - .directive('lookupModal', directive); diff --git a/awx/ui/client/src/shared/main.js b/awx/ui/client/src/shared/main.js deleted file mode 100644 index ecedd80f35b8..000000000000 --- a/awx/ui/client/src/shared/main.js +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import listGenerator from './list-generator/main'; -import formGenerator from './form-generator'; -import lookupModal from './lookup/main'; -import smartSearch from './smart-search/main'; -import paginate from './paginate/main'; -import columnSort from './column-sort/main'; -import lodashAsPromised from './lodash-as-promised'; -import filters from './filters/main'; -import truncatedText from './truncated-text.directive'; -import stateExtender from './stateExtender.provider'; -import rbacUiControl from './rbacUiControl'; -import socket from './socket/main'; -import templateUrl from './template-url/main'; -import RestServices from '../rest/main'; -import stateDefinitions from './stateDefinitions.factory'; -import apiLoader from './api-loader'; -import variables from './variables/main'; -import parse from './parse/main'; -import loadconfig from './load-config/main'; -import nextpage from './next-page/main'; -import Modal from './Modal'; -import moment from './moment/main'; -import config from './config/main'; -import PromptDialog from './prompt-dialog'; -import directives from './directives'; -import features from './features/main'; -import orgAdminLookup from './org-admin-lookup/main'; -import limitPanels from './limit-panels/main'; -import multiSelectPreview from './multi-select-preview/main'; -import credentialTypesLookup from './credentialTypesLookup.factory'; - -export default -angular.module('shared', [ - listGenerator.name, - formGenerator.name, - lookupModal.name, - smartSearch.name, - paginate.name, - columnSort.name, - filters.name, - 'ui.router', - rbacUiControl.name, - socket.name, - templateUrl.name, - RestServices.name, - apiLoader.name, - variables.name, - parse.name, - loadconfig.name, - nextpage.name, - Modal.name, - moment.name, - config.name, - PromptDialog.name, - directives.name, - filters.name, - features.name, - orgAdminLookup.name, - limitPanels.name, - multiSelectPreview.name, - 'ngCookies', - 'angular-duration-format' - ]) - .factory('stateDefinitions', stateDefinitions) - .factory('lodashAsPromised', lodashAsPromised) - .factory('credentialTypesLookup', credentialTypesLookup) - .directive('truncatedText', truncatedText) - .provider('$stateExtender', stateExtender); diff --git a/awx/ui/client/src/shared/media-object.block.less b/awx/ui/client/src/shared/media-object.block.less deleted file mode 100644 index 085999154fdd..000000000000 --- a/awx/ui/client/src/shared/media-object.block.less +++ /dev/null @@ -1,14 +0,0 @@ -/** @define Media */ - -.Media { - display: flex; - align-items: flex-start; - - &-figure { - margin-right: 1.4rem; - } - - &-body { - flex: 1; - } -} diff --git a/awx/ui/client/src/shared/modal/modal.less b/awx/ui/client/src/shared/modal/modal.less deleted file mode 100644 index 5b09e72b92d8..000000000000 --- a/awx/ui/client/src/shared/modal/modal.less +++ /dev/null @@ -1,133 +0,0 @@ -.Modal-content { - display:flex; - flex-wrap:wrap; - flex-direction: row; - padding: 15px 20px; - -webkit-box-shadow: 5px 5px 5px 0px rgba(0,0,0,0.25); - -moz-box-shadow: 5px 5px 5px 0px rgba(0,0,0,0.25); - box-shadow: 5px 5px 5px 0px rgba(0,0,0,0.25); -} - -.Modal-header { - display: flex; - width: 100%; - margin-bottom: 20px; -} - -.Modal-title { - flex: 1 0 auto; - text-transform: uppercase; - color: @list-header-txt; - font-size: 14px; - font-weight: bold; - width: calc(100%-18px); - word-break: break-word; -} - -.Modal-exitHolder{ - justify-content: flex-end; - display:flex; -} - -.Modal-exit{ - cursor:pointer; - padding:0px; - border: none; - height:20px; - font-size: 20px; - background-color:@default-bg; - color:@default-icon-hov; - line-height:1; - opacity: 1; -} - -.Modal-exit:hover{ - color: @default-icon; - opacity: 1; -} - -.Modal-body { - width: 100%; -} - -.Modal-bodyQuery { - margin-bottom: 20px; - color: @default-interface-txt; -} - -.Modal-bodyTarget { - color: @default-data-txt; -} - -.Modal-footer { - display: flex; - justify-content: flex-end; - margin-top: 20px; - width: 100%; -} - -.Modal-defaultButton { - background-color: @default-bg; - color: @btn-txt; - text-transform: uppercase; - border-radius: 5px; - border: 1px solid @btn-bord; - transition: background-color 0.2s; - padding-left:15px; - padding-right: 15px; -} - -.Modal-defaultButton:hover { - background-color: @btn-bg-hov; - color: @btn-txt; -} - -.Modal-errorButton { - background-color: @default-err; - color: @btn-txt-sel; - text-transform: uppercase; - border-radius: 5px; - transition: background-color 0.2s; - padding-left:15px; - padding-right: 15px; -} - -.Modal-errorButton:hover { - background-color: @default-err-hov; - color: @btn-txt-sel; -} - -.Modal-errorButton--sourcesDelete:hover{ - cursor: not-allowed; -} - -.Modal-primaryButton { - background-color: @default-link; - color: @default-bg; - text-transform: uppercase; - border-radius: 5px; - transition: background-color 0.2s; - padding-left:15px; - padding-right: 15px; -} - -.Modal-primaryButton:hover { - background-color: @default-link-hov; - color: @default-bg; -} - -.Modal-errorButton:focus { - color: @btn-txt-sel; -} - -.Modal-footerButton { - padding: 4px 8px; -} - -.Modal-footerButton + .Modal-footerButton { - margin-left: 20px; -} - -.Modal-titleResourceName { - color: @default-err; -} diff --git a/awx/ui/client/src/shared/moment/main.js b/awx/ui/client/src/shared/moment/main.js deleted file mode 100644 index f1c70d88c0ad..000000000000 --- a/awx/ui/client/src/shared/moment/main.js +++ /dev/null @@ -1,9 +0,0 @@ -import newMoment from './moment'; - -export default - angular.module('moment', ['angularMoment']) - .config(function() { - // Remove the global variable for moment - delete window.moment; - }) - .constant('moment', newMoment); diff --git a/awx/ui/client/src/shared/moment/moment.js b/awx/ui/client/src/shared/moment/moment.js deleted file mode 100644 index bf03763b50fc..000000000000 --- a/awx/ui/client/src/shared/moment/moment.js +++ /dev/null @@ -1,21 +0,0 @@ -var originalMoment = require('moment'); -import {merge} from 'lodash'; - -function moment() { - - // navigator.language is available in all modern browsers. - // however navigator.languages is a new technology that - // lists the user's preferred languages, the first in the array - // being the user's top choice. navigator.languages is currently - // comptabile with chrome>v32, ffox>32, but not IE/Safari - var lang = window.navigator.languages ? - window.navigator.languages[0] : - (window.navigator.language || window.navigator.userLanguage); - - originalMoment.locale(lang); - return originalMoment.apply(this, arguments); -} - -merge(moment, originalMoment); - -export default moment; diff --git a/awx/ui/client/src/shared/multi-select-list/main.js b/awx/ui/client/src/shared/multi-select-list/main.js deleted file mode 100644 index 0c1bb7fcbadb..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/main.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import multiSelect from './multi-select-list.directive'; -//import selectAll from './select-all.directive'; -import selectListItem from './select-list-item.directive'; -import templateUrl from '../template-url/main'; - -export default - angular.module('multiSelectList', [templateUrl.name]) - .directive('multiSelectList', multiSelect) - //.directive('selectAll', selectAll) - .directive('selectListItem', selectListItem); diff --git a/awx/ui/client/src/shared/multi-select-list/multi-select-list.controller.js b/awx/ui/client/src/shared/multi-select-list/multi-select-list.controller.js deleted file mode 100644 index 1d7044af28d0..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/multi-select-list.controller.js +++ /dev/null @@ -1,206 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc object - * @name multiSelectList.controller:multiSelectList - * - * @description - * - * `multiSelectList` controller provides the API for the {@link multiSelectList.directive:multiSelectList `multiSelectList`} directive. The controller contains methods for selecting/deselecting items, controlling the extended selection, registering items to be selectable and emitting an event on the directive's `$scope`. - * - */ -export default ['$scope', - function ($scope) { - $scope.items = []; - $scope.selection = { - isExtended: false, - selectedItems: [], - deselectedItems: [] - }; - - // Makes $scope.selection.length an alias for $scope.selectedItems.length - Object.defineProperty($scope.selection, - 'length', - { get: function() { - return this.selectedItems.length; - } - }); - - function rebuildSelections() { - var _items = _($scope.items).chain(); - - $scope.selection.selectedItems = - _items.filter(function(item) { - return item.isSelected; - }).pluck('value').value(); - - $scope.selection.deselectedItems = - _items.pluck('value').difference($scope.selection.selectedItems) - .value(); - - /** - * - * @ngdoc event - * @name multiSelectList.selectionChanged - * @eventOf multiSelectList.directive:multiSelectList - * - */ - $scope.$emit('multiSelectList.selectionChanged', $scope.selection); - } - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#registerItem - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Prepares an object to be tracked in the select list. Returns the - * decorated item created by - * {@link multiSelectList.controller:multiSelectList#decorateItem `decorateItem`} - */ - this.registerItem = function(item) { - var foundItem = _.find($scope.items, function(existingItem) { return existingItem.id === item.id; }); - - if(foundItem) { - return foundItem; - } - else { - var decoratedItem = this.decorateItem(item); - $scope.items = $scope.items.concat(decoratedItem); - return decoratedItem; - } - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#deregisterItem - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Removes an item from the list; called if the item is removed from the display - * so that it is no longer tracked as a selectable item. - */ - this.deregisterItem = function(leavingItem) { - $scope.items = $scope.items.filter(function(item) { - return leavingItem !== item; - }); - rebuildSelections(); - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#decorateItem - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * - * This decorates an item with an object that has an `isSelected` property. - * This value is used to determine the lists of selected and non-selected - * items to emit with the `multiSelectList.selectionChanged` - * event. - */ - this.decorateItem = function(item) { - return { - isSelected: false, - id: item.id, - value: item - }; - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#selectAll - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Marks all items in the list as selected. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - */ - this.selectAll = function() { - $scope.items.forEach(function(item) { - item.isSelected = true; - }); - rebuildSelections(); - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#deselectAll - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Marks all items in the list as not selected. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - */ - this.deselectAll = function() { - $scope.items.forEach(function(item) { - item.isSelected = false; - }); - $scope.selection.isExtended = false; - rebuildSelections(); - }; - - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#deselectAllExtended - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Disables extended selection. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - */ - this.deselectAllExtended = function() { - $scope.selection.isExtended = false; - rebuildSelections(); - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#selectAllExtended - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Enables extended selection. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - */ - this.selectAllExtended = function() { - $scope.selection.isExtended = true; - rebuildSelections(); - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#selectItem - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Marks an item as selected. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - * - */ - this.selectItem = function(item) { - item.isSelected = true; - rebuildSelections(); - }; - - /** - * @ngdoc method - * @name multiSelectList.controller:multiSelectList#deregisterItem - * @methodOf multiSelectList.controller:multiSelectList - * - * @description - * Marks an item as not selected. - * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`} - * - */ - this.deselectItem = function(item) { - item.isSelected = false; - rebuildSelections(); - }; - - }]; diff --git a/awx/ui/client/src/shared/multi-select-list/multi-select-list.directive.js b/awx/ui/client/src/shared/multi-select-list/multi-select-list.directive.js deleted file mode 100644 index 71424d3cbea5..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/multi-select-list.directive.js +++ /dev/null @@ -1,146 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc overview - * @name multiSelectList - * @scope - * @description Does some stuff - * - * @ngdoc directive - * @name multiSelectList.directive:multiSelectList - * @description - * The `multiSelectList` directive works in conjunction with the - * `selectListItem` and (optionally) the `selectAll` directives to - * render checkboxes with list items and tracking the selected state - * of each item. The `selectListItem` directive renders a checkbox, - * and the `multiSelectList` directive tracks the selected state - * of list items. The `selectAll` directive renders a checkbox that - * will select/deselect all items in the list. - * - * - * This directive exposes a special object on its local scope called - * `selection` that is used to access the current selection state. - * The following properties on `selection` are available: - * - * | Property | Type | Details | - * |-------------------|-----------------|-------------------------------------------------------------| - * | `selectedItems` | {@type array} | The items that are currently selected | - * | `deselectedItem` | {@type array} | The items that are currently _not_ selected | - * | `isExtended` | {@type boolean} | Indicates that the user has requested an extended selection | - * | `length` | {@type number} | The length of the selected items array | - * - * Use the `multi-select-list` directive to indicate that you want - * to allow users to select items in a list. To display a checkbox - * next to each item, use the {@link multiSelectList.directive:selectListItem `select-list-item`} directive. - * - * # Rendering a basic multi-select list - * - * @example - * - * This example creates a list of names and then - * uses `multiSelectList` to make the names - * selectable: - * - - -
-
    -
  • - - {{item.name}} -
  • -
-
-
- -
- - # Making other elements respond to the state of the selction - - In this example, we'll see how to make a button that enables/disables - itself based on some property of the selection. - - - - angular.module('stateTrackingExample', ['multiSelectList']) - .controller('namesController', ['$scope', function($scope) { - $scope.names = - [ { name: 'John' - }, - { name: 'Jared' - }, - { name: 'Joe' - }, - { name: 'James' - }, - { name: 'Matt' - }, - { name: 'Luke' - }, - { name: 'Chris' - } - ]; - - // Initial logic for buttons - $scope.noSelections = true; - $scope.atLeastOneSelection = false; - $scope.exactlyTwoSelections = false; - - var cleanup = $scope.$on('multiSelectList.selectionChanged', function(e, selection) { - // Recalculate logic for buttons whenever selections change - $scope.noSelections = selection.length == 0; - $scope.atLeastOneSelection = selection.length >= 1; - $scope.exactlyTwoSelections = selection.length == 2; - }); - }]); - - -
- - - -
    -
  • - - {{item.name}} -
  • -
-
-
- -
- - * -*/ -import controller from './multi-select-list.controller'; - -export default -[ function() { - return { - restrict: 'A', - scope: { - }, - controller: controller - }; - }]; diff --git a/awx/ui/client/src/shared/multi-select-list/select-all.directive.js b/awx/ui/client/src/shared/multi-select-list/select-all.directive.js deleted file mode 100644 index 4470f05e79fa..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/select-all.directive.js +++ /dev/null @@ -1,193 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc directive - * @name multiSelectList.directive:selectAll - * @scope - * @restrict E - * - * @param {string} label The text that will appear next to the checkbox - * @param {number} itemsLength The number of displayed items in the list - * @param {number} extendedItemsLength The total number of items in the list used for extended mode (see below) - * @param {string_expression} extendedLabel A custom label to display when prompting the user to extend the selection; this is an expression so strings must be in single quotes ('), but you can use scope varibles here to display the count of items with the `extendedItemsLength` property - * @param {boolean_expression} selectionsEmpty An expression that evaluates to a truthy value used to disable - * the select all checkbox when the displayed list is empty - * - * @description - * - * Use the `select-all` directive as a child of a `multi-select-list` - * to present the user with a checkbox that, when checked, checks all - * `select-list-item` children, and when unchecked it unchecks them. - * - * - -
-
    -
  • - -
  • -
  • - - {{item.name}} -
  • -
-
-
- - *
- * - * ## Extended Selections - * - * In some cases the list items you are displaying are only a subset of - * a larger list (eg. using pagination or infinite scroll to seperate - * items). In these cases, when a user checks "select all", it may be - * useful to give them the option to also select all the remaining - * items in the list. - * - * This behavior is controlled by the `extendedItemsLength` property - * of this directive. Set it to the total length of items in the list. - * For example, if you have a list of 100 items, displayed 10 per page, - * then `itemsLength` would be 10 and `extendedItemsLength` would be 100. - * When the user checks "select all" in the above example, it will show - * a button prompting them to "Select all 100 items". When the user selects - * this option, the `select-all` directive tells the `multiSelectList` - * controller that the selection is "extended" to all the items in the list. - * Listeners to the `multiSelectList.selectionChanged` event can then use this - * flag to respond differently when all items are selected. - * - * - * - - angular.module('extendedSelectionExample', ['multiSelectList']) - .controller('namesController', ['$scope', function($scope) { - - var cleanup = $scope.$on('multiSelectList.selectionChanged', function(e, selection) { - $scope.isSelectionExtended = selection.isExtended; - }); - - $scope.$on('$destroy', cleanup); - - $scope.allNames = - [ { name: 'John' - }, - { name: 'Jared' - }, - { name: 'Joe' - }, - { name: 'James' - }, - { name: 'Matt' - }, - { name: 'Luke' - }, - { name: 'Chris' - } - ]; - - $scope.firstPageOfNames = - $scope.allNames.slice(0,3); - }]); - - -
-

Extended Selection

-
    -
  • - -
  • -
  • - - {{item.name}} -
  • -
-
-
- *
- */ -// TODO: Extract to its own helper -// Example: -// template('shared/multi-select-list/select-all') -// // => -// '/static/js/shared/multi-select-list/select-all.html -// - -export default - [ 'templateUrl', - function(templateUrl) { - return { - require: '^multiSelectList', - restrict: 'E', - scope: { - label: '@', - itemsLength: '=', - extendedItemsLength: '=', - extendedLabel: '&', - isSelectionEmpty: '=selectionsEmpty' - }, - templateUrl: templateUrl('shared/multi-select-list/select-all'), - link: function(scope, element, attrs, controller) { - - scope.label = scope.label || 'All'; - scope.selectExtendedLabel = scope.extendedLabel() || 'Select all ' + scope.extendedItemsLength + ' items'; - scope.deselectExtendedLabel = scope.deselectExtendedLabel || 'Deselect extra items'; - - scope.doSelectAll = function() { - if (scope.isSelected) { - controller.selectAll(); - - if (scope.supportsExtendedItems) { - scope.showExtendedMessage = scope.itemsLength !== scope.extendedItemsLength; - } - } else { - controller.deselectAll(); - - if (scope.isSelectionExtended) { - scope.deselectAllExtended(); - } - - scope.showExtendedMessage = false; - } - }; - - scope.$watch('extendedItemsLength', function(value) { - scope.supportsExtendedItems = _.isNumber(value); - }); - - scope.$watch('isSelectionEmpty', function(value) { - if (value) { - scope.isSelected = false; - } - }); - - scope.selectAllExtended = function() { - controller.selectAllExtended(scope.extendedItemsLength); - scope.isSelectionExtended = true; - }; - - scope.deselectAllExtended = function() { - controller.deselectAllExtended(scope.extendedItemsLength); - scope.isSelectionExtended = false; - }; - - } - }; - }]; diff --git a/awx/ui/client/src/shared/multi-select-list/select-all.partial.html b/awx/ui/client/src/shared/multi-select-list/select-all.partial.html deleted file mode 100644 index e16d664345f2..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/select-all.partial.html +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/awx/ui/client/src/shared/multi-select-list/select-list-item.directive.js b/awx/ui/client/src/shared/multi-select-list/select-list-item.directive.js deleted file mode 100644 index aa8397e9040f..000000000000 --- a/awx/ui/client/src/shared/multi-select-list/select-list-item.directive.js +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc directive - * @name multiSelectList.directive:selectListItem - * @restrict E - * @scope - * @description - * - The `select-list-item` directive renders a checkbox for tracking - the state of a given item in a list. When the user checks the - checkbox it tells the `multi-select-list` controller to select - the item; when the user unchecks the checkbox it tells the controller - to deselect the item. - - @example - - For examples of using this directive, see {@link multiSelectList.directive:multiSelectList multiSelectList}. - - */ -export default - [ function() { - return { - restrict: 'E', - scope: { - item: '=item' - }, - require: '^multiSelectList', - template: '', - link: function(scope, element, attrs, multiSelectList) { - - scope.decoratedItem = multiSelectList.registerItem(scope.item); - - scope.$watch('item.isSelected', function(value) { - if (value === true) { - multiSelectList.selectItem(scope.decoratedItem); - } else if (value === false) { - multiSelectList.deselectItem(scope.decoratedItem); - } - }); - - scope.userInteractionSelect = function() { - scope.$emit("selectedOrDeselected", scope.decoratedItem); - }; - - } - }; - }]; diff --git a/awx/ui/client/src/shared/multi-select-preview/main.js b/awx/ui/client/src/shared/multi-select-preview/main.js deleted file mode 100644 index 1f50c494c0ff..000000000000 --- a/awx/ui/client/src/shared/multi-select-preview/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import multiSelectPreview from './multi-select-preview.directive'; - -export default - angular.module('multiSelectPreview', []) - .directive('multiSelectPreview', multiSelectPreview); diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less deleted file mode 100644 index 2a21ab3f2e2e..000000000000 --- a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less +++ /dev/null @@ -1,97 +0,0 @@ -.MultiSelectPreview { - display: flex; - flex: 1 0 auto; - margin-bottom: 15px; - align-items: baseline; -} - -.MultiSelectPreview-selectedItems { - display: flex; - flex: 0 0 100%; - background-color: @default-no-items-bord; - border: 1px solid @default-border; - padding: 10px; - border-radius: 5px; -} - -.MultiSelectPreview-selectedItemsLabel, .MultiSelectPreview-label { - color: @default-interface-txt; - margin-right: 10px; -} - -.MultiSelectPreview-selectedItemsLabel { - flex: 0 0 80px; - line-height: 29px; -} - -.MultiSelectPreview-previewTags--outer { - flex: 1 0 auto; - max-width: ~"calc(100% - 140px)"; -} - -.MultiSelectPreview-previewTags--inner { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -.MultiSelectPreview-previewTagContainer { - display: flex; -} - -.MultiSelectPreview-previewTagRevert { - flex: 0 0 60px; - line-height: 29px; -} - -.MultiSelectPreview-revertLink { - font-size: 12px; -} - -.MultiSelectPreview-previewTagContainerDelete { - background-color: @default-link; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - color: @default-bg; - padding: 0 5px; - margin: 4px 0px; - align-items: center; - display: flex; - cursor: pointer; -} - -.MultiSelectPreview-previewTagContainerDelete:hover { - border-color: @default-err; - background-color: @default-err; -} - -.MultiSelectPreview-previewTagContainerDelete:hover > .MultiSelectPreview-previewTagContainerTagDelete { - color: @default-bg; -} - -.MultiSelectPreview-previewTag { - border-radius: 5px; - padding: 2px 10px; - margin: 4px 0px; - font-size: 12px; - color: @default-interface-txt; - background-color: @default-list-header-bg; - margin-right: 5px; - max-width: 100%; - display: inline-block; -} - -.MultiSelectPreview-previewTagLabel { - color: @default-list-header-bg; -} - -.MultiSelectPreview-previewTag--deletable { - color: @default-bg; - background-color: @default-link; - margin-right: 0px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - border-right: 0; - max-width: ~"calc(100% - 23px)"; - margin-right: 5px; -} diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js deleted file mode 100644 index be166234c733..000000000000 --- a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js +++ /dev/null @@ -1,21 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', - function ($scope) { - $scope.unselectSelectedRow = function(index) { - - angular.forEach($scope.availableRows, function(value) { - if(value.id === $scope.selectedRows[index].id) { - value.isSelected = false; - } - }); - - $scope.selectedRows.splice(index, 1); - - }; - } -]; diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js deleted file mode 100644 index 6805840f193a..000000000000 --- a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js +++ /dev/null @@ -1,20 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import MultiSelectPreviewController from './multi-select-preview.controller'; - - export default ['templateUrl', function(templateUrl) { - return { - restrict: 'E', - replace: true, - scope: { - selectedRows: '=', - availableRows: '=' - }, - controller: MultiSelectPreviewController, - templateUrl: templateUrl('shared/multi-select-preview/multi-select-preview') - }; - }]; diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html deleted file mode 100644 index 48eb41b1b557..000000000000 --- a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
- SELECTED: -
-
-
-
-
- -
-
- {{selectedRow.name}} - {{selectedRow.hostname}} -
-
-
-
-
-
diff --git a/awx/ui/client/src/shared/next-page/main.js b/awx/ui/client/src/shared/next-page/main.js deleted file mode 100644 index 8d9e83f28a63..000000000000 --- a/awx/ui/client/src/shared/next-page/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import NextPage from './next-page.factory'; - -export default - angular.module('nextpage', []) - .factory('NextPage', NextPage); diff --git a/awx/ui/client/src/shared/next-page/next-page.factory.js b/awx/ui/client/src/shared/next-page/next-page.factory.js deleted file mode 100644 index fa5bce3dc76b..000000000000 --- a/awx/ui/client/src/shared/next-page/next-page.factory.js +++ /dev/null @@ -1,28 +0,0 @@ -export default - function NextPage(Rest, $q) { - return function(params) { - - let getNext = function(getNextParams){ - Rest.setUrl(getNextParams.url); - return Rest.get() - .then(function (res) { - if (res.data.next) { - return getNext({ - url: res.data.next, - arrayOfValues: getNextParams.arrayOfValues.concat(res.data.results) - }); - } else { - return $q.resolve(getNextParams.arrayOfValues.concat(res.data.results)); - } - }) - .catch(function(response) { - return $q.reject( response ); - }); - }; - - return getNext(params); - - }; - } - -NextPage.$inject = ['Rest', '$q']; diff --git a/awx/ui/client/src/shared/org-admin-lookup/main.js b/awx/ui/client/src/shared/org-admin-lookup/main.js deleted file mode 100644 index 3d4f162f6265..000000000000 --- a/awx/ui/client/src/shared/org-admin-lookup/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import OrgAdminLookupFactory from './org-admin-lookup.factory'; - -export default - angular.module('orgAdminLookup', []) - .service('OrgAdminLookup', OrgAdminLookupFactory); diff --git a/awx/ui/client/src/shared/org-admin-lookup/org-admin-lookup.factory.js b/awx/ui/client/src/shared/org-admin-lookup/org-admin-lookup.factory.js deleted file mode 100644 index 3e86cd866c97..000000000000 --- a/awx/ui/client/src/shared/org-admin-lookup/org-admin-lookup.factory.js +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - ['Rest', 'Authorization', 'GetBasePath', 'ProcessErrors', '$rootScope', '$q', - function(Rest, Authorization, GetBasePath, ProcessErrors, $rootScope, $q){ - return { - checkForAdminAccess: function(params) { - // params.organization - id of the organization in question - var deferred = $q.defer(); - if(Authorization.getUserInfo('is_superuser') !== true) { - Rest.setUrl(GetBasePath('users') + $rootScope.current_user.id + '/admin_of_organizations'); - Rest.get({ params: { id: params.organization } }) - .then(({data}) => { - if(data.count && data.count > 0) { - deferred.resolve(true); - } - else { - deferred.resolve(false); - } - }); - } - else { - deferred.resolve(true); - } - - return deferred.promise; - }, - - checkForRoleLevelAdminAccess: function(organization_id, role_level) { - let deferred = $q.defer(); - let params = { - role_level, - id: organization_id - }; - - if(Authorization.getUserInfo('is_superuser') !== true) { - Rest.setUrl(GetBasePath('organizations')); - Rest.get({ params: params }) - .then(({data}) => { - if(data.count && data.count > 0) { - deferred.resolve(true); - } - else { - deferred.resolve(false); - } - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get organization data based on role_level. Return status: ' + status - }); - }); - } - else { - deferred.resolve(true); - } - return deferred.promise; - } - }; - } - ]; diff --git a/awx/ui/client/src/shared/paginate/main.js b/awx/ui/client/src/shared/paginate/main.js deleted file mode 100644 index 394f9b90342b..000000000000 --- a/awx/ui/client/src/shared/paginate/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import directive from './paginate.directive'; -import controller from './paginate.controller'; - -export default - angular.module('PaginateModule', []) - .directive('paginate', directive) - .controller('PaginateController', controller); diff --git a/awx/ui/client/src/shared/paginate/paginate.block.less b/awx/ui/client/src/shared/paginate/paginate.block.less deleted file mode 100644 index 4cddec9d916b..000000000000 --- a/awx/ui/client/src/shared/paginate/paginate.block.less +++ /dev/null @@ -1,84 +0,0 @@ - // @todo cleanup these messy overrides for styles in ansible-ui.min.css - -.Paginate-controls--first a, -.Paginate-controls--previous a{ - border-radius: 4px 0 0 4px; - } -.Paginate-controls--last a, -.Paginate-controls--next a{ - border-radius: 0px 4px 4px 0; -} - - .Paginate-controls--item a { - font-size: 12px; - padding: 3px 6px !important; - border-color: @list-pagin-bord; - } - -.Paginate { - margin-top: 20px; - font-size: 10px !important; - color: @list-pagin-text; - text-transform: uppercase; - display: flex; - justify-content: flex-end; -} - -.Paginate-pager--pageof { - line-height: 25px; - margin-left: 10px; -} - -.Paginate-wrapper { - display: flex; - flex: 1 0 auto; -} - -.Paginate-controls { - margin-top: 0; - margin-bottom: 0px; - display: inline-block; - padding-left: 0; - border-radius: 4px; -} - -.Paginate-controls--active { - color: #fff !important; - border-color: @default-icon-hov !important; - background-color: @default-icon-hov !important; -} - -.Paginate-total { - display: flex; - align-items: flex-end; - margin: 0 0 -2px 10px; -} - -.Paginate-filterLabel{ - padding: 0px 10px 0px 10px; -} - -.Paginate-filteringDropdowns{ - display: flex; - align-items: center; - line-height: 25px; -} - -.Paginate-dropdown{ - z-index: 1041; - margin-bottom: 10px; -} - -.Paginate-filteringDropdowns { - & > .DashboardGraphs-periodDropdown { - min-width: 50px; - - & > ul { - min-width: 50px; - } - } -} - -.Paginate-itemsOf { - line-height: 25px; -} diff --git a/awx/ui/client/src/shared/paginate/paginate.controller.js b/awx/ui/client/src/shared/paginate/paginate.controller.js deleted file mode 100644 index 5c4a9f109074..000000000000 --- a/awx/ui/client/src/shared/paginate/paginate.controller.js +++ /dev/null @@ -1,131 +0,0 @@ -export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'QuerySet', '$interpolate', - function($scope, $stateParams, $state, $filter, GetBasePath, qs, $interpolate) { - - let pageSize = $scope.querySet ? $scope.querySet.page_size || 20 : $stateParams[`${$scope.iterator}_search`].page_size || 20, - queryset, path; - - $scope.pageSize = pageSize; - $scope.basePageSize = parseInt(pageSize) === 5 ? 5 : 20; - $scope.maxVisiblePages = $scope.maxVisiblePages ? parseInt($scope.maxVisiblePages) : 10; - - $scope.filter = function(id){ - let pageSize = Number(id); - $('#period-dropdown') - .replaceWith(""+id+ - "\n"); - - if ($scope.querySet){ - let origQuerySet = _.cloneDeep($scope.querySet); - queryset = _.merge(origQuerySet, { page_size: pageSize }); - } else { - queryset = _.merge($stateParams[`${$scope.iterator}_search`], { page_size: pageSize, page: 1 }); - } - $scope.toPage(); - }; - - $scope.toPage = function(page) { - if (page === 0 || page > $scope.last) { - return; - } - if (GetBasePath($scope.basePath) || $scope.basePath) { - path = GetBasePath($scope.basePath) || $scope.basePath; - } else { - let interpolator = $interpolate($scope.basePath); - path = interpolator({ $stateParams: $stateParams }); - } - if ($scope.querySet) { - // merging $scope.querySet seems to destroy our initial reference which - // kills the two-way binding here. To fix that, clone the queryset first - // and merge with that object. - let origQuerySet = _.cloneDeep($scope.querySet); - queryset = _.merge(origQuerySet, { page: page }); - - } else { - let origStateParams = _.cloneDeep($stateParams[`${$scope.iterator}_search`]); - queryset = _.merge(origStateParams, { page: page }); - } - if (!$scope.querySet) { - $state.go('.', { - [$scope.iterator + '_search']: queryset - }, {notify: false}); - } - qs.search(path, queryset).then((res) => { - if ($scope.querySet) { - // Update the query set - $scope.querySet = queryset; - } - $scope.dataset = res.data; - $scope.collection = res.data.results; - }); - }; - - function calcLast() { - return Math.ceil($scope.dataset.count / $scope.pageSize); - } - - function calcCurrent() { - if ($scope.querySet) { - return parseInt($scope.querySet.page || '1'); - } else { - return parseInt($stateParams[`${$scope.iterator}_search`].page || '1'); - } - } - - function calcPageRange(current, last) { - let result = [], - maxVisiblePages = parseInt($scope.maxVisiblePages), - pagesLeft, - pagesRight; - if (maxVisiblePages % 2) { - // It's an odd number - pagesLeft = (maxVisiblePages - 1) / 2; - pagesRight = ((maxVisiblePages - 1) / 2) + 1; - } else { - // Its an even number - pagesLeft = pagesRight = maxVisiblePages / 2; - } - if (last < maxVisiblePages) { - // Don't have enough pages to exceed the max range - just show all of them - result = _.range(1, last + 1); - } else if (current === last) { - result = _.range(last + 1 - maxVisiblePages, last + 1); - } else { - let topOfRange = current + pagesRight > maxVisiblePages + 1 ? (current + pagesRight < last + 1 ? current + pagesRight : last + 1) : maxVisiblePages + 1; - let bottomOfRange = (topOfRange === last + 1) ? last + 1 - maxVisiblePages : (current - pagesLeft > 0 ? current - pagesLeft : 1); - result = _.range(bottomOfRange, topOfRange); - } - return result; - } - - function calcDataRange() { - if ($scope.current === 1 && $scope.dataset.count < parseInt($scope.pageSize)) { - return `1 - ${$scope.dataset.count}`; - } else if ($scope.current === 1) { - return `1 - ${$scope.pageSize}`; - } else { - let floor = (($scope.current - 1) * parseInt($scope.pageSize)) + 1; - let ceil = floor + parseInt($scope.pageSize) - 1 < $scope.dataset.count ? floor + parseInt($scope.pageSize) - 1 : $scope.dataset.count; - return `${floor} - ${ceil}`; - } - } - - function calcPageSize(){ - let pageSize = $scope.querySet ? $scope.querySet.page_size || 20 : $stateParams[`${$scope.iterator}_search`].page_size || 20; - return Number(pageSize) ; - } - - let updatePaginationVariables = function() { - $scope.pageSize = calcPageSize(); - $scope.current = calcCurrent(); - $scope.last = calcLast(); - $scope.pageRange = calcPageRange($scope.current, $scope.last); - $scope.dataRange = calcDataRange(); - }; - - updatePaginationVariables(); - - $scope.$watch('collection', function(){ - updatePaginationVariables(); - }); - } -]; diff --git a/awx/ui/client/src/shared/paginate/paginate.directive.js b/awx/ui/client/src/shared/paginate/paginate.directive.js deleted file mode 100644 index 73d6eed26b4b..000000000000 --- a/awx/ui/client/src/shared/paginate/paginate.directive.js +++ /dev/null @@ -1,19 +0,0 @@ -export default ['templateUrl', - function(templateUrl) { - return { - restrict: 'E', - replace: false, - scope: { - collection: '=', - dataset: '=', - iterator: '@', - basePath: '@', - querySet: '=', - maxVisiblePages: '@', - hideViewPerPage: '=' - }, - controller: 'PaginateController', - templateUrl: templateUrl('shared/paginate/paginate') - }; - } -]; diff --git a/awx/ui/client/src/shared/paginate/paginate.partial.html b/awx/ui/client/src/shared/paginate/paginate.partial.html deleted file mode 100644 index 68c36651da72..000000000000 --- a/awx/ui/client/src/shared/paginate/paginate.partial.html +++ /dev/null @@ -1,72 +0,0 @@ -
-
- - {{ 'Page' | translate }} - {{current}} {{ 'of' | translate }} - {{last}} - -
-
- - {{ 'ITEMS' | translate }}  - {{dataRange}} - of {{dataset.count | number}} - -
-
VIEW PER PAGE
-
- - {{pageSize}} - - -
-
-
-
diff --git a/awx/ui/client/src/shared/parse/main.js b/awx/ui/client/src/shared/parse/main.js deleted file mode 100644 index 962bf14bcf46..000000000000 --- a/awx/ui/client/src/shared/parse/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import ParseTypeChange from './parse-type-change.factory'; - -export default - angular.module('parse', []) - .factory('ParseTypeChange', ParseTypeChange); diff --git a/awx/ui/client/src/shared/parse/parse-type-change.factory.js b/awx/ui/client/src/shared/parse/parse-type-change.factory.js deleted file mode 100644 index 7728850046c1..000000000000 --- a/awx/ui/client/src/shared/parse/parse-type-change.factory.js +++ /dev/null @@ -1,121 +0,0 @@ -import 'codemirror/lib/codemirror.js'; -import 'codemirror/mode/javascript/javascript.js'; -import 'codemirror/mode/yaml/yaml.js'; -import 'codemirror/addon/lint/lint.js'; -import 'angular-codemirror/lib/yaml-lint.js'; -import 'codemirror/addon/edit/closebrackets.js'; -import 'codemirror/addon/edit/matchbrackets.js'; -import 'codemirror/addon/selection/active-line.js'; - -export default - function ParseTypeChange(Alert, AngularCodeMirror) { - return function(params) { - var scope = params.scope, - field_id = params.field_id, - fld = (params.variable) ? params.variable : 'variables', - pfld = (params.parse_variable) ? params.parse_variable : 'parseType', - onReady = params.onReady, - onChange = params.onChange, - readOnly = params.readOnly; - - function removeField(fld) { - //set our model to the last change in CodeMirror and then destroy CodeMirror - scope[fld] = scope[fld + 'codeMirror'].getValue(); - $('#cm-' + fld + '-container > .CodeMirror').empty().remove(); - } - - function createField(onChange, onReady, fld) { - //hide the textarea and show a fresh CodeMirror with the current mode (json or yaml) - let variableEditModes = { - yaml: { - mode: 'text/x-yaml', - matchBrackets: true, - autoCloseBrackets: true, - styleActiveLine: true, - lineNumbers: true, - gutters: ['CodeMirror-lint-markers'], - lint: true, - scrollbarStyle: null - }, - json: { - mode: 'application/json', - styleActiveLine: true, - matchBrackets: true, - autoCloseBrackets: true, - lineNumbers: true, - gutters: ['CodeMirror-lint-markers'], - lint: true, - scrollbarStyle: null - } - }; - - scope[fld + 'codeMirror'] = AngularCodeMirror(readOnly); - scope[fld + 'codeMirror'].addModes(variableEditModes); - scope[fld + 'codeMirror'].showTextArea({ - scope: scope, - model: fld, - element: field_id, - lineNumbers: true, - mode: scope[pfld], - onReady: onReady, - onChange: onChange - }); - } - - // Hide the textarea and show a CodeMirror editor - createField(onChange, onReady, fld); - - - // Toggle displayed variable string between JSON and YAML - scope.parseTypeChange = function(model, fld) { - var json_obj; - if (scope[model] === 'json') { - // converting yaml to json - try { - removeField(fld); - - json_obj = jsyaml.load(scope[fld]); - - if ($.isEmptyObject(json_obj)) { - if (Array.isArray(json_obj)) { - scope[fld] = "[]"; - } else { - scope[fld] = "{}"; - } - } else { - scope[fld] = JSON.stringify(json_obj, null, " "); - } - createField(onReady, onChange, fld); - } - catch (e) { - Alert('Parse Error', 'Failed to parse valid YAML. ' + e.message); - setTimeout( function() { scope.$apply( function() { scope[model] = 'yaml'; createField(onReady, onChange, fld); }); }, 500); - } - } - else { - // convert json to yaml - try { - removeField(fld); - - json_obj = JSON.parse(scope[fld]); - if ($.isEmptyObject(json_obj)) { - scope[fld] = '---'; - } - else { - scope[fld] = jsyaml.safeDump(json_obj); - } - createField(onReady, onChange, fld); - } - catch (e) { - Alert('Parse Error', 'Failed to parse valid JSON. ' + e.message); - setTimeout( function() { scope.$apply( function() { scope[model] = 'json'; createField(onReady, onChange, fld); }); }, 500 ); - } - } - }; - }; - } - -ParseTypeChange.$inject = - [ 'Alert', - 'AngularCodeMirror' - ]; diff --git a/awx/ui/client/src/shared/prompt-dialog.js b/awx/ui/client/src/shared/prompt-dialog.js deleted file mode 100644 index cfcc9e0e2eb8..000000000000 --- a/awx/ui/client/src/shared/prompt-dialog.js +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name shared.function:prompt-dialog - * @description - * PromptDialog - * Prompt the user with a Yes/No dialog to confirm an action such - * as Delete. Assumes a hidden dialog already exists in $scope. - * See example at bottom. If user responds with Yes, execute action - * parameter. - * - * params: { hdr: 'header msg', - * body: 'body text/html', - * class: 'btn-class for Yes button', --defaults to btn-danger - * action: function() {} --action to take, if use clicks Yes - * } - */ - - -/** -* @ngdoc method -* @name shared.function:prompt-dialog#PromptDialog -* @methodOf shared.function:prompt-dialog -* @description discuss difference b/t this and other modals -*/ - -export default -angular.module('PromptDialog', ['Utilities']) - .factory('Prompt', [ 'AppStrings', - function (strings) { - return function (params) { - - var dialog = angular.element(document.getElementById('prompt-modal')), - scope = dialog.scope(), cls, local_backdrop; - - scope.promptHeader = params.hdr; - scope.promptResourceName = params.resourceName; - scope.promptBody = params.body; - scope.promptAction = params.action; - scope.promptActionText = (params.actionText === null || params.actionText === undefined || params.actionText === '') ? strings.get('YES') : params.actionText; - scope.cancelActionText = (params.cancelText === null || params.cancelText === undefined || params.cancelText === '') ? strings.get('CANCEL') : params.cancelText; - scope.hideActionButton = params.hideActionButton ? true : false; - - local_backdrop = (params.backdrop === undefined) ? "static" : params.backdrop; - - cls = (params['class'] === null || params['class'] === undefined) ? 'Modal-errorButton' : params['class']; - - $('#prompt_action_btn').removeClass('Modal-errorButton Modal-primaryButton').addClass(cls); - - // bootstrap modal's have an open defect with disallowing tab index's of the background of the modal - // This will keep the tab indexing on the modal's focus. This is to fix an issue with tabbing working when - // the user is attempting to delete something. Might need to be checked for other occurances of the bootstrap - // modal other than deleting - function disableTabModalShown() { - - $('.modal').on('shown.bs.modal', function() { - - var modal = $(this), - focusableChildren = modal.find('a[href], a[data-dismiss], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]'), - numElements = focusableChildren.length, - currentIndex = 0, - focus, - focusPrevious, - focusNext; - - $(document.activeElement).blur(); - - focus = function() { - var focusableElement = focusableChildren[currentIndex]; - if (focusableElement) { - focusableElement.focus(); - } - }; - - focusPrevious = function () { - currentIndex--; - if (currentIndex < 0) { - currentIndex = numElements - 1; - } - - focus(); - - return false; - }; - - focusNext = function () { - currentIndex++; - if (currentIndex >= numElements) { - currentIndex = 0; - } - - focus(); - - return false; - }; - - $(document).on('keydown', function (e) { - - if (e.keyCode === 9 && e.shiftKey) { - e.preventDefault(); - focusPrevious(); - } - else if (e.keyCode === 9) { - e.preventDefault(); - focusNext(); - } - }); - - $(this).focus(); - }); - - $('.modal').on('hidden.bs.modal', function() { - $(document).unbind('keydown'); - }); - } - - - $('#prompt-modal').off('hidden.bs.modal'); - $('#prompt-modal').modal({ - backdrop: 'static', - keyboard: true, - show: true - }); - disableTabModalShown(); - - }; - } - ]); diff --git a/awx/ui/client/src/shared/prompt/prompt.less b/awx/ui/client/src/shared/prompt/prompt.less deleted file mode 100644 index b2ad0108031a..000000000000 --- a/awx/ui/client/src/shared/prompt/prompt.less +++ /dev/null @@ -1,29 +0,0 @@ -.Prompt-bodyQuery { - margin-bottom: 20px; - color: @default-interface-txt; - word-break: break-word; -} - -.Prompt-bodyTarget { - color: @default-data-txt; - word-break: break-word; -} - -.Prompt-bodyNote { - margin: 20px 0; - color: @default-interface-txt; -} - -.Prompt-bodyNote--emphasis { - text-transform: uppercase; - color: @default-err; -} - -.Prompt-emphasis { - font-weight: bold; - text-transform: uppercase; -} - -.Prompt-warningResourceTitle { - margin-right: 10px; -} diff --git a/awx/ui/client/src/shared/rbacUiControl.js b/awx/ui/client/src/shared/rbacUiControl.js deleted file mode 100644 index b65c6c57bdb9..000000000000 --- a/awx/ui/client/src/shared/rbacUiControl.js +++ /dev/null @@ -1,32 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - angular.module('rbacUiControl', []) - .service('rbacUiControlService', ['$q', 'GetBasePath', 'Rest', 'Wait', function($q, GetBasePath, Rest, Wait){ - this.canAdd = function(apiPath) { - var canAddVal = $q.defer(); - - if (/api\/v[0-9]+\//.test(apiPath)) { - Rest.setUrl(apiPath); - } else { - Rest.setUrl(GetBasePath(apiPath)); - } - - Wait("start"); - Rest.options() - .then(({data}) => { - if (data.actions.POST) { - canAddVal.resolve({canAdd: true, options: data}); - } else { - canAddVal.resolve({canAdd: false}); - } - Wait("stop"); - }); - - return canAddVal.promise; - }; - }]); diff --git a/awx/ui/client/src/shared/smart-search/django-search-model.class.js b/awx/ui/client/src/shared/smart-search/django-search-model.class.js deleted file mode 100644 index 3809e47a316a..000000000000 --- a/awx/ui/client/src/shared/smart-search/django-search-model.class.js +++ /dev/null @@ -1,50 +0,0 @@ -export default -class DjangoSearchModel { - /* - @property name - supplied model name - @property base { - field: { - type: 'string' // string, bool, field, choice, datetime, - label: 'Label', // Capitalized - help_text: 'Some helpful descriptive text' - } - } - @@property related ['field' ...] - */ - constructor(name, baseFields, relatedSearchFields) { - function trimRelated(relatedSearchField){ - return relatedSearchField.replace(/\__search$/, ""); - } - this.name = name; - this.searchExamples = []; - this.related = _.uniq(_.map(relatedSearchFields, trimRelated)); - // Remove "object" type fields from this list - for (var key in baseFields) { - if (baseFields.hasOwnProperty(key)) { - if (baseFields[key].type === 'object'){ - delete baseFields[key]; - } - } - } - delete baseFields.url; - this.base = baseFields; - if(baseFields.id) { - this.searchExamples.push("id:>10"); - } - // Loop across the base fields and try find one of type = string and one of type = datetime - let stringFound = false, - dateTimeFound = false; - - _.forEach(baseFields, (value, key) => { - if(!stringFound && value.type === 'string') { - this.searchExamples.push(key + ":foobar"); - stringFound = true; - } - if(!dateTimeFound && value.type === 'datetime') { - this.searchExamples.push(key + ":>=2000-01-01T00:00:00Z"); - this.searchExamples.push(key + ":<2000-01-01"); - dateTimeFound = true; - } - }); - } -} diff --git a/awx/ui/client/src/shared/smart-search/main.js b/awx/ui/client/src/shared/smart-search/main.js deleted file mode 100644 index e7aaf825a72c..000000000000 --- a/awx/ui/client/src/shared/smart-search/main.js +++ /dev/null @@ -1,13 +0,0 @@ -import directive from './smart-search.directive'; -import controller from './smart-search.controller'; -import service from './queryset.service'; -import DjangoSearchModel from './django-search-model.class'; -import smartSearchService from './smart-search.service'; - -export default -angular.module('SmartSearchModule', []) - .directive('smartSearch', directive) - .controller('SmartSearchController', controller) - .service('QuerySet', service) - .service('SmartSearchService', smartSearchService) - .constant('DjangoSearchModel', DjangoSearchModel); diff --git a/awx/ui/client/src/shared/smart-search/queryset.service.js b/awx/ui/client/src/shared/smart-search/queryset.service.js deleted file mode 100644 index cb0b6087fc08..000000000000 --- a/awx/ui/client/src/shared/smart-search/queryset.service.js +++ /dev/null @@ -1,512 +0,0 @@ -function searchWithoutKey (term, singleSearchParam = null) { - if (singleSearchParam) { - return { [singleSearchParam]: `search=${encodeURIComponent(term)}` }; - } - return { search: encodeURIComponent(term) }; -} - -function QuerysetService ($q, Rest, ProcessErrors, $rootScope, Wait, DjangoSearchModel, SmartSearchService) { - return { - // kick off building a model for a specific endpoint - // this is usually a list's basePath - // unified_jobs is the exception, where we need to fetch many subclass OPTIONS and summary_fields - initFieldset(path, name) { - let defer = $q.defer(); - defer.resolve(this.getCommonModelOptions(path, name)); - return defer.promise; - }, - getCommonModelOptions(path, name) { - let resolve, base, - defer = $q.defer(); - - this.url = path; - resolve = this.options(path) - .then((res) => { - base = res.data.actions.GET; - let relatedSearchFields = res.data.related_search_fields; - defer.resolve({ - models: { - [name]: new DjangoSearchModel(name, base, relatedSearchFields) - }, - options: res - }); - }); - return defer.promise; - }, - replaceDefaultFlags (value) { - if (value) { - value = value.toString().replace(/__icontains_DEFAULT/g, "__icontains"); - value = value.toString().replace(/__search_DEFAULT/g, "__search"); - } - - return value; - }, - replaceEncodedTokens(value) { - return decodeURIComponent(value).replace(/"|'/g, ""); - }, - encodeTerms (values, key) { - key = this.replaceDefaultFlags(key); - - if (!Array.isArray(values)) { - values = [values]; - } - - return values - .map(value => { - value = this.replaceDefaultFlags(value); - value = this.replaceEncodedTokens(value); - return [key, value]; - }); - - }, - // encodes ui-router params from {operand__key__comparator: value} pairs to API-consumable URL - encodeQueryset(params) { - if (typeof params !== 'object') { - return ''; - } - - return _.reduce(params, (result, value, key) => { - if (result !== '?') { - result += '&'; - } - - const encodedTermString = this.encodeTerms(value, key) - .map(([key, value]) => `${key}=${value}`) - .join('&'); - - return result += encodedTermString; - }, '?'); - }, - // like encodeQueryset, but return an actual unstringified API-consumable http param object - encodeQuerysetObject(params) { - return _.reduce(params, (obj, value, key) => { - const encodedTerms = this.encodeTerms(value, key); - - for (let encodedIndex in encodedTerms) { - const [encodedKey, encodedValue] = encodedTerms[encodedIndex]; - obj[encodedKey] = obj[encodedKey] || []; - obj[encodedKey].push(encodedValue); - } - - return obj; - }, {}); - }, - // encodes a ui smart-search param to a django-friendly param - // operand:key:comparator:value => {operand__key__comparator: value} - encodeParam({ term, relatedSearchTerm, searchTerm, singleSearchParam }){ - // Assumption here is that we have a key and a value so the length - // of the paramParts array will be 2. [0] is the key and [1] the value - let paramParts = SmartSearchService.splitTermIntoParts(term); - let keySplit = paramParts[0].split('.'); - let exclude = false; - let lessThanGreaterThan = paramParts[1].match(/^(>|<).*$/) ? true : false; - if(keySplit[0].match(/^-/g)) { - exclude = true; - keySplit[0] = keySplit[0].replace(/^-/, ''); - } - let paramString = exclude ? "not__" : ""; - let valueString = paramParts[1]; - - if(keySplit.length === 1) { - if(searchTerm && !lessThanGreaterThan) { - if(singleSearchParam) { - paramString += keySplit[0] + '__icontains'; - } - else { - paramString += keySplit[0] + '__icontains_DEFAULT'; - } - } - else if(relatedSearchTerm) { - if(singleSearchParam) { - paramString += keySplit[0]; - } - else { - paramString += keySplit[0] + '__search_DEFAULT'; - } - } - else { - paramString += keySplit[0]; - } - } - else { - paramString += keySplit.join('__'); - } - - if(lessThanGreaterThan) { - if(paramParts[1].match(/^>=.*$/)) { - paramString += '__gte'; - valueString = valueString.replace(/^(>=)/,""); - } - else if(paramParts[1].match(/^<=.*$/)) { - paramString += '__lte'; - valueString = valueString.replace(/^(<=)/,""); - } - else if(paramParts[1].match(/^<.*$/)) { - paramString += '__lt'; - valueString = valueString.replace(/^(<)/,""); - } - else if(paramParts[1].match(/^>.*$/)) { - paramString += '__gt'; - valueString = valueString.replace(/^(>)/,""); - } - } - - if(singleSearchParam) { - return {[singleSearchParam]: paramString + "=" + valueString}; - } - else { - return {[paramString] : encodeURIComponent(valueString)}; - } - }, - // decodes a django queryset param into a ui smart-search tag or set of tags - decodeParam(value, key){ - - let decodeParamString = function(searchString) { - if(key === 'search') { - // Don't include 'search:' in the search tag - return decodeURIComponent(`${searchString}`); - } - else { - key = key.toString().replace(/__icontains_DEFAULT/g, ""); - key = key.toString().replace(/__search_DEFAULT/g, ""); - let split = key.split('__'); - let decodedParam = searchString; - let exclude = false; - if(key.startsWith('not__')) { - exclude = true; - split = split.splice(1, split.length); - } - if(key.endsWith('__gt')) { - decodedParam = '>' + decodedParam; - split = split.splice(0, split.length-1); - } - else if(key.endsWith('__lt')) { - decodedParam = '<' + decodedParam; - split = split.splice(0, split.length-1); - } - else if(key.endsWith('__gte')) { - decodedParam = '>=' + decodedParam; - split = split.splice(0, split.length-1); - } - else if(key.endsWith('__lte')) { - decodedParam = '<=' + decodedParam; - split = split.splice(0, split.length-1); - } - - let uriDecodedParam = decodeURIComponent(decodedParam); - - return exclude ? `-${split.join('.')}:${uriDecodedParam}` : `${split.join('.')}:${uriDecodedParam}`; - } - }; - - if (Array.isArray(value)){ - value = _.uniq(_.flattenDeep(value)); - return _.map(value, (item) => { - return decodeParamString(item); - }); - } - else { - return decodeParamString(value); - } - }, - // encodes a django queryset for ui-router's URLMatcherFactory - // {operand__key__comparator: value, } => 'operand:key:comparator:value;...' - // value.isArray expands to: - // {operand__key__comparator: [value1, value2], } => 'operand:key:comparator:value1;operand:key:comparator:value1...' - encodeArr(params) { - let url; - url = _.reduce(params, (result, value, key) => { - return result.concat(encodeUrlString(value, key)); - }, []); - - return url.join(';'); - - // {key:'value'} => 'key:value' - // {key: [value1, value2, ...]} => ['key:value1', 'key:value2'] - function encodeUrlString(value, key){ - if (Array.isArray(value)){ - value = _.uniq(_.flattenDeep(value)); - return _.map(value, (item) => { - return `${key}:${item}`; - }); - } - else { - return `${key}:${value}`; - } - } - }, - // decodes a django queryset for ui-router's URLMatcherFactory - // 'operand:key:comparator:value,...' => {operand__key__comparator: value, } - decodeArr(arr) { - let params = {}; - - if (!arr) { - return params; - } - - _.forEach(arr.split(';'), (item) => { - let key = item.split(':')[0], - value = item.split(':')[1]; - if(!params[key]){ - params[key] = value; - } - else if (Array.isArray(params[key])){ - params[key] = _.uniq(_.flattenDeep(params[key])); - params[key].push(value); - } - else { - params[key] = [params[key], value]; - } - }); - return params; - }, - // REST utilities - options(endpoint) { - Rest.setUrl(endpoint); - return Rest.options(endpoint); - }, - search(endpoint, params) { - Wait('start'); - this.url = `${endpoint}${this.encodeQueryset(params)}`; - Rest.setUrl(this.url); - - return Rest.get() - .then(function(response) { - Wait('stop'); - - if (response - .headers('X-UI-Max-Events') !== null) { - response.data.maxEvents = response. - headers('X-UI-Max-Events'); - } - - return response; - }) - .catch(function(response) { - Wait('stop'); - - this.error(response.data, response.status); - - throw response; - }.bind(this)); - }, - error(data, status) { - if(data && data.detail){ - let error = typeof data.detail === "string" ? data.detail : JSON.parse(data.detail); - - if(_.isArray(error)){ - data.detail = error[0]; - } - } - ProcessErrors($rootScope, data, status, null, { - hdr: 'Error!', - msg: `Invalid search term entered. GET returned: ${status}` - }); - }, - // Removes state definition defaults and pagination terms - stripDefaultParams(params, defaultParams) { - if (!params) { - return []; - } - if(defaultParams) { - let stripped =_.pick(params, (value, key) => { - // setting the default value of a term to null in a state definition is a very explicit way to ensure it will NEVER generate a search tag, even with a non-default value - return defaultParams[key] !== value && key !== 'order_by' && key !== 'page' && key !== 'page_size' && defaultParams[key] !== null; - }); - let strippedCopy = _.cloneDeep(stripped); - if(_.keys(_.pick(defaultParams, _.keys(strippedCopy))).length > 0){ - for (var key in strippedCopy) { - if (strippedCopy.hasOwnProperty(key)) { - let value = strippedCopy[key]; - if(_.isArray(value)){ - let index = _.indexOf(value, defaultParams[key]); - value = value.splice(index, 1)[0]; - } - } - } - stripped = strippedCopy; - } - return _(strippedCopy).map(this.decodeParam).flatten().value(); - } - else { - return _(params).map(this.decodeParam).flatten().value(); - } - }, - mergeQueryset (queryset, additional, singleSearchParam) { - const space = '%20and%20'; - - const merged = _.merge({}, queryset, additional, (objectValue, sourceValue, key, object) => { - if (!(object[key] && object[key] !== sourceValue)) { - // // https://lodash.com/docs/3.10.1#each - // If this returns undefined merging is handled by default _.merge algorithm - return undefined; - } - - if (_.isArray(object[key])) { - object[key].push(sourceValue); - return object[key]; - } - - if (singleSearchParam) { - if (!object[key]) { - return sourceValue; - } - - const singleSearchParamKeys = object[key].split(space); - - if (_.includes(singleSearchParamKeys, sourceValue)) { - return object[key]; - } - - return `${object[key]}${space}${sourceValue}`; - } - - // Start the array of keys - return [object[key], sourceValue]; - }); - - return merged; - }, - getSearchInputQueryset (searchInput, isFilterableBaseField = null, isRelatedField = null, isAnsibleFactField = null, singleSearchParam = null) { - // XXX Should find a better approach than passing in the two 'is...Field' callbacks XXX - const space = '%20and%20'; - let params = {}; - - // Remove leading/trailing whitespace if there is any - const terms = (searchInput) ? searchInput.trim() : ''; - - if (!(terms && terms !== '')) { - return; - } - - let splitTerms; - - if (singleSearchParam === 'host_filter') { - splitTerms = SmartSearchService.splitFilterIntoTerms(terms); - } else { - splitTerms = SmartSearchService.splitSearchIntoTerms(terms); - } - - const combineSameSearches = (a, b) => { - if (!a) { - return undefined; - } - - if (_.isArray(a)) { - return a.concat(b); - } - - if (singleSearchParam) { - return `${a}${space}${b}`; - } - - return [a, b]; - }; - - _.each(splitTerms, term => { - const termParts = SmartSearchService.splitTermIntoParts(term); - let termParams; - - if (termParts.length === 1) { - termParams = searchWithoutKey(term, singleSearchParam); - } else if ((isAnsibleFactField && isAnsibleFactField(termParts)) || (isFilterableBaseField && isFilterableBaseField(termParts))) { - termParams = this.encodeParam({ term, singleSearchParam, searchTerm: true }); - } else if (isRelatedField && isRelatedField(termParts)) { - termParams = this.encodeParam({ term, singleSearchParam, relatedSearchTerm: true }); - } else { - termParams = searchWithoutKey(term, singleSearchParam); - } - - params = _.merge(params, termParams, combineSameSearches); - }); - - return params; - }, - removeTermsFromQueryset(queryset, term, isFilterableBaseField, isRelatedField = null, isAnsibleFactField = null, singleSearchParam = null) { - const modifiedQueryset = _.cloneDeep(queryset); - - const removeSingleTermFromQueryset = (value, key) => { - const space = '%20and%20'; - - if (Array.isArray(modifiedQueryset[key])) { - modifiedQueryset[key] = modifiedQueryset[key].filter(item => item !== value); - if (modifiedQueryset[key].length < 1) { - delete modifiedQueryset[key]; - } - } else if (singleSearchParam && _.get(modifiedQueryset, singleSearchParam, []).includes(space)) { - const searchParamParts = modifiedQueryset[singleSearchParam].split(space); - // The value side of each paramPart might have been encoded in - // SmartSearch.splitFilterIntoTerms - _.each(searchParamParts, (paramPart, paramPartIndex) => { - searchParamParts[paramPartIndex] = decodeURIComponent(paramPart); - }); - - const paramPartIndex = searchParamParts.indexOf(value); - - if (paramPartIndex !== -1) { - searchParamParts.splice(paramPartIndex, 1); - } - - modifiedQueryset[singleSearchParam] = searchParamParts.join(space); - - } else { - delete modifiedQueryset[key]; - } - }; - - const termParts = SmartSearchService.splitTermIntoParts(term); - - let removed; - - if (termParts.length === 1) { - removed = searchWithoutKey(term, singleSearchParam); - } else if ((isAnsibleFactField && isAnsibleFactField(termParts)) || (isFilterableBaseField && isFilterableBaseField(termParts))) { - removed = this.encodeParam({ term, singleSearchParam, searchTerm: true }); - } else if (isRelatedField && isRelatedField(termParts)) { - removed = this.encodeParam({ term, singleSearchParam, relatedSearchTerm: true }); - } else { - removed = searchWithoutKey(term, singleSearchParam); - } - - if (!removed) { - removed = searchWithoutKey(termParts[termParts.length - 1], singleSearchParam); - } - - _.each(removed, removeSingleTermFromQueryset); - - return modifiedQueryset; - }, - createSearchTagsFromQueryset(queryset, defaultParams = null, singleSearchParam = null) { - const space = '%20and%20'; - const modifiedQueryset = angular.copy(queryset); - - let searchTags = []; - - if (singleSearchParam && modifiedQueryset[singleSearchParam]) { - const searchParam = modifiedQueryset[singleSearchParam].split(space); - delete modifiedQueryset[singleSearchParam]; - - $.each(searchParam, (index, param) => { - const paramParts = decodeURIComponent(param).split(/=(.+)/); - const reconstructedSearchString = this.decodeParam(paramParts[1], paramParts[0]); - - searchTags.push(reconstructedSearchString); - }); - } - - return searchTags.concat(this.stripDefaultParams(modifiedQueryset, defaultParams)); - } - }; -} - -QuerysetService.$inject = [ - '$q', - 'Rest', - 'ProcessErrors', - '$rootScope', - 'Wait', - 'DjangoSearchModel', - 'SmartSearchService', -]; - -export default QuerysetService; diff --git a/awx/ui/client/src/shared/smart-search/smart-search.block.less b/awx/ui/client/src/shared/smart-search/smart-search.block.less deleted file mode 100644 index cd9749044084..000000000000 --- a/awx/ui/client/src/shared/smart-search/smart-search.block.less +++ /dev/null @@ -1,247 +0,0 @@ -@import "../branding/colors.default.less"; -.SmartSearch { - padding-left: 15px; - padding-right: 15px; -} - -.SmartSearch-form { - width: 100%; -} - -.SmartSearch-bar { - display: flex; - padding: 0; - font-size: 12px; - align-items: stretch; - line-height: 20px; - width: 50%; -} - -.SmartSearch-bar--fullWidth { - width: 100%; -} - -.SmartSearch-tags{ - padding-left: 0px; -} - -.SmartSearch-bar i { - font-size: 16px; - color: @default-icon; -} - -.SmartSearch-searchTermContainer { - flex: initial; - flex-grow: 1; - border: 1px solid @b7grey; - border-radius: 4px; - display: flex; - background-color: @default-bg; - position: relative; - height: 34px; -} - -.SmartSearch-searchTermContainer.is-open { - border-bottom-right-radius: 0; -} - -.SmartSearch-input { - flex: 1 0 auto; - margin: 0 10px; - border: none; - font-size: 14px; - height: 100%; - width: 100%; -} - -.SmartSearch-input:focus, -.SmartSearch-input:active { - outline: 0; -} - -.SmartSearch-searchTermContainer input:placeholder-shown { - color: @default-icon !important; - text-transform: uppercase; -} - -.SmartSearch-searchButton { - flex: initial; - margin-left: auto; - padding: 8px 10px; - border-left: 1px solid @b7grey; - background-color: @default-bg; - cursor: pointer; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - z-index: 1; -} - -.SmartSearch-searchButton:hover { - background-color: @default-tertiary-bg; -} - -.SmartSearch-flexContainer { - display: flex; - width: 100%; - flex-wrap: wrap; -} - -.SmartSearch-tagContainer { - display: flex; - max-width: 100%; - margin-top: 10px; -} - -.SmartSearch-tag { - border-radius: 5px; - padding: 2px 10px; - margin: 0px; - font-size: 12px; - color: @default-interface-txt; - background-color: @default-bg; - margin-right: 10px; - max-width: 100%; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - height: 20px; -} - -.SmartSearch-tag--deletable { - margin-right: 0px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - border-right: 0; - max-width: ~"calc(100% - 23px)"; - background-color: @default-link; - color: @default-bg; - margin-right: 10px; -} - -.SmartSearch-deleteContainer { - background-color: @default-link!important; - color: white; - background-color: @default-bg; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - padding: 0 5px; - margin: 0px; - align-items: center; - display: flex; - cursor: pointer; - height: 20px; -} - -.SmartSearch-tagDelete { - font-size: 13px; -} - -.SmartSearch-name { - flex: initial; - max-width: 100%; -} - -.SmartSearch-tag--deletable > .SmartSearch-name { - max-width: ~"calc(100% - 23px)"; -} - -.SmartSearch-deleteContainer:hover, -{ - border-color: @default-err; - background-color: @default-err!important; -} - -.SmartSearch-deleteContainer:hover > .SmartSearch-tagDelete { - color: @default-bg; -} -.SmartSearch-clearAll{ - font-size: 10px; - padding-top: 14px; -} -.SmartSearch-keyToggle { - margin-right: auto; - margin-left: 20px; - text-transform: uppercase; - background-color: @default-bg; - border-radius: 5px; - color: @default-interface-txt; - border: 1px solid @b7grey; - cursor: pointer; - min-width: 70px; - height: 34px; - line-height: 20px; -} - -.SmartSearch-keyToggle:hover { - background-color: @default-tertiary-bg; -} - -.SmartSearch-keyToggle.is-active { - background-color: @default-link; - border-color: @default-link; - color: @default-bg; - &:hover{ - background-color: @default-link-hov; - } -} - -.SmartSearch-keyPane { - max-height: 215px; - overflow: auto; - margin: 10px 0 0 0; - font-size: 12px; - width: 100%; - padding: 20px; - border-radius: 4px; - border: 1px solid @d7grey; - background-color: @login-notice-bg; - color: @login-notice-text; - position: relative; -} - -.SmartSearch-keyRow { - margin-bottom: 15px; -} - -.SmartSearch-keyRow:last-child { - margin-bottom: 0; -} - -.SmartSearch-keyName { - flex: 1 0 auto; - text-transform: uppercase; - font-weight: bold; - padding-bottom: 3px; -} - -.SmartSearch-keyComparators { - flex: 1 0 auto; -} - -.SmartSearch-keyPane--exit { - background-color: @login-notice-bg; -} - -.SmartSearch-examples { - display: flex; - flex-wrap: wrap; -} - -.SmartSearch-examples--title { - margin-right: 5px; -} - -.SmartSearch-examples--search { - color: @default-err; - background-color: @default-bg; - border: 1px solid @default-border; - border-radius: 5px; - padding: 0px 5px; - margin-right: 5px; -} - -@media (max-width: 700px) { - .SmartSearch-bar { - width: 100%; - } -} diff --git a/awx/ui/client/src/shared/smart-search/smart-search.controller.js b/awx/ui/client/src/shared/smart-search/smart-search.controller.js deleted file mode 100644 index ad14dd53448a..000000000000 --- a/awx/ui/client/src/shared/smart-search/smart-search.controller.js +++ /dev/null @@ -1,272 +0,0 @@ -function SmartSearchController ( - $scope, - $state, - $stateParams, - $transitions, - configService, - GetBasePath, - i18n, - qs -) { - const searchKey = `${$scope.iterator}_search`; - const optionsKey = `${$scope.list.iterator}_options`; - - let path; - let defaults; - let queryset; - let transitionSuccessListener; - - configService.getConfig() - .then(config => init(config)); - - function init (config) { - let version; - - try { - [version] = config.version.split('-'); - } catch (err) { - version = 'latest'; - } - - $scope.documentationLink = `http://docs.ansible.com/ansible-tower/${version}/html/userguide/search_sort.html`; - $scope.searchPlaceholder = i18n._('Search'); - - if ($scope.defaultParams) { - defaults = $scope.defaultParams; - } else { - // steps through the current tree of $state configurations, grabs default search params - const stateConfig = _.find($state.$current.path, step => _.has(step, `params.${searchKey}`)); - defaults = stateConfig.params[searchKey].config.value; - } - - if ($scope.querySet) { - queryset = _.cloneDeep($scope.querySet); - } else { - queryset = $state.params[searchKey]; - } - - path = GetBasePath($scope.basePath) || $scope.basePath; - generateSearchTags(); - - qs.initFieldset(path, $scope.djangoModel) - .then((data) => { - $scope.models = data.models; - $scope.options = data.options.data; - $scope.keyFields = _.reduce(data.models[$scope.djangoModel].base, function(result, value, key) { - if (value.filterable) { - result.push(key); - } - return result; - }, []); - if ($scope.list) { - $scope.$emit(optionsKey, data.options); - } - }); - - function compareParams (a, b) { - for (let key in a) { - if (!(key in b) || a[key].toString() !== b[key].toString()) { - return false; - } - } - for (let key in b) { - if (!(key in a)) { - return false; - } - } - return true; - } - - if (transitionSuccessListener) { - transitionSuccessListener(); - } - - transitionSuccessListener = $transitions.onSuccess({}, trans => { - // State has changed - check to see if this is a param change - if (trans.from().name === trans.to().name) { - if (!compareParams(trans.params('from')[searchKey], trans.params('to')[searchKey])) { - // Params are not the same - we need to update the search. This should only - // happen when the user hits the forward/back browser navigation buttons. - queryset = trans.params('to')[searchKey]; - qs.search(path, queryset).then((res) => { - $scope.dataset = res.data; - $scope.collection = res.data.results; - $scope.$emit('updateDataset', res.data); - }); - - $scope.searchTerm = null; - generateSearchTags(); - } - } - }); - - $scope.$on('$destroy', transitionSuccessListener); - $scope.$watch('disableSearch', disableSearch => { - if (disableSearch) { - $scope.searchPlaceholder = i18n._('Cannot search running job'); - } else { - $scope.searchPlaceholder = i18n._('Search'); - } - }); - } - - function generateSearchTags () { - const { singleSearchParam } = $scope; - $scope.searchTags = qs.createSearchTagsFromQueryset(queryset, defaults, singleSearchParam); - } - - function revertSearch (queryToBeRestored) { - queryset = queryToBeRestored; - // https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic - // This transition will not reload controllers/resolves/views - // but will register new $stateParams[$scope.iterator + '_search'] terms - if (!$scope.querySet) { - $state.go('.', { [searchKey]: queryset }); - } - qs.search(path, queryset).then((res) => { - if ($scope.querySet) { - $scope.querySet = queryset; - } - $scope.dataset = res.data; - $scope.collection = res.data.results; - }); - - $scope.searchTerm = null; - - generateSearchTags(); - } - - $scope.toggleKeyPane = () => { - $scope.showKeyPane = !$scope.showKeyPane; - }; - - function isAnsibleFactField (termParts) { - const rootField = termParts[0].split('.')[0].replace(/^-/, ''); - return rootField === 'ansible_facts'; - } - - function isFilterableBaseField (termParts) { - const rootField = termParts[0].split('.')[0].replace(/^-/, ''); - const listName = $scope.list.name; - const baseFieldPath = `models.${listName}.base.${rootField}`; - const isBaseField = _.has($scope, `${baseFieldPath}`); - - const isFilterable = _.get($scope, `${baseFieldPath}.filterable`); - const isBaseModelRelatedSearchTermField = (_.get($scope, `${baseFieldPath}.type`) === 'field'); - - return isBaseField && !isBaseModelRelatedSearchTermField && isFilterable; - } - - function isRelatedField (termParts) { - const rootField = termParts[0].split('.')[0].replace(/^-/, ''); - const listName = $scope.list.name; - const baseRelatedTypePath = `models.${listName}.base.${rootField}.type`; - - const isRelatedSearchTermField = (_.contains($scope.models[listName].related, rootField)); - const isBaseModelRelatedSearchTermField = (_.get($scope, baseRelatedTypePath) === 'field'); - - return (isRelatedSearchTermField || isBaseModelRelatedSearchTermField); - } - - $scope.addTerms = terms => { - const { singleSearchParam } = $scope; - const unmodifiedQueryset = _.clone(queryset); - - const searchInputQueryset = qs.getSearchInputQueryset(terms, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam); - queryset = qs.mergeQueryset(queryset, searchInputQueryset, singleSearchParam); - - // Go back to the first page after a new search - delete queryset.page; - - // https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic - // This transition will not reload controllers/resolves/views but will register new - // $stateParams[searchKey] terms. - if (!$scope.querySet) { - $state.go('.', { [searchKey]: queryset }) - .then(() => { - // same as above in $scope.remove. For some reason deleting the page - // from the queryset works for all lists except lists in modals. - delete $stateParams[searchKey].page; - }); - } - - qs.search(path, queryset) - .then(({ data }) => { - if ($scope.querySet) { - $scope.querySet = queryset; - } - $scope.dataset = data; - $scope.collection = data.results; - }) - .catch(() => revertSearch(unmodifiedQueryset)); - - $scope.searchTerm = null; - - generateSearchTags(); - }; - // remove tag, merge new queryset, $state.go - $scope.removeTerm = index => { - const { singleSearchParam } = $scope; - const [term] = $scope.searchTags.splice(index, 1); - - queryset = qs.removeTermsFromQueryset(queryset, term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam); - - if (!$scope.querySet) { - $state.go('.', { [searchKey]: queryset }) - .then(() => { - // for some reason deleting a tag from a list in a modal does not - // remove the param from $stateParams. Here we'll manually check to make sure - // that that happened and remove it if it didn't. - const clearedParams = qs.removeTermsFromQueryset($stateParams[searchKey], term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam); - $stateParams[searchKey] = clearedParams; - }); - } - - qs.search(path, queryset) - .then(({ data }) => { - if ($scope.querySet) { - $scope.querySet = queryset; - } - $scope.dataset = data; - $scope.collection = data.results; - }); - - generateSearchTags(); - }; - - $scope.clearAllTerms = () => { - const cleared = _(defaults).omit(_.isNull).value(); - - delete cleared.page; - - queryset = cleared; - - if (!$scope.querySet) { - $state.go('.', { [searchKey]: queryset }); - } - - qs.search(path, queryset) - .then(({ data }) => { - if ($scope.querySet) { - $scope.querySet = queryset; - } - $scope.dataset = data; - $scope.collection = data.results; - }); - - $scope.searchTags = qs.stripDefaultParams(queryset, defaults); - }; -} - -SmartSearchController.$inject = [ - '$scope', - '$state', - '$stateParams', - '$transitions', - 'ConfigService', - 'GetBasePath', - 'i18n', - 'QuerySet', -]; - -export default SmartSearchController; diff --git a/awx/ui/client/src/shared/smart-search/smart-search.directive.js b/awx/ui/client/src/shared/smart-search/smart-search.directive.js deleted file mode 100644 index 6ae367a0c8cd..000000000000 --- a/awx/ui/client/src/shared/smart-search/smart-search.directive.js +++ /dev/null @@ -1,27 +0,0 @@ -export default ['templateUrl', - function(templateUrl) { - return { - restrict: 'E', - replace: false, - transclude: { - actions: '?div' // preferably would transclude an actions directive here - }, - scope: { - djangoModel: '@', - basePath: '@', - iterator: '@', - list: '=', - dataset: '=', - collection: '=', - searchTags: '=', - disableSearch: '=', - defaultParams: '=', - querySet: '=', - singleSearchParam: '@', - searchBarFullWidth: '=' - }, - controller: 'SmartSearchController', - templateUrl: templateUrl('shared/smart-search/smart-search') - }; - } -]; diff --git a/awx/ui/client/src/shared/smart-search/smart-search.partial.html b/awx/ui/client/src/shared/smart-search/smart-search.partial.html deleted file mode 100644 index a44a90f6499b..000000000000 --- a/awx/ui/client/src/shared/smart-search/smart-search.partial.html +++ /dev/null @@ -1,56 +0,0 @@ -
- -
-
- -
- - -
- -
-
-
- Key -
-
- -
-
-
-
-
- -
-
- {{tag}} -
-
- CLEAR ALL -
-
-
- -
-
-
-
- EXAMPLES: -
- -
-
-
- FIELDS: {{ field }}, -
-
- RELATED FIELDS: {{ relation }}, -
-
- {{ 'ADDITIONAL INFORMATION' | translate }}: - {{ 'For additional information on advanced search search syntax please see the Ansible Tower' | translate }} - {{ 'documentation' | translate }}. -
-
-
diff --git a/awx/ui/client/src/shared/smart-search/smart-search.service.js b/awx/ui/client/src/shared/smart-search/smart-search.service.js deleted file mode 100644 index 8e7b57271d09..000000000000 --- a/awx/ui/client/src/shared/smart-search/smart-search.service.js +++ /dev/null @@ -1,59 +0,0 @@ -export default [function() { - return { - /** - * For the Smart Host Filter, values with spaces are wrapped with double quotes on input. - * To avoid having these quoted values split up and treated as terms themselves, some - * work is done to encode quotes in quoted values and the spaces within those quoted - * values before calling to `splitSearchIntoTerms`. - */ - splitFilterIntoTerms (searchString) { - if (!searchString) { - return null; - } - - let groups = []; - let quoted; - - searchString.split(' ').forEach(substring => { - if (/:"/g.test(substring)) { - if (/"$/.test(substring)) { - groups.push(this.encode(substring)); - } else { - quoted = substring; - } - } else if (quoted) { - quoted += ` ${substring}`; - - if (/"/g.test(substring)) { - groups.push(this.encode(quoted)); - quoted = undefined; - } - } else { - groups.push(substring); - } - }); - - return this.splitSearchIntoTerms(groups.join(' ')); - }, - encode (string) { - string = string.replace(/'/g, '%27'); - - return string.replace(/("| )/g, match => encodeURIComponent(match)); - }, - splitSearchIntoTerms(searchString) { - return searchString.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g); - }, - splitTermIntoParts(searchTerm) { - let breakOnColon = searchTerm.match(/(?:[^:"]+|"[^"]*")+/g); - - if(breakOnColon.length > 2) { - // concat all the strings after the first one together - let stringsToJoin = breakOnColon.slice(1,breakOnColon.length); - return [breakOnColon[0], stringsToJoin.join(':')]; - } - else { - return breakOnColon; - } - } - }; -}]; diff --git a/awx/ui/client/src/shared/socket/main.js b/awx/ui/client/src/shared/socket/main.js deleted file mode 100644 index 3b38053762bc..000000000000 --- a/awx/ui/client/src/shared/socket/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import awFeatureDirective from './features.directive'; -import socketService from './socket.service'; - -export default - angular.module('socket', []) - // .directive('awFeature', awFeatureDirective) - .service('SocketService', socketService); diff --git a/awx/ui/client/src/shared/socket/socket.service.js b/awx/ui/client/src/shared/socket/socket.service.js deleted file mode 100644 index f58c2d69284c..000000000000 --- a/awx/ui/client/src/shared/socket/socket.service.js +++ /dev/null @@ -1,267 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import ReconnectingWebSocket from 'reconnectingwebsocket'; -export default -['$rootScope', '$location', '$log','$state', '$q', 'i18n', - function ($rootScope, $location, $log, $state, $q, i18n) { - var needsResubscribing = false, - socketPromise = $q.defer(), - needsRefreshAfterBlur; - return { - init: function() { - var self = this, - host = window.location.host, - protocol, - url; - - if($location.protocol() === 'http'){ - protocol = 'ws'; - } - if($location.protocol() === 'https'){ - protocol = 'wss'; - } - url = `${protocol}://${host}/websocket/`; - - // only toggle background tabbed sockets if the - // UI_LIVE_UPDATES_ENABLED flag is true in the settings file - if(window.liveUpdates){ - document.addEventListener('visibilitychange', function() { - $log.debug(document.visibilityState); - if(document.visibilityState === 'hidden'){ - window.liveUpdates = false; - } - else if(document.visibilityState === 'visible'){ - window.liveUpdates = true; - if(needsRefreshAfterBlur){ - $state.go('.', null, {reload: true}); - needsRefreshAfterBlur = false; - } - - } - }); - } - - - if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { - - $log.debug('Socket connecting to: ' + url); - self.socket = new ReconnectingWebSocket(url, null, { - timeoutInterval: 3000, - maxReconnectAttempts: 10 }); - - self.socket.onopen = function () { - $log.debug("Websocket connection opened. Socket readyState: " + self.socket.readyState); - socketPromise.resolve(); - self.checkStatus(); - if(needsResubscribing){ - self.subscribe(self.getLast()); - needsResubscribing = false; - } - - }; - - self.socket.onerror = function (error) { - self.checkStatus(); - $log.debug('Websocket Error Logged: ' + error); //log errors - }; - - self.socket.onconnecting = function () { - self.checkStatus(); - $log.debug('Websocket reconnecting'); - needsResubscribing = true; - }; - - self.socket.onclose = function () { - self.checkStatus(); - $log.debug(`Websocket disconnected`); - }; - - self.socket.onmessage = this.onMessage; - - return self.socket; - } - else { - // encountered expired token, redirect to login page - $rootScope.sessionTimer.expireSession('idle'); - $location.url('/login'); - } - }, - onMessage: function(e){ - // Function called when messages are received on by the UI from - // the API over the websocket. This will route each message to - // the appropriate controller for the current $state. - $log.debug('Received From Server: ' + e.data); - - var data = JSON.parse(e.data), str = ""; - - if(!window.liveUpdates && data.group_name !== "control" && $state.current.name !== "jobResult"){ - $log.debug('Message from server dropped: ' + e.data); - needsRefreshAfterBlur = true; - return; - } - - if(data.group_name==="jobs" && !('status' in data)){ - // we know that this must have been a - // summary complete message b/c status is missing. - // A an object w/ group_name === "jobs" AND a 'status' key - // means it was for the event: status_changed. - $log.debug('Job summary_complete ' + data.unified_job_id); - $rootScope.$broadcast('ws-jobs-summary', data); - return; - } - else if(data.group_name==="job_events"){ - // The naming scheme is "ws" then a - // dash (-) and the group_name, then the job ID - // ex: 'ws-jobs-' - str = `ws-${data.group_name}-${data.job}`; - } - else if(data.group_name==="project_update_events"){ - str = `ws-${data.group_name}-${data.project_update}`; - } - else if(data.group_name==="ad_hoc_command_events"){ - str = `ws-${data.group_name}-${data.ad_hoc_command}`; - } - else if(data.group_name==="system_job_events"){ - str = `ws-${data.group_name}-${data.system_job}`; - } - else if(data.group_name==="inventory_update_events"){ - str = `ws-${data.group_name}-${data.inventory_update}`; - } - else if(data.group_name==="control"){ - // As of v. 3.1.0, there is only 1 "control" - // message, which is for expiring the session if the - // session limit is breached. - $log.debug(data.reason); - $rootScope.sessionTimer.expireSession('session_limit'); - $state.go('signOut'); - } - else { - // The naming scheme is "ws" then a - // dash (-) and the group_name. - // ex: 'ws-jobs' - str = `ws-${data.group_name}`; - } - $rootScope.$broadcast(str, data); - }, - disconnect: function(){ - if(this.socket){ - this.socket.close(); - delete this.socket; - console.log("Socket deleted: "+this.socket); - } - }, - subscribe: function(state){ - // Subscribe is used to tell the API that the UI wants to - // listen for specific messages. A subscription object could - // look like {"groups":{"jobs": ["status_changed", "summary"]}. - // This is used by all socket-enabled $states - this.emit(JSON.stringify(state.data.socket)); - this.setLast(state); - }, - unsubscribe: function(state){ - // Unsubscribing tells the API that the user is no longer on - // on a socket-enabled page, and sends an empty groups object - // to the API: {"groups": {}}. - // This is used for all pages that are socket-disabled - if(this.requiresNewSubscribe(state)){ - this.emit(JSON.stringify(state.data.socket) || JSON.stringify({"groups": {}})); - } - this.setLast(state); - }, - setLast: function(state){ - this.last = state; - }, - getLast: function(){ - return this.last; - }, - requiresNewSubscribe(state){ - // This function is used for unsubscribing. If the last $state - // required an "unsubscribe", then we don't need to unsubscribe - // again, b/c the UI is already unsubscribed from all groups - if (this.getLast() !== undefined){ - if( _.isEmpty(state.data.socket.groups) && _.isEmpty(this.getLast().data.socket.groups)){ - return false; - } - else { - return true; - } - } - else { - return true; - } - }, - checkStatus: function() { - // Function for changing the socket indicator icon in the nav bar - var self = this; - if(self){ - if(self.socket){ - if (self.socket.readyState === 0 ) { - $rootScope.socketStatus = 'connecting'; - $rootScope.socketTip = i18n._(`Live events: attempting to connect to the ${$rootScope.BRAND_NAME} server.`); - } - else if (self.socket.readyState === 1){ - $rootScope.socketStatus = 'ok'; - $rootScope.socketTip = i18n._("Live events: connected. Pages containing job status information will automatically update in real-time."); - } - else if (self.socket.readyState === 2 || self.socket.readyState === 3 ){ - $rootScope.socketStatus = 'error'; - $rootScope.socketTip = i18n._(`Live events: error connecting to the ${$rootScope.BRAND_NAME} server.`); - } - return; - } - } - - }, - emit: function(data, callback) { - // Function used for sending objects to the API over the - // websocket. - var self = this; - socketPromise.promise.then(function(){ - if(self.socket.readyState === 0){ - $log.debug('Unable to send message, waiting 500ms to resend. Socket readyState: ' + self.socket.readyState); - setTimeout(function(){ - self.subscribe(self.getLast()); - }, 500); - } - else if(self.socket.readyState === 1){ - self.socket.send(data, function () { - var args = arguments; - self.scope.$apply(function () { - if (callback) { - callback.apply(self.socket, args); - } - }); - }); - $log.debug('Sent to Websocket Server: ' + data); - } - }); - }, - addStateResolve: function(state, id){ - // This function is used for add a state resolve to all states, - // socket-enabled AND socket-disabled, and whether the $state - // requires a subscribe or an unsubscribe - var self = this; - return socketPromise.promise.then(function(){ - if(!state.data || !state.data.socket){ - _.merge(state.data, {socket: {groups: {}}}); - self.unsubscribe(state); - } - else{ - ["job_events", "ad_hoc_command_events", "workflow_events", - "project_update_events", "inventory_update_events", - "system_job_events" - ].forEach(function(group) { - if(state.data && state.data.socket && state.data.socket.groups.hasOwnProperty(group)){ - state.data.socket.groups[group] = [id]; - } - }); - self.subscribe(state); - } - return true; - }); - } - }; - }]; diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js deleted file mode 100644 index 99dc4f6f995c..000000000000 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ /dev/null @@ -1,895 +0,0 @@ -/** - * @ngdoc interface - * @name stateDefinitions - * @description An API for generating a standard set of state definitions - * generateTree - builds a full list/form tree - * generateListNode - builds a single list node e.g. {name: 'projects', ...} - * generateFormNode - builds a form node definition e.g. {name: 'projects.add', ...} - * generateFormListDefinitions - builds form list definitions attached to a form node e.g. {name: 'projects.edit.permissions', ...} - * generateLookupNodes - Attaches to a form node. Builds an abstract '*.lookup' node with field-specific 'lookup.*' children e.g. {name: 'projects.add.lookup.organizations', ...} - */ - -export default ['$injector', '$stateExtender', '$log', 'i18n', -function($injector, $stateExtender, $log, i18n) { - return { - /** - * @ngdoc method - * @name stateDefinitions.generateTree - * @description intended for consumption by $stateProvider.state.lazyLoad in a placeholder node - * @param {object} params - { - parent: 'stateName', // the name of the top-most node of this tree - modes: ['add', 'edit'], // form modes to include in this state tree - list: 'InjectableListDefinition', - form: 'InjectableFormDefinition', - controllers: { - list: 'Injectable' || Object, - add: 'Injectable' || Object, - edit: 'Injectable' || Object, - } - * @returns {object} Promise which resolves to an object.state containing array of all state definitions in this tree - * e.g. {state: [{...}, {...}, ...]} - */ - generateTree: function(params) { - let form, list, formStates, listState, - states = []; - //return defer.promise; - return new Promise((resolve) => { - // returns array of the following states: - // resource.add, resource.edit - // resource.add.lookup, resource.add.lookup.* => [field in form.fields if field.type == 'lookup'] - // resource.edit.lookup, resource.edit.lookup.* => [field in form.fields if field.type == 'lookup'] - // resource.edit.* => [relationship in form.related] - if (params.list) { - list = $injector.get(params.list); - - listState = this.generateListNode(list, params); - states.push(listState); - } - if (params.form) { - // handle inconsistent typing of form definitions - // can be either an object or fn - form = $injector.get(params.form); - form = typeof(form) === 'function' ? form() : form; - - formStates = _.map(params.modes, (mode) => this.generateFormNode(mode, form, params)); - states = states.concat(_.flatten(formStates)); - } - - $log.debug('*** Generated State Tree', states); - resolve({ states: states }); - }); - }, - - /** - * @ngdoc method - * @name stateDefinitions.generateListNode - * @description builds single list node - * @params {object} list - list definition/configuration object - * @params {object} params - * @returns {object} a list state definition - */ - generateListNode: function(list, params) { - let state, - url = params.urls && params.urls.list ? params.urls.list : (params.url ? params.url : `/${list.name}`); - - // allows passed-in params to specify a custom templateUrl - // otherwise, use html returned by generateList.build() to fulfill templateProvider fn - function generateTemplateBlock() { - if (params.templates && params.templates.list) { - return params.templates.list; - } else { - return function(ListDefinition, generateList) { - let html = generateList.build({ - list: ListDefinition, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - // generateList.formView() inserts a ui-view="form" inside the list view's hierarchy - html = generateList.insertFormView() + html; - if(params.generateSchedulerView){ - html = generateList.insertSchedulerView() + html; - } - return html; - }; - } - } - - let views = params.views ? params.views : { - '@': { - // resolves to a variable property name: - // 'templateUrl' OR 'templateProvider' - [params.templates && params.templates.list ? 'templateUrl' : 'templateProvider']: generateTemplateBlock(), - controller: params.controllers.list, - } - }; - - state = $stateExtender.buildDefinition({ - searchPrefix: list.iterator, - name: params.parent, - url: url, - data: params.data, - ncyBreadcrumb: { - label: list.title - }, - resolve: { - Dataset: [params.list, 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ListDefinition: () => list - }, - views: views - }); - // allow passed-in params to override default resolve block - if (params.resolve && params.resolve.list) { - state.resolve = _.merge(state.resolve, params.resolve.list); - } - // allow passed-in params to override default ncyBreadcrumb property - if (params.ncyBreadcrumb) { - state.ncyBreadcrumb = params.ncyBreadcrumb; - } - if (list.search) { - state.params[`${list.iterator}_search`].value = _.merge(state.params[`${list.iterator}_search`].value, list.search); - } - return state; - }, - /** - * @ngdoc method - * @name stateDefinitions.generateFormNode - * @description builds a node of form states, e.g. resource.edit.** or resource.add.** - * @param {string} mode - 'add' || 'edit' - the form mode of this node - * @param {object} form - form definition/configuration object - * @returns {array} Array of state definitions required by form mode [{...}, {...}, ...] - */ - generateFormNode: function(mode, form, params) { - let formNode, - states = [], - url; - switch (mode) { - case 'add': - url = params.urls && params.urls.add ? params.urls.add : (params.url ? params.url : '/add'); - // breadcrumbName necessary for resources that are more than one word like - // job templates. form.name can't have spaces in it or it busts form gen - formNode = $stateExtender.buildDefinition({ - name: params.name || `${params.parent}.add`, - url: url, - ncyBreadcrumb: { - [params.parent ? 'parent' : null]: `${params.parent}`, - label: i18n.sprintf(i18n._("CREATE %s"), i18n._(`${form.breadcrumbName || form.name.toUpperCase()}`)) - }, - views: { - 'form': { - templateProvider: function(FormDefinition, GenerateForm) { - let form = typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'add', - related: false - }); - }, - controller: params.controllers.add - } - }, - resolve: { - 'FormDefinition': [params.form, function(definition) { - return definition; - }] - } - }); - if (params.resolve && params.resolve.add) { - formNode.resolve = _.merge(formNode.resolve, params.resolve.add); - } - break; - case 'edit': - url = params.urls && params.urls.edit ? params.urls.edit : (params.url ? params.url : `/:${form.name}_id`); - let breadcrumbLabel = params.breadcrumbs && params.breadcrumbs.edit ? params.breadcrumbs.edit : '{{parentObject.name || name}}'; - let formNodeState = { - name: params.name || `${params.parent}.edit`, - url: url, - ncyBreadcrumb: { - [params.parent ? 'parent' : null]: `${params.parent}`, - label: breadcrumbLabel - }, - views: { - 'form': { - templateProvider: function(FormDefinition, GenerateForm) { - let form = typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition; - return GenerateForm.buildHTML(form, { - mode: 'edit' - }); - }, - controller: params.controllers.edit - } - }, - resolve: { - FormDefinition: [params.form, function(definition) { - return definition; - }], - resourceData: ['FormDefinition', 'Rest', '$stateParams', 'GetBasePath', - function(FormDefinition, Rest, $stateParams, GetBasePath) { - let form, path; - form = typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition; - if (GetBasePath(form.basePath) === undefined && GetBasePath(form.stateTree) === undefined ){ - throw { name: 'NotImplementedError', message: `${form.name} form definition is missing basePath or stateTree property.` }; - } - else{ - path = (GetBasePath(form.basePath) || GetBasePath(form.stateTree) || form.basePath) + $stateParams[`${form.name}_id`]; - } - Rest.setUrl(path); - return Rest.get(); - } - ] - }, - }; - if (params.data && params.data.activityStreamTarget) { - formNodeState.data = {}; - formNodeState.data.activityStreamId = params.data.activityStreamId ? params.data.activityStreamId : params.data.activityStreamTarget + '_id'; - formNodeState.data.activityStreamTarget = params.data.activityStreamTarget; - } - formNode = $stateExtender.buildDefinition(formNodeState); - - if (params.resolve && params.resolve.edit) { - formNode.resolve = _.merge(formNode.resolve, params.resolve.edit); - } - break; - } - states.push(formNode); - states = states.concat(this.generateLookupNodes(form, formNode)).concat(this.generateFormListDefinitions(form, formNode, params)); - return states; - }, - /** - * @ngdoc method - * @name stateDefinitions.generateFormListDefinitions - * @description builds state definitions for a form's related lists, like notifications/permissions - * @param {object} form - form definition/configuration object - * @params {object} formStateDefinition - the parent form node - * @returns {array} Array of state definitions [{...}, {...}, ...] - */ - generateFormListDefinitions: function(form, formStateDefinition, params) { - function buildRbacUserTeamDirective(){ - let states = []; - - states.push($stateExtender.buildDefinition({ - name: `${formStateDefinition.name}.permissions.add`, - squashSearchUrl: true, - url: '/add-permissions', - params: { - project_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - }, - job_template_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - }, - workflow_template_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - }, - inventory_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - }, - credential_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - }, - organization_search: { - value: {order_by: 'name', page_size: '5', role_level: 'admin_role'}, - dynamic: true - } - }, - ncyBreadcrumb:{ - skip:true - }, - views: { - [`modal@${formStateDefinition.name}`]: { - template: `` - } - }, - resolve: { - jobTemplatesDataset: ['QuerySet', '$stateParams', 'GetBasePath', - function(qs, $stateParams, GetBasePath) { - let path = GetBasePath('job_templates'); - return qs.search(path, $stateParams.job_template_search); - } - ], - workflowTemplatesDataset: ['QuerySet', '$stateParams', 'GetBasePath', - function(qs, $stateParams, GetBasePath) { - let path = GetBasePath('workflow_job_templates'); - return qs.search(path, $stateParams.workflow_template_search); - } - ], - projectsDataset: ['ProjectList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - inventoriesDataset: ['InventoryList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - credentialsDataset: ['CredentialList', 'QuerySet', '$stateParams', 'GetBasePath', 'resourceData', 'Rest', '$q', - function(list, qs, $stateParams, GetBasePath, resourceData, Rest, $q) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - - if(resourceData.data.type === "team") { - $stateParams[`${list.iterator}_search`].organization = resourceData.data.organization; - } - - if(resourceData.data.type === "user") { - - let resolve = $q.defer(); - - let getMoreOrgs = function(data, arr) { - Rest.setUrl(data.next); - Rest.get() - .then(function (resData) { - if (data.next) { - getMoreOrgs(resData.data, arr.concat(resData.data.results)); - } else { - resolve.resolve(arr.concat(resData.data.results)); - } - }); - }; - - Rest.setUrl(GetBasePath('users') + `${resourceData.data.id}/organizations?page_size=200`); - Rest.get() - .then(function(resData) { - if (resData.data.next) { - getMoreOrgs(resData.data, resData.data.results); - } else { - resolve.resolve(resData.data.results); - } - }); - - return resolve.promise.then(function (organizations) { - if(organizations && organizations.length > 0) { - let orgIds = _.map(organizations, function(organization){ - return organization.id; - }); - - $stateParams[`${list.iterator}_search`].or__organization = 'null'; - $stateParams[`${list.iterator}_search`].or__organization__in = orgIds.join(); - - } - else { - $stateParams[`${list.iterator}_search`].organization = 'null'; - } - - return qs.search(path, $stateParams[`${list.iterator}_search`]); - }); - - } - else { - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - } - ], - organizationsDataset: ['OrganizationList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - }, - onExit: function($state) { - if ($state.transition) { - $('#add-permissions-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - }, - })); - return states; - } - - function buildRbacResourceDirective() { - let states = []; - - states.push($stateExtender.buildDefinition({ - name: `${formStateDefinition.name}.permissions.add`, - squashSearchUrl: true, - url: '/add-permissions', - params: { - user_search: { - value: { order_by: 'username', page_size: '5', is_superuser: false }, - dynamic: true, - }, - team_search: { - value: { order_by: 'name', page_size: '5' }, - dynamic: true - } - }, - views: { - [`modal@${formStateDefinition.name}`]: { - template: `` - } - }, - ncyBreadcrumb:{ - skip:true - }, - resolve: { - usersDataset: ['addPermissionsUsersList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams.user_search); - - } - ], - teamsDataset: ['addPermissionsTeamsList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams.team_search); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#add-permissions-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - }, - })); - return states; - } - - function buildNotificationState(field) { - let state, - list = field.include ? $injector.get(field.include) : field, - breadcrumbLabel = (field.iterator.replace('_', ' ') + 's').toUpperCase(); - state = $stateExtender.buildDefinition({ - searchPrefix: `${list.iterator}`, - name: `${formStateDefinition.name}.${list.iterator}s`, - url: `/${list.iterator}s`, - ncyBreadcrumb: { - parent: `${formStateDefinition.name}`, - label: `${breadcrumbLabel}` - }, - params: { - [list.iterator + '_search']: { - value: { order_by: field.order_by ? field.order_by : 'name' } - } - }, - views: { - 'related': { - templateProvider: function(FormDefinition, GenerateForm, $stateParams, SourcesFormDefinition) { - var form, html; - if($stateParams && $stateParams.inventory_source_id){ - form = SourcesFormDefinition; - } - else { - form = typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition; - } - html = GenerateForm.buildCollection({ - mode: 'edit', - related: `${list.iterator}s`, - form: form - }); - return html; - }, - controller: ['$scope', 'ListDefinition', 'Dataset', 'ToggleNotification', 'NotificationsListInit', 'GetBasePath', '$stateParams', - function($scope, list, Dataset, ToggleNotification, NotificationsListInit, GetBasePath, $stateParams) { - var url , params = $stateParams, id; - if(params.hasOwnProperty('project_id')){ - id = params.project_id; - url = GetBasePath('projects'); - } - if(params.hasOwnProperty('job_template_id')){ - id = params.job_template_id; - url = GetBasePath('job_templates'); - } - if(params.hasOwnProperty('workflow_job_template_id')){ - id = params.workflow_job_template_id; - url = GetBasePath('workflow_job_templates'); - } - if(params.hasOwnProperty('inventory_source_id')){ - id = params.inventory_source_id; - url = GetBasePath('inventory_sources'); - } - if(params.hasOwnProperty('organization_id')){ - id = params.organization_id; - url = GetBasePath('organizations'); - } - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - - NotificationsListInit({ - scope: $scope, - url: url, - id: id - }); - - $scope.$watch(`${list.iterator}_dataset`, function() { - // The list data has changed and we need to update which notifications are on/off - $scope.$emit('relatednotifications'); - }); - } - - $scope.toggleNotification = function(event, notifier_id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } - catch(e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: url + id, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - - init(); - - } - ] - } - }, - resolve: { - ListDefinition: () => { - return list; - }, - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - } - }); - return state; - } - - function buildRbacUserDirective() { - let states = []; - - states.push($stateExtender.buildDefinition({ - name: `${formStateDefinition.name}.users.add`, - squashSearchUrl: true, - url: '/add-user', - params: { - user_search: { - value: { order_by: 'username', page_size: '5' }, - dynamic: true, - } - }, - views: { - [`modal@${formStateDefinition.name}`]: { - template: `` - } - }, - ncyBreadcrumb:{ - skip:true - }, - resolve: { - usersDataset: ['addPermissionsUsersList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath(list.basePath) || GetBasePath(list.name); - return qs.search(path, $stateParams.user_search); - - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#add-permissions-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - }, - })); - return states; - } - - function buildListNodes(field) { - let states = []; - if(!field.skipGenerator) { - if(field.iterator === 'notification'){ - states.push(buildNotificationState(field)); - states = _.flatten(states); - } - else{ - states.push(buildListDefinition(field)); - if (field.iterator === 'permission' && field.actions && field.actions.add) { - if (form.name === 'user' || form.name === 'team'){ - states.push(buildRbacUserTeamDirective()); - } - else { - states.push(buildRbacResourceDirective()); - } - } - else if (field.iterator === 'user' && field.actions && field.actions.add) { - if(form.name === 'team' || form.name === 'organization') { - states.push(buildRbacUserDirective()); - } - } - } - } - - states = _.flatten(states); - return states; - } - - function buildListDefinition(field) { - let state, - list = field.include ? $injector.get(field.include) : field, - // Added this line specifically for Completed Jobs but should be OK - // for all the rest of the related tabs - breadcrumbLabel = (field.iterator.replace('_', ' ') + 's').toUpperCase(), - stateConfig = { - searchPrefix: `${list.iterator}`, - name: `${formStateDefinition.name}.${list.iterator}s`, - url: `/${list.iterator}s`, - ncyBreadcrumb: { - parent: `${formStateDefinition.name}`, - label: `${breadcrumbLabel}` - }, - params: { - [list.iterator + '_search']: { - value: { order_by: field.order_by ? field.order_by : 'name' } - }, - }, - views: { - 'related': { - templateProvider: function(FormDefinition, GenerateForm) { - let html = GenerateForm.buildCollection({ - mode: 'edit', - related: `${list.iterator}s`, - form: typeof(FormDefinition) === 'function' ? - FormDefinition() : FormDefinition - }); - return html; - } - } - }, - resolve: { - ListDefinition: () => { - return list; - }, - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { - // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field - let path, interpolator; - if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - } - }; - - if(params.controllers && params.controllers.related && params.controllers.related[field.name]) { - stateConfig.views.related.controller = params.controllers.related[field.name]; - } - else if(field.name === 'permissions') { - stateConfig.views.related.controller = 'PermissionsList'; - } - else { - // Generic controller - stateConfig.views.related.controller = ['$scope', 'ListDefinition', 'Dataset', - function($scope, list, Dataset) { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[`${list.iterator}s`] = $scope[`${list.iterator}_dataset`].results; - } - ]; - } - - state = $stateExtender.buildDefinition(stateConfig); - // appy any default search parameters in form definition - if (field.search) { - state.params[`${field.iterator}_search`].value = _.merge(state.params[`${field.iterator}_search`].value, field.search); - } - - return state; - } - return _(form.related).map(buildListNodes).flatten().value(); - }, - /** - * @ngdoc method - * @name stateDefinitions.generateLookupNode - * @description builds a node of child states for each lookup field in a form - * @param {object} form - form definition/configuration object - * @params {object} formStateDefinition - the parent form node - * @returns {array} Array of state definitions [{...}, {...}, ...] - */ - generateLookupNodes: function(form, formStateDefinition) { - - function buildFieldDefinition(field) { - - // Some lookup modals require some additional default params, - // namely organization and inventory_script, and insights - // credentials. If these params - // aren't set as default params out of the gate, then smart - // search will think they need to be set as search tags. - var params; - if(field.sourceModel === "organization"){ - params = { - page_size: '5', - role_level: 'admin_role' - }; - } - else if(field.sourceModel === "inventory_script"){ - params = { - page_size: '5', - role_level: 'admin_role', - organization: null - }; - } - else if(field.sourceModel === "insights_credential"){ - params = { - page_size: '5', - role_level: 'admin_role', - credential_type: null - }; - } - else if(field.sourceModel === 'host') { - params = { - page_size: '5' - }; - } - else { - params = { - page_size: '5', - role_level: 'use_role' - }; - } - - let state = $stateExtender.buildDefinition({ - searchPrefix: field.sourceModel, - //squashSearchUrl: true, @issue enable - name: `${formStateDefinition.name}.${field.sourceModel}`, - url: `/${field.sourceModel}?selected`, - // a lookup field's basePath takes precedence over generic list definition's basePath, if supplied - data: { - basePath: field.basePath || null, - formChildState: true - }, - params: { - [field.sourceModel + '_search']: { - value: params - } - }, - ncyBreadcrumb: { - skip: true - }, - views: { - 'modal': { - templateProvider: function(ListDefinition, generateList) { - let list_html = generateList.build({ - mode: 'lookup', - list: ListDefinition, - input_type: 'radio' - }); - return `${list_html}`; - - } - } - }, - resolve: { - ListDefinition: [field.list, function(list) { - let listClone = _.cloneDeep(list); - listClone.iterator = field.sourceModel; - return listClone; - }], - OrganizationId: ['ListDefinition', 'InventoriesService', '$stateParams', '$rootScope', - function(list, InventoriesService, $stateParams, $rootScope){ - if(list.iterator === 'inventory_script'){ - if($rootScope.$$childTail && - $rootScope.$$childTail.$resolve && - $rootScope.$$childTail.$resolve.hasOwnProperty('inventoryData')){ - return $rootScope.$$childTail.$resolve.inventoryData.summary_fields.organization.id; - } - else { - return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data.summary_fields.organization.id); - } - - } - else { - return; - } - }], - InsightsCredTypePK: ['ListDefinition', 'Rest', 'GetBasePath', 'ProcessErrors', - function(list, Rest, GetBasePath,ProcessErrors) { - if(list.iterator === 'insights_credential'){ - Rest.setUrl(GetBasePath('credential_types') + '?name=Insights'); - return Rest.get() - .then(({data}) => { - return data.results[0].id; - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get credential type data: ' + status - }); - }); - } - }], - Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', '$state', 'OrganizationId', 'InsightsCredTypePK', - (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope, $state, OrganizationId, InsightsCredTypePK) => { - // allow lookup field definitions to use interpolated $stateParams / $rootScope in basePath field - // the basePath on a form's lookup field will take precedence over the general model list's basepath - let path, interpolator; - if ($state.transition._targetState._definition.data && GetBasePath($state.transition._targetState._definition.data.basePath)) { - path = GetBasePath($state.transition._targetState._definition.data.basePath); - } else if ($state.transition._targetState._definition.data && $state.transition._targetState._definition.data.basePath) { - interpolator = $interpolate($state.transition._targetState._definition.data.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } else if (GetBasePath(list.basePath)) { - path = GetBasePath(list.basePath); - } else { - interpolator = $interpolate(list.basePath); - path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); - } - // Need to change the role_level here b/c organizations and inventory scripts - // don't have a "use_role", only "admin_role" and "read_role" - if(list.iterator === "organization"){ - if ($state.current.name.includes('inventories')) { - $stateParams[`${list.iterator}_search`].role_level = "inventory_admin_role"; - } else if ($state.current.name.includes('projects')) { - $stateParams[`${list.iterator}_search`].role_level = "project_admin_role"; - } else if ($state.current.name.includes('templates.addWorkflowJobTemplate') || $state.current.name.includes('templates.editWorkflowJobTemplate')) { - $stateParams[`${list.iterator}_search`].role_level = "workflow_admin_role"; - } - } - if(list.iterator === "inventory_script"){ - $stateParams[`${list.iterator}_search`].role_level = "admin_role"; - $stateParams[`${list.iterator}_search`].organization = OrganizationId; - } - if(list.iterator === "insights_credential"){ - $stateParams[`${list.iterator}_search`].role_level = "admin_role"; - $stateParams[`${list.iterator}_search`].credential_type = InsightsCredTypePK.toString() ; - } - - - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ] - }, - onExit: function($state) { - if ($state.transition) { - $('#form-modal').modal('hide'); - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - } - }, - }); - if (field.search) { - state.params[`${field.sourceModel}_search`].value = _.merge(state.params[`${field.sourceModel}_search`].value, field.search); - } - return state; - } - return _(form.fields).filter({ type: 'lookup' }).map(buildFieldDefinition).value(); - } - - }; - -}]; diff --git a/awx/ui/client/src/shared/stateExtender.provider.js b/awx/ui/client/src/shared/stateExtender.provider.js deleted file mode 100644 index 2ca49c3a76e0..000000000000 --- a/awx/ui/client/src/shared/stateExtender.provider.js +++ /dev/null @@ -1,75 +0,0 @@ -export default function($stateProvider) { - this.$get = function() { - return { - // attaches socket as resolvable if specified in state definition - addSocket: function(state){ - // The login route has a 'null' socket because it should - // neither subscribe or unsubscribe - if(state.data && state.data.socket!==null){ - if(!state.resolve){ - state.resolve = {}; - } - state.resolve.socket = ['SocketService', '$stateParams', - function(SocketService, $stateParams) { - SocketService.addStateResolve(state, $stateParams.id); - } - ]; - } - }, - // builds a state definition with default slaw - buildDefinition: function(state) { - let params, defaults, definition, - searchPrefix = state.searchPrefix ? `${state.searchPrefix}_search` : null, - route = state.route || state.url; - - if (searchPrefix) { - defaults = { - params: { - [searchPrefix]: { - value: { - page_size: "20", - order_by: "name" - }, - dynamic: true, - squash: false - } - } - }; - route = !state.squashSearchUrl ? `${route}?{${searchPrefix}:queryset}` : route; - params = state.params === undefined ? defaults.params : _.merge(defaults.params, state.params); - } else { - params = state.params; - } - - definition = { - name: state.name, - url: route, - abstract: state.abstract, - controller: state.controller, - templateUrl: state.templateUrl, - templateProvider: state.templateProvider, - resolve: state.resolve, - params: params, - data: state.data, - ncyBreadcrumb: state.ncyBreadcrumb, - onEnter: state.onEnter, - onExit: state.onExit, - template: state.template, - controllerAs: state.controllerAs, - views: state.views, - parent: state.parent, - redirectTo: state.redirectTo, - // new in uiRouter 1.0 - lazyLoad: state.lazyLoad, - }; - this.addSocket(definition); - return definition; - }, - // registers a state definition with $stateProvider service - addState: function(state) { - let definition = this.buildDefinition(state); - $stateProvider.state(state.name, definition); - } - }; - }; -} diff --git a/awx/ui/client/src/shared/template-url/main.js b/awx/ui/client/src/shared/template-url/main.js deleted file mode 100644 index 8c1c64185e54..000000000000 --- a/awx/ui/client/src/shared/template-url/main.js +++ /dev/null @@ -1,6 +0,0 @@ -import templateUrl from './template-url.factory'; - -export default - angular.module('templateUrl', []) - .factory('templateUrl', templateUrl); - diff --git a/awx/ui/client/src/shared/template-url/template-url.factory.js b/awx/ui/client/src/shared/template-url/template-url.factory.js deleted file mode 100644 index bcdd1d5e87b9..000000000000 --- a/awx/ui/client/src/shared/template-url/template-url.factory.js +++ /dev/null @@ -1,26 +0,0 @@ -// This function is accessible outside of angular -// -export function templateUrl(path) { - return _templateUrl(null, path); -} - -function _templateUrl($sce, path, isTrusted) { - isTrusted = isTrusted !== false; // defaults to true, can be passed in as false - var parts = ['', 'static/partials']; - parts.push(path); - - var url = parts.join('/') + '.partial.html'; - - if (isTrusted && $sce) { - url = $sce.trustAsResourceUrl(url); - } - - return url; -} - -export default - [ '$sce', - function($sce) { - return _.partial(_templateUrl, $sce); - } - ]; diff --git a/awx/ui/client/src/shared/text-label.less b/awx/ui/client/src/shared/text-label.less deleted file mode 100644 index 91ff0f1a656d..000000000000 --- a/awx/ui/client/src/shared/text-label.less +++ /dev/null @@ -1,18 +0,0 @@ -/* oops */ - -.include-text-label(@background-color; @color; @content) { - display: inline-block; - content: @content; - - border-radius: 3px; - background-color: @background-color; - color: @color; - text-transform: uppercase; - font-size: .7em; - font-weight: bold; - font-style: normal; - margin-left: 0.5em; - padding: 0.35em; - padding-bottom: 0.2em; - line-height: 1.1; -} diff --git a/awx/ui/client/src/shared/title.directive.js b/awx/ui/client/src/shared/title.directive.js deleted file mode 100644 index 717b0912b78d..000000000000 --- a/awx/ui/client/src/shared/title.directive.js +++ /dev/null @@ -1,17 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/* jshint unused: vars */ - -export default function() { - return function(scope, element, attrs) { - if (attrs.awToolTip) { - return; - } - - element.tooltip(); - }; -} diff --git a/awx/ui/client/src/shared/truncated-text.directive.js b/awx/ui/client/src/shared/truncated-text.directive.js deleted file mode 100644 index bf3d1fd8cc62..000000000000 --- a/awx/ui/client/src/shared/truncated-text.directive.js +++ /dev/null @@ -1,84 +0,0 @@ -/* jshint unused: vars */ - -function link($compile, scope, element, attrs) { - - // If the element is a DOM comment, that means - // it's been hidden with `ng-if` so don't try - // to process it or we get an error! - if (element[0].nodeType === 8) { - element = element.next(); - - // Element was removed due to `ng-if`, so don't - // worry about it - if (element.length === 0) { - return; - } - } - - - function elementTextWillWrap(element) { - - if (element[0].nodeType === 8) { - return false; - } - - var fullTextWidth = element[0].scrollWidth; - var elementWidth = element.outerWidth(); - - // HACK: For some reason many of my divs - // are ending up with a 1px size diff. - // Guessing this is because of 3 cols - // at 33% flex-basis, with 8px padding. - // Perhaps the padding is pushing it over - // in JavaScript but not visually? Using - // threshold to filter those out. - var threshold = 5; - - if(fullTextWidth > elementWidth && - fullTextWidth - elementWidth > threshold) { - return true; - } - - return false; - } - - function getText() { - return element.text(); - } - - function addTitleIfWrapping(text) { - - if (elementTextWillWrap(element)) { - element - .addClass('u-truncatedText') - .removeAttr('truncated-text') - .attr('title', text); - - $compile(element)(scope); - } - } - - scope.$watch(getText, addTitleIfWrapping); - - // HACK: This handles truncating _after_ other elements - // are added that affect the size of this element. I - // wanted to leave this as a regular event binding, but - // was running into issues with the resized element getting - // removed from the DOM after truncating! No idea why yet. - element.resize(function() { - addTitleIfWrapping(getText()); - }); - - scope.$watch('$destroy', function() { - element.off('resize'); - }); -} - -export default - ['$compile', - function($compile) { - return { - link: _.partial(link, $compile) - }; - } - ]; diff --git a/awx/ui/client/src/shared/upgrade/upgrade.block.less b/awx/ui/client/src/shared/upgrade/upgrade.block.less deleted file mode 100644 index 4d0203fa3295..000000000000 --- a/awx/ui/client/src/shared/upgrade/upgrade.block.less +++ /dev/null @@ -1,57 +0,0 @@ -.at-Upgrade--panel { - align-items: center; - background-color: @at-color-body-background-light; - border-radius: 10px; - color: @at-color-body-text; - display: flex; - flex-direction: column; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: @at-font-size-jumbotron-text; - height: ~"calc(100vh - 40px)"; - justify-content: center; - margin: @at-space-4x; - padding: @at-space-10x; -} - - .at-Upgrade--header { - display: flex; - font-size: @at-font-size-jumbotron-heading; - margin-top: @at-space-2x; - } - - .at-Upgrade--text { - align-items: center; - display: flex; - flex-flow: column; - } - - .at-Upgrade--brand { - margin-right: .4em; - } - - .at-Upgrade--icon { - color: @at-gray-b7; - } - - .at-Upgrade--loading:after { - content: "\2026"; - display: inline-block; - overflow: hidden; - position: absolute; - vertical-align: bottom; - width: 0px; - animation: ellipsis steps(4, end) 1500ms infinite; - -webkit-animation: ellipsis steps(4, end) 1500ms infinite; - } - - @keyframes ellipsis { - to { - width: 30px; - } - } - - @-webkit-keyframes ellipsis { - to { - width: 30px; - } - } diff --git a/awx/ui/client/src/shared/utilities/alerts.less b/awx/ui/client/src/shared/utilities/alerts.less deleted file mode 100644 index 1aaed209983d..000000000000 --- a/awx/ui/client/src/shared/utilities/alerts.less +++ /dev/null @@ -1,8 +0,0 @@ -.u-input-info-alert { - border-color: #31708f !important; -} - -.u-info-alert { - color: #31708f !important; -} - diff --git a/awx/ui/client/src/shared/utilities/hidden.less b/awx/ui/client/src/shared/utilities/hidden.less deleted file mode 100644 index 36942122d40a..000000000000 --- a/awx/ui/client/src/shared/utilities/hidden.less +++ /dev/null @@ -1,4 +0,0 @@ -.u-hiddenVisually { - visibility: hidden; -} - diff --git a/awx/ui/client/src/shared/utilities/icons.less b/awx/ui/client/src/shared/utilities/icons.less deleted file mode 100644 index 654f4f08005c..000000000000 --- a/awx/ui/client/src/shared/utilities/icons.less +++ /dev/null @@ -1,14 +0,0 @@ -/* not bem */ - -.icon(@icon-var) { - display: flex; - align-self: center; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - content: @icon-var; -} diff --git a/awx/ui/client/src/shared/utilities/layer.less b/awx/ui/client/src/shared/utilities/layer.less deleted file mode 100644 index e5af025d5b42..000000000000 --- a/awx/ui/client/src/shared/utilities/layer.less +++ /dev/null @@ -1,4 +0,0 @@ -.u-layer { - position: relative; - z-index: 10000; -} diff --git a/awx/ui/client/src/shared/utilities/truncated-text.less b/awx/ui/client/src/shared/utilities/truncated-text.less deleted file mode 100644 index 42be763ab9e8..000000000000 --- a/awx/ui/client/src/shared/utilities/truncated-text.less +++ /dev/null @@ -1,9 +0,0 @@ -.u-truncatedText { - overflow: hidden; - text-overflow: ellipsis; -} - -.u-wrappedText { - white-space: normal; - word-wrap: break-word; -} diff --git a/awx/ui/client/src/shared/utilities/unbold.less b/awx/ui/client/src/shared/utilities/unbold.less deleted file mode 100644 index 35654737e03a..000000000000 --- a/awx/ui/client/src/shared/utilities/unbold.less +++ /dev/null @@ -1,3 +0,0 @@ -.u-unbold { - font-weight: normal; -} diff --git a/awx/ui/client/src/shared/utilities/wordwrap.less b/awx/ui/client/src/shared/utilities/wordwrap.less deleted file mode 100644 index 7ca289d4da27..000000000000 --- a/awx/ui/client/src/shared/utilities/wordwrap.less +++ /dev/null @@ -1,10 +0,0 @@ -.u-wordwrap { - white-space: -moz-pre-wrap !important; - white-space: -webkit-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-all; - white-space: normal; -} \ No newline at end of file diff --git a/awx/ui/client/src/shared/variables/main.js b/awx/ui/client/src/shared/variables/main.js deleted file mode 100644 index 29942a7ff9d6..000000000000 --- a/awx/ui/client/src/shared/variables/main.js +++ /dev/null @@ -1,9 +0,0 @@ -import ParseVariableString from './parse-variable-string.factory'; -import SortVariables from './sort-variables.factory'; -import ToJSON from './to-json.factory'; - -export default - angular.module('variables', []) - .factory('ParseVariableString', ParseVariableString) - .factory('SortVariables', SortVariables) - .factory('ToJSON', ToJSON); diff --git a/awx/ui/client/src/shared/variables/parse-variable-string.factory.js b/awx/ui/client/src/shared/variables/parse-variable-string.factory.js deleted file mode 100644 index 71e145897f9f..000000000000 --- a/awx/ui/client/src/shared/variables/parse-variable-string.factory.js +++ /dev/null @@ -1,55 +0,0 @@ -export default - function ParseVariableString($log, ProcessErrors, SortVariables) { - return function (variables) { - var result = "---", json_obj; - if (typeof variables === 'string') { - if (variables === "{}" || variables === "null" || variables === "" || variables === "\"\"") { - // String is empty, return --- - } else { - try { - json_obj = JSON.parse(variables); - json_obj = SortVariables(json_obj); - result = jsyaml.safeDump(json_obj); - - } - catch (e) { - $log.debug('Attempt to parse extra_vars as JSON failed. Check that the variables parse as yaml. Set the raw string as the result.'); - try { - // do safeLoad, which well error if not valid yaml - json_obj = jsyaml.safeLoad(variables); - // but just send the variables - result = variables; - } - catch(e2) { - ProcessErrors(null, variables, e2.message, null, { hdr: 'Error!', - msg: 'Attempts to parse variables as JSON and YAML failed. Last attempt returned: ' + e2.message }); - } - } - } - } - else { - if ($.isEmptyObject(variables) || variables === null) { - // Empty object, return --- - } - else { - // convert object to yaml - try { - json_obj = SortVariables(variables); - result = jsyaml.safeDump(json_obj); - // result = variables; - } - catch(e3) { - ProcessErrors(null, variables, e3.message, null, { hdr: 'Error!', - msg: 'Attempt to convert JSON object to YAML document failed: ' + e3.message }); - } - } - } - return result; - }; - } - -ParseVariableString.$inject = - [ '$log', - 'ProcessErrors', - 'SortVariables' - ]; diff --git a/awx/ui/client/src/shared/variables/sort-variables.factory.js b/awx/ui/client/src/shared/variables/sort-variables.factory.js deleted file mode 100644 index a9cb3a363b20..000000000000 --- a/awx/ui/client/src/shared/variables/sort-variables.factory.js +++ /dev/null @@ -1,23 +0,0 @@ -export default - function SortVariables() { - return function(variableObj) { - var newObj; - function sortIt(objToSort) { - var i, - keys = Object.keys(objToSort), - newObj = {}; - keys = keys.sort(); - for (i=0; i < keys.length; i++) { - if (typeof objToSort[keys[i]] === 'object' && objToSort[keys[i]] !== null && !Array.isArray(objToSort[keys[i]])) { - newObj[keys[i]] = sortIt(objToSort[keys[i]]); - } - else { - newObj[keys[i]] = objToSort[keys[i]]; - } - } - return newObj; - } - newObj = sortIt(variableObj); - return newObj; - }; - } diff --git a/awx/ui/client/src/shared/variables/to-json.factory.js b/awx/ui/client/src/shared/variables/to-json.factory.js deleted file mode 100644 index 70996d489ed2..000000000000 --- a/awx/ui/client/src/shared/variables/to-json.factory.js +++ /dev/null @@ -1,80 +0,0 @@ -export default - function ToJSON($log, ProcessErrors) { - return function(parseType, variables, stringify, reviver) { - var json_data, - result, - tmp; - // bracketVar, - // key, - // lines, i, newVars = []; - if (parseType === 'json') { - try { - // perform a check to see if the user cleared the field completly - if(variables.trim() === "" || variables.trim() === "{" || variables.trim() === "}" ){ - variables = "{}"; - } - //parse a JSON string - if (reviver) { - json_data = JSON.parse(variables, reviver); - } - else { - json_data = JSON.parse(variables); - } - } - catch(e) { - json_data = {}; - $log.error('Failed to parse JSON string. Parser returned: ' + e.message); - ProcessErrors(null, variables, e.message, null, { hdr: 'Error!', - msg: 'Failed to parse JSON string. Parser returned: ' + e.message }); - throw 'Parse error. Failed to parse variables.'; - } - } else { - try { - if(variables.trim() === "" || variables.trim() === "-" || variables.trim() === "--"){ - variables = '---'; - } - json_data = jsyaml.safeLoad(variables); - if(json_data!==null){ - // unparsing just to make sure no weird characters are included. - tmp = jsyaml.dump(json_data); - if(tmp.indexOf('[object Object]')!==-1){ - throw "Failed to parse YAML string. Parser returned' + key + ' : ' +value + '.' "; - } - } - } - catch(e) { - json_data = undefined; // {}; - // $log.error('Failed to parse YAML string. Parser returned undefined'); - ProcessErrors(null, variables, e.message, null, { hdr: 'Error!', - msg: 'Failed to parse YAML string. Parser returned undefined'}); - } - } - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - ProcessErrors(null, variables, null, null, { hdr: 'Error!', - msg: 'Failed to parse variables. Attempted to parse ' + parseType + '. Parser did not return an object.' }); - // setTimeout( function() { - throw 'Parse error. Failed to parse variables.'; - // }, 1000); - } - result = json_data; - if (stringify) { - if(json_data === undefined){ - result = undefined; - } - else if ($.isEmptyObject(json_data)) { - result = ""; - } else { - // utilize the parsing to get here - // but send the raw variable string - result = variables; - } - } - return result; - }; - } - -ToJSON.$inject = - [ '$log', - 'ProcessErrors' - ]; diff --git a/awx/ui/client/src/smart-status/main.js b/awx/ui/client/src/smart-status/main.js deleted file mode 100644 index dfa2b35f0fab..000000000000 --- a/awx/ui/client/src/smart-status/main.js +++ /dev/null @@ -1,10 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import smartStatusDirective from './smart-status.directive'; -export default - angular.module('systemStatus', []) - .directive('awSmartStatus', smartStatusDirective); diff --git a/awx/ui/client/src/smart-status/smart-status.block.less b/awx/ui/client/src/smart-status/smart-status.block.less deleted file mode 100644 index 8b0b49c0f09a..000000000000 --- a/awx/ui/client/src/smart-status/smart-status.block.less +++ /dev/null @@ -1,107 +0,0 @@ -/** @define SmartStatus */ - -.SmartStatus-container{ - max-width: 165px; - display:flex; -} - -.SmartStatus-iconContainer{ - padding: 2px; - flex: 0 1 auto; -} - -.SmartStatus-icon { - width: 14px; - height: 14px; -} - -.SmartStatus-iconDirectionPlaceholder { - width: 14px; - height: 7px; - border: 1px solid @d7grey; - background: #f2f2f2; -} - -.SmartStatus-iconDirectionPlaceholder--bottom { - border-bottom: 0; -} - -.SmartStatus-iconDirectionPlaceholder--top { - border-top: 0; -} - -.SmartStatus-iconIndicator { - width: 14px; - height: 7px; -} - -.SmartStatus-iconIndicator--success { - background: #5cb85c; -} - -.SmartStatus-iconIndicator--failed { - background: #d9534f; -} - -.SmartStatus-iconPlaceholder { - height: 14px; - width: 14px; - border: 1px solid @d7grey; - background: #f2f2f2; -} - -.SmartStatus-tooltip--successful, -.SmartStatus-tooltip--success{ - color: @default-succ; - padding-right: 0px; - text-shadow: - -1px -1px 0 @default-bg, - 1px -1px 0 @default-bg, - -1px 1px 0 @default-bg, - 1px 1px 0 @default-bg; - -} - -.SmartStatus-tooltip--error, .SmartStatus-tooltip--failed{ - color: @default-err; - padding-right: 0px; - text-shadow: - -1px -1px 0 @default-bg, - 1px -1px 0 @default-bg, - -1px 1px 0 @default-bg, - 1px 1px 0 @default-bg; -} - -.SmartStatus-tooltip--running{ - color: @default-data-txt; - padding-right: 0px; - text-shadow: - -1px -1px 0 @default-bg, - 1px -1px 0 @default-bg, - -1px 1px 0 @default-bg, - 1px 1px 0 @default-bg; - .pulsate(); -} - -.SmartStatus-waiting { - width: 14px; - height: 14px; - border: 1px solid @d7grey; -} - -@keyframes pulse_animation { - 0% { transform: scale(1); } - 50% { transform: scale(0); } - 100% { transform: scale(1); } -} - -.SmartStatus-running { - height: 14px; - width: 14px; - background-color: @default-succ; - animation-name: pulse_animation; - animation-duration: 5000ms; - transform-origin:70% 70%; - animation-iteration-count: infinite; - animation-timing-function: linear; -} diff --git a/awx/ui/client/src/smart-status/smart-status.controller.js b/awx/ui/client/src/smart-status/smart-status.controller.js deleted file mode 100644 index 1caf92e5ba88..000000000000 --- a/awx/ui/client/src/smart-status/smart-status.controller.js +++ /dev/null @@ -1,90 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$filter', - function ($scope, $filter) { - - function isFailureState(status) { - return status === 'failed' || status === 'error' || status === 'canceled'; - } - - function init(){ - var singleJobStatus = true; - var firstJobStatus; - var recentJobs = $scope.jobs; - var detailsBaseUrl; - - if(!recentJobs){ - return; - } - - // unless we explicitly define a value for the template-type attribute when invoking the - // directive, assume the status icons are for a regular (non-workflow) job when building - // the details url path - if (typeof $scope.templateType !== 'undefined' && $scope.templateType === 'workflow_job_template') { - detailsBaseUrl = '/#/workflows/'; - } else { - detailsBaseUrl = '/#/jobs/playbook/'; - } - - var sparkData = - _.sortBy(recentJobs.map(function(job) { - - const finished = $filter('longDate')(job.finished) || job.status+""; - - const data = { - status: job.status, - jobId: job.id, - sortDate: job.finished || "running" + job.id, - finished: finished, - status_tip: "JOB ID: " + job.id + "
STATUS: " + job.status.toUpperCase() + "
FINISHED: " + finished, - detailsUrl: detailsBaseUrl + job.id - }; - - // If we've already determined that there are both failed and successful jobs OR if the current job in the loop is - // pending/waiting/running then we don't worry about checking for a single job status - if(singleJobStatus && (isFailureState(job.status) || job.status === "successful")) { - if(firstJobStatus) { - // We've already been through at least once and have a first job status - if(!(isFailureState(firstJobStatus) && isFailureState(job.status) || firstJobStatus === job.status)) { - // We have a different status in the array - singleJobStatus = false; - } - } - else { - // We haven't set a first job status yet so go ahead set it - firstJobStatus = job.status; - } - } - - return data; - }), "sortDate").reverse(); - - $scope.singleJobStatus = singleJobStatus; - - $scope.sparkArray = sparkData; - $scope.placeholders = new Array(10 - sparkData.length); - } - $scope.$watchCollection('jobs', function(){ - init(); - }); - -}]; - -// -// -// JOB_STATUS_CHOICES = [ -// ('new', _('New')), # Job has been created, but not started. -// ('pending', _('Pending')), # Job has been queued, but is not yet running. -// ('waiting', _('Waiting')), # Job is waiting on an update/dependency. -// ('running', _('Running')), # Job is currently running. -// ('successful', _('Successful')), # Job completed successfully. -// ('failed', _('Failed')), # Job completed, but with failures. -// ('error', _('Error')), # The job was unable to run. -// ('canceled', _('Canceled')), # The job was canceled before completion. -// final states only***** -// ] -// diff --git a/awx/ui/client/src/smart-status/smart-status.directive.js b/awx/ui/client/src/smart-status/smart-status.directive.js deleted file mode 100644 index a4486e125ec7..000000000000 --- a/awx/ui/client/src/smart-status/smart-status.directive.js +++ /dev/null @@ -1,19 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import smartStatusController from './smart-status.controller'; -export default [ 'templateUrl', - function(templateUrl) { - return { - scope: { - jobs: '=', - templateType: '=?', - }, - templateUrl: templateUrl('smart-status/smart-status'), - restrict: 'E', - controller: smartStatusController - }; -}]; diff --git a/awx/ui/client/src/smart-status/smart-status.partial.html b/awx/ui/client/src/smart-status/smart-status.partial.html deleted file mode 100644 index ee3a157eaac5..000000000000 --- a/awx/ui/client/src/smart-status/smart-status.partial.html +++ /dev/null @@ -1,35 +0,0 @@ - diff --git a/awx/ui/client/src/standard-out/standard-out-factories/delete-job.factory.js b/awx/ui/client/src/standard-out/standard-out-factories/delete-job.factory.js deleted file mode 100644 index 6e28362f3a20..000000000000 --- a/awx/ui/client/src/standard-out/standard-out-factories/delete-job.factory.js +++ /dev/null @@ -1,145 +0,0 @@ -export default -function DeleteJob($state, Find, Rest, Wait, ProcessErrors, Prompt, Alert, - $filter, i18n) { - return function(params) { - var scope = params.scope, - id = params.id, - job = params.job, - callback = params.callback, - action, jobs, url, action_label, hdr; - - if (!job) { - if (scope.completed_jobs) { - jobs = scope.completed_jobs; - } - else if (scope.running_jobs) { - jobs = scope.running_jobs; - } - else if (scope.queued_jobs) { - jobs = scope.queued_jobs; - } - else if (scope.all_jobs) { - jobs = scope.all_jobs; - } - else if (scope.jobs) { - jobs = scope.jobs; - } - job = Find({list: jobs, key: 'id', val: id }); - } - - if (job.status === 'pending' || job.status === 'running' || job.status === 'waiting') { - url = job.related.cancel; - action_label = 'cancel'; - hdr = i18n._('Cancel'); - } else { - url = job.url; - action_label = 'delete'; - hdr = i18n._('Delete'); - } - - action = function () { - Wait('start'); - Rest.setUrl(url); - if (action_label === 'cancel') { - Rest.post() - .then(() => { - $('#prompt-modal').modal('hide'); - if (callback) { - scope.$emit(callback, action_label); - } - else { - $state.reload(); - Wait('stop'); - } - }) - .catch(({obj, status}) => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - if (status === 403) { - Alert('Error', obj.detail); - } - // Ignore the error. The job most likely already finished. - // ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - // ' failed. POST returned status: ' + status }); - }); - } else { - Rest.destroy() - .then(() => { - $('#prompt-modal').modal('hide'); - if (callback) { - scope.$emit(callback, action_label); - } - else { - let reloadListStateParams = null; - - if(scope.jobs.length === 1 && $state.params.job_search && !_.isEmpty($state.params.job_search.page) && $state.params.job_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.job_search.page = (parseInt(reloadListStateParams.job_search.page)-1).toString(); - } - - $state.go('.', reloadListStateParams, {reload: true}); - Wait('stop'); - } - }) - .catch(({obj, status}) => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - if (status === 403) { - Alert('Error', obj.detail); - } - // Ignore the error. The job most likely already finished. - //ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - // ' failed. DELETE returned status: ' + status }); - }); - } - }; - - if (scope.removeCancelNotAllowed) { - scope.removeCancelNotAllowed(); - } - scope.removeCancelNotAllowed = scope.$on('CancelNotAllowed', function() { - Wait('stop'); - Alert('Job Completed', 'The request to cancel the job could not be submitted. The job already completed.', 'alert-info'); - }); - - if (scope.removeCancelJob) { - scope.removeCancelJob(); - } - scope.removeCancelJob = scope.$on('CancelJob', function() { - var cancelBody = "
" + i18n._("Are you sure you want to submit the request to cancel this job?") + "
"; - var deleteBody = "
" + i18n._("Are you sure you want to delete this job?") + "
"; - Prompt({ - hdr: hdr, - resourceName: `#${job.id} ` + $filter('sanitize')(job.name), - body: (action_label === 'cancel' || job.status === 'new') ? cancelBody : deleteBody, - action: action, - actionText: (action_label === 'cancel' || job.status === 'new') ? i18n._("OK") : i18n._("DELETE") - }); - }); - - if (action_label === 'cancel') { - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - if (data.can_cancel) { - scope.$emit('CancelJob'); - } - else { - scope.$emit('CancelNotAllowed'); - } - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - ' failed. GET returned: ' + status }); - }); - } - else { - scope.$emit('CancelJob'); - } - }; -} - -DeleteJob.$inject = -[ '$state', 'Find', 'Rest', 'Wait', - 'ProcessErrors', 'Prompt', 'Alert', '$filter', 'i18n' -]; diff --git a/awx/ui/client/src/standard-out/standard-out-factories/main.js b/awx/ui/client/src/standard-out/standard-out-factories/main.js deleted file mode 100644 index 935c8dca375c..000000000000 --- a/awx/ui/client/src/standard-out/standard-out-factories/main.js +++ /dev/null @@ -1,13 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import lookUpName from './lookup-name.factory'; -import DeleteJob from './delete-job.factory'; - -export default - angular.module('StandardOutHelper', []) - .factory('LookUpName', lookUpName) - .factory('DeleteJob', DeleteJob); diff --git a/awx/ui/client/src/system-tracking/compare-facts/fact-template.js b/awx/ui/client/src/system-tracking/compare-facts/fact-template.js deleted file mode 100644 index dcb666ee9a39..000000000000 --- a/awx/ui/client/src/system-tracking/compare-facts/fact-template.js +++ /dev/null @@ -1,31 +0,0 @@ -var $injector = angular.injector(['ng']); -var $interpolate = $injector.get('$interpolate'); - -function FactTemplate(templateString) { - this.templateString = templateString; -} - -function loadFactTemplate(factTemplate, fact) { - if (_.isFunction(factTemplate)) { - return factTemplate(fact); - } else { - return factTemplate; - } -} - - -FactTemplate.prototype.render = function(factData) { - - if (_.isUndefined(factData) || _.isEmpty(factData)) { - return 'absent'; - } - - var template = loadFactTemplate(this.templateString, factData); - return $interpolate(template)(factData); -}; - -FactTemplate.prototype.hasTemplate = function() { - return !_.isUndefined(this.templateString); -}; - -export default FactTemplate; diff --git a/awx/ui/client/src/system-tracking/compare-facts/flat.js b/awx/ui/client/src/system-tracking/compare-facts/flat.js deleted file mode 100644 index 6e487abf9491..000000000000 --- a/awx/ui/client/src/system-tracking/compare-facts/flat.js +++ /dev/null @@ -1,229 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -function slotFactValues(basisPosition, basisValue, comparatorValue) { - var leftValue, rightValue; - - if (basisPosition === 'left') { - leftValue = basisValue; - rightValue = comparatorValue; - } else { - rightValue = basisValue; - leftValue = comparatorValue; - } - - return { left: leftValue, - right: rightValue - }; -} - -/* - * @name flatCompare - * @description - * Takes two separate fact objects and combines any differences into a single result - * object, formatted for display. - * - * @param {Tower.SystemTracking.ResolvedFact} basisFacts - The facts we will use as the basis for this comparison - * @param {Tower.SystemTracking.ResolvedFact} comparatorFacts - The facts we will compare against the basis - * @param {Tower.SystemTracking.RenderOptions} renderOptions - Options specified in the module for rendering values - * - * @returns {Array.} - * - * @typedef {Object} Tower.SystemTracking.RenderOptions - * @property {string} nameKey - The name of the key that is used to locate facts from basisFacts in comparatorFacts - * @property {string|string[]} compareKey - A single key or list of keys to compare in the two fact collections - * @property {Tower.SystemTracking.KeyNameMap} keyNameMap - An object mapping existing key names to new key names for display - * @property {Tower.SystemTracking.FactTemplate} factTemplate - An optional template used as the string for comparing and displaying a fact - * @property {boolean} supportsValueArray - Indicates that the module we're rendering supports values in an array of strings rather than just a string; iterim measure to make sure modules with multiple facts matching nameKey don't get evaluated because we won't know how to dipslay them - * - * @typedef {(string|boolean)} Tower.SystemTracking.KeyNameMapValue - The name you want to use for the display of a key or "true" to indicate a key should be displayed without changing its name (all keys are hidden by default) - * - * @typedef {Object.} Tower.SystemTracking.KeyNameMap - An object whose keys are the names of keys that exist in a fact and whose values control how that key is displayed - * - * @typedef {{displayKeyPath: string, nestingLevel: number, facts: Array.}} Tower.SystemTracking.FactComparisonDescriptor - * - * @typedef {{keyName: string, value1: Tower.SystemTracking.FactComparisonValue, value2: Tower.SystemTracking.FactComparisonValue, isDivergent: boolean}} Tower.SystemTracking.FactComparisonResult - * - * @typedef {(string|string[])} Tower.SystemTracking.FactComparisonValue - * - */ -export default - function flatCompare(basisFacts, - comparatorFacts, renderOptions) { - - var nameKey = renderOptions.nameKey; - var compareKeys = renderOptions.compareKey; - var keyNameMap = renderOptions.keyNameMap; - var factTemplate = renderOptions.factTemplate; - - - return basisFacts.facts.reduce(function(arr, basisFact) { - - // First, make sure this fact hasn't already been processed, if it - // has don't process it again - // - if (_.any(arr, { displayKeyPath: basisFact[nameKey] })) { - return arr; - } - - var searcher = {}; - searcher[nameKey] = basisFact[nameKey]; - - var containsValueArray = false; - var matchingFacts = _.where(comparatorFacts.facts, searcher); - var comparisonResults; - var diffs; - - // If this fact exists more than once in `basisFacts`, then - // we need to process it differently - // - var otherBasisFacts = _.where(basisFacts.facts, searcher); - if (renderOptions.supportsValueArray && otherBasisFacts.length > 1) { - comparisonResults = processFactsForValueArray(basisFacts.position, otherBasisFacts, matchingFacts); - } else { - comparisonResults = processFactsForSingleValue(basisFact, matchingFacts[0] || {}); - } - - function processFactsForValueArray(basisPosition, basisFacts, comparatorFacts) { - - function renderFactValues(facts) { - return facts.map(function(fact) { - return factTemplate.render(fact); - }); - } - - var basisFactValues = renderFactValues(basisFacts); - var comparatorFactValues = renderFactValues(comparatorFacts); - - var slottedValues = slotFactValues(basisPosition, basisFactValues, comparatorFactValues); - - var remaining = _.difference(slottedValues.left, slottedValues.right); - - if (_.isEmpty(remaining)) { - slottedValues.isDivergent = false; - } else { - slottedValues.isDivergent = true; - containsValueArray = true; - } - - return slottedValues; - } - - function processFactsForSingleValue(basisFact, comparatorFact) { - // Perform comparison and get back comparisonResults; like: - // { 'value': - // { leftValue: 'blah', - // rightValue: 'doo' - // } - // }; - // - return _.reduce(compareKeys, function(result, compareKey) { - - var isNestedDisplay = false; - var basisFactValue = basisFact[compareKey]; - var comparatorFactValue = comparatorFact[compareKey]; - var slottedValues; - - if (_.isUndefined(basisFactValue) && _.isUndefined(comparatorFactValue)) { - return result; - } - - var template = factTemplate; - - if (_.isObject(template) && template.hasOwnProperty(compareKey)) { - template = template[compareKey]; - - // 'true' means render the key without formatting - if (template === true) { - template = - { render: function(fact) { return fact[compareKey]; } - }; - } - - isNestedDisplay = true; - } else if (typeof template.hasTemplate === 'function' && !template.hasTemplate()) { - template = - { render: function(fact) { return fact[compareKey]; } - }; - isNestedDisplay = true; - } else if (typeof factTemplate.render === 'function') { - template = factTemplate; - } else if (!template.hasOwnProperty(compareKey)) { - return result; - } - - // if (!renderOptions.supportsValueArray) { - // comparatorFact = comparatorFact[0]; - // } - - basisFactValue = template.render(basisFact); - comparatorFactValue = template.render(comparatorFact); - - slottedValues = slotFactValues(basisFacts.position, - basisFactValue, - comparatorFactValue); - - if (slottedValues.left !== slottedValues.right) { - slottedValues.isDivergent = true; - } else { - slottedValues.isDivergent = false; - } - - if (isNestedDisplay) { - result[compareKey] = slottedValues; - } else { - result = slottedValues; - } - - return result; - }, {}); - } - - var hasDiffs = - _.any(comparisonResults, { isDivergent: true }) || - comparisonResults.isDivergent === true; - - if (hasDiffs && typeof factTemplate.render === 'function') { - - diffs = - { keyName: basisFact[nameKey], - value1: comparisonResults.left, - value2: comparisonResults.right - }; - - } else if (hasDiffs) { - - diffs = - _(comparisonResults).map(function(slottedValues, key) { - - var keyName = key; - - if (keyNameMap && keyNameMap[key]) { - keyName = keyNameMap[key]; - } - - return { keyName: keyName, - value1: slottedValues.left, - value2: slottedValues.right, - isDivergent: slottedValues.isDivergent - }; - }).compact() - .value(); - } - - var descriptor = - { displayKeyPath: basisFact[nameKey], - nestingLevel: 0, - containsValueArray: containsValueArray, - facts: diffs - }; - - return arr.concat(descriptor); - }, []).filter(function(diff) { - return !_.isEmpty(diff.facts); - }); - - } diff --git a/awx/ui/client/src/system-tracking/compare-facts/main.js b/awx/ui/client/src/system-tracking/compare-facts/main.js deleted file mode 100644 index df8aa67e154a..000000000000 --- a/awx/ui/client/src/system-tracking/compare-facts/main.js +++ /dev/null @@ -1,55 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import compareNestedFacts from './nested'; -import compareFlatFacts from './flat'; -import FactTemplate from './fact-template'; - -export function compareFacts(module, facts) { - - - var renderOptions = _.merge({}, module); - - // If the module has a template or includes a list of keys to display, - // then perform a flat comparison, otherwise assume nested - // - if (renderOptions.factTemplate || renderOptions.nameKey) { - // For flat structures we compare left-to-right, then right-to-left to - // make sure we get a good comparison between both hosts - - if (_.isPlainObject(renderOptions.factTemplate)) { - renderOptions.factTemplate = - _.mapValues(renderOptions.factTemplate, function(template) { - if (typeof template === 'string' || typeof template === 'function') { - return new FactTemplate(template); - } else { - return template; - } - }); - } else { - renderOptions.factTemplate = new FactTemplate(renderOptions.factTemplate); - } - - var leftToRight = compareFlatFacts(facts[0], facts[1], renderOptions); - var rightToLeft = compareFlatFacts(facts[1], facts[0], renderOptions); - - return _(leftToRight) - .concat(rightToLeft) - .unique('displayKeyPath') - .thru(function(result) { - return { factData: result, - isNestedDisplay: _.isPlainObject(renderOptions.factTemplate), - leftData: facts[0].facts, - rightData: facts[1].facts - }; - }) - .value(); - } else { - return { factData: compareNestedFacts(facts[0], facts[1]), - isNestedDisplay: true - }; - } -} diff --git a/awx/ui/client/src/system-tracking/compare-facts/nested-helpers.js b/awx/ui/client/src/system-tracking/compare-facts/nested-helpers.js deleted file mode 100644 index 3a8fea8926ae..000000000000 --- a/awx/ui/client/src/system-tracking/compare-facts/nested-helpers.js +++ /dev/null @@ -1,204 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export function formatFacts(diffedResults) { - - var loggingEnabled = false; - - function log(msg, obj) { - if (loggingEnabled) { - /* jshint ignore:start */ - console.log(msg, obj); - /* jshint ignore:end */ - } - return obj; - } - - function isFlatFactArray(fact) { - // Flat arrays will have the index as their - // keyName - return !_.isNaN(Number(fact.keyName)); - } - - function isNestedFactArray(fact) { - // Nested arrays will have the index as the last element - // in the keypath - return !_.isNaN(Number(_.last(fact.keyPath))); - } - function isFactArray(fact) { - return isNestedFactArray(fact) || isFlatFactArray(fact); - } - - // Explode flat results into groups based matching - // parent keypaths - var grouped = _.groupBy(diffedResults, function(obj) { - var leftKeyPathStr = obj.keyPath.join('.'); - log('obj.keyPath', obj.keyPath); - return log(' reduced key', _.reduce(diffedResults, function(result, obj2) { - log(' obj2.keyPath', obj2.keyPath); - var rightKeyPathStr = obj2.keyPath.join('.'); - if (isFactArray(obj)) { - log(' number hit!', Number(_.last(obj.keyPath))); - return obj.keyPath.slice(0,-1); - } else if (rightKeyPathStr && leftKeyPathStr !== rightKeyPathStr && log(' intersection', _.intersection(obj.keyPath, obj2.keyPath).join('.')) === rightKeyPathStr) { - log(' hit!'); - return obj2.keyPath; - } else { - log(' else hit!'); - return result; - } - }, obj.keyPath)).join('.'); - }); - - var normalized = _.mapValues(grouped, function(arr, rootKey) { - log('processing', rootKey); - var nestingLevel = 0; - var trailingLength; - return _(arr).sortBy('keyPath.length').tap(function(arr) { - // Initialize trailing length to the shortest keyPath length - // in the array (first item because we know it's sorted now) - trailingLength = arr[0].keyPath.length; - }).map(function(obj) { - var keyPathStr = obj.keyPath.join('.'); - log(' calculating displayKeyPath for', keyPathStr); - var rootKeyPath = rootKey.split('.'); - var displayKeyPath; - // var factArrayIndex; - var isFactArrayProp = isFactArray(obj); - - if (obj.keyPath.length > trailingLength) { - nestingLevel++; - trailingLength = obj.keyPath.length; - } - - if (isNestedFactArray(obj)) { - // factArrayIndex = obj.keyPath.length > 1 ? Number(_.last(obj.keyPath)) : obj.keyName; - displayKeyPath = _.initial(obj.keyPath).join('.'); - // } else { - // displayKeyPath = _.difference(obj.keyPath, rootKeyPath).join('.'); - } else { - displayKeyPath = rootKeyPath.join('.'); - } - - - obj.displayKeyPath = displayKeyPath; - obj.nestingLevel = nestingLevel; - // obj.arrayPosition = factArrayIndex; - obj.isArrayMember = isFactArrayProp; - return obj; - }).value(); - }); - - var flattened = _.reduce(normalized, function(flat, value) { - - var groupedValues = _.groupBy(value, 'displayKeyPath'); - - var groupArr = - _.reduce(groupedValues, function(groupArr, facts, key) { - var isArray = facts[0].isArrayMember; - var nestingLevel = facts[0].nestingLevel; - - if (isArray) { - facts = _(facts) - .groupBy('arrayPosition') - .values() - .value(); - } - - var displayObj = - { keyPath: key.split('.'), - displayKeyPath: key, - isNestedDisplay: true, - facts: facts, - isFactArray: isArray, - nestingLevel: nestingLevel - }; - return groupArr.concat(displayObj); - }, []); - - return flat.concat(groupArr); - - }, []); - - return flattened; -} - -export function findFacts(factData) { - var leftData = factData[0].facts; - var rightData = factData[1].facts; - - // For value types (boolean, number) or complex objects use the value - // as is. For collection types, return 'absent' if it's empty - // otherwise, use the value as is. - // - function factValueOrAbsent(value) { - - if (_.isBoolean(value) || - _.isNumber(value)) { - return value; - } - - if (_.isNull(value) || _.isEmpty(value)) { - return 'absent'; - } - - return value; - } - - function factObject(keyPath, key, leftValue, rightValue) { - var obj = - { keyPath: keyPath, - keyName: key - }; - - leftValue = factValueOrAbsent(leftValue); - rightValue = factValueOrAbsent(rightValue); - - if (factData[0].position === 'left') { - obj.value1 = leftValue; - obj.value2 = rightValue; - } else { - obj.value1 = rightValue; - obj.value2 = leftValue; - } - - return obj; - } - - function descend(parentValue, parentKey, parentKeys) { - if (_.isObject(parentValue)) { - return _.reduce(parentValue, function(all, value, key) { - var merged = descend(value, key, parentKeys.concat(key)); - return all.concat(merged); - }, []); - } else { - - // default value in _.get ('absent') only hits if it's undefined, so we need to handle other falsey cases with || - var rightValue = - _.get(rightData, - parentKeys); - - return factObject( - // TODO: Currently parentKeys is getting passed with the final key - // as the last element. Figure out how to have it passed - // in correctly, so that it's all the keys leading up to - // the value, but not the value's key itself - // In the meantime, slicing the last element off the array - parentKeys.slice(0,-1), - parentKey, - parentValue, - rightValue); - } - } - - return _.reduce(leftData, function(mergedFacts, parentValue, parentKey) { - - var merged = descend(parentValue, parentKey, [parentKey]); - - return _.flatten(mergedFacts.concat(merged)); - - }, []); -} diff --git a/awx/ui/client/src/system-tracking/compare-facts/nested.js b/awx/ui/client/src/system-tracking/compare-facts/nested.js deleted file mode 100644 index 31e98526a760..000000000000 --- a/awx/ui/client/src/system-tracking/compare-facts/nested.js +++ /dev/null @@ -1,76 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {formatFacts, findFacts} from './nested-helpers'; - -export default function nestedCompare(basisFacts, comparatorFacts) { - - if (_.isEmpty(basisFacts.facts)) { - var tmp = _.merge({}, basisFacts); - basisFacts = _.merge({}, comparatorFacts); - comparatorFacts = tmp; - } - - var factsList = [basisFacts, comparatorFacts]; - factsList = findFacts(factsList); - factsList = compareFacts(factsList); - return formatFacts(factsList); - - function compareFacts(factsList) { - - function serializedFactKey(fact) { - return fact.keyPath.join('.'); - } - - var groupedByParent = - _.groupBy(factsList, function(fact) { - return serializedFactKey(fact); - }); - - - var diffed = _.mapValues(groupedByParent, function(facts) { - return facts.filter(function(fact) { - return fact.value1 !== fact.value2; - }).map(function(fact) { - // TODO: Can we determine a "compare order" and be able say - // which property is actually divergent? - return _.merge({}, fact, { isDivergent: true }); - }); - }); - - var itemsWithDiffs = - _.filter(factsList, function(facts) { - var groupedData = diffed[serializedFactKey(facts)]; - return !_.isEmpty(groupedData); - }); - - var keysWithDiffs = - _.reduce(diffed, function(diffs, facts, key) { - diffs[key] = - facts.reduce(function(diffKeys, fact) { - if (fact.isDivergent) { - return diffKeys.concat(fact.keyName); - } - return diffKeys; - }, []); - return diffs; - }, {}); - - var factsWithDivergence = - _.mapValues(itemsWithDiffs, function(fact) { - var divergentKeys = keysWithDiffs[serializedFactKey(fact)]; - if (divergentKeys) { - var isDivergent = _.include(divergentKeys, fact.keyName); - return _.merge({}, fact, { isDivergent: isDivergent }); - } else { - return _.merge({}, fact, { isDivergent: false }); - } - }); - - return factsWithDivergence; - - } -} diff --git a/awx/ui/client/src/system-tracking/data-services/dedupe-versions.js b/awx/ui/client/src/system-tracking/data-services/dedupe-versions.js deleted file mode 100644 index e6f27040086a..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/dedupe-versions.js +++ /dev/null @@ -1,42 +0,0 @@ -export default - function dedupeVersions(nonEmptyResults) { - - if (_.any(nonEmptyResults, 'versions.length', 0)) { - return _.pluck(nonEmptyResults, 'versions[0]'); - } - - // if the version that will be displayed on the left is before the - // version that will be displayed on the right, flip them - if (nonEmptyResults[0].versions[0].timestamp > nonEmptyResults[1].versions[0].timestamp) { - nonEmptyResults = nonEmptyResults.reverse(); - } - - var firstTimestamp = nonEmptyResults[0].versions[0].timestamp; - - var hostIdsWithDupes = - _(nonEmptyResults) - .pluck('versions[0]') - .filter('timestamp', firstTimestamp) - .map(function(version, index) { - return nonEmptyResults[index].hostId; - }) - .value(); - - if (hostIdsWithDupes.length === 1) { - return _.pluck(nonEmptyResults, 'versions[0]'); - } - - var bestScanResults = _.max(nonEmptyResults, "versions.length"); - - return nonEmptyResults.map(function(scan, index) { - var hasDupe = - _.include(hostIdsWithDupes, scan.hostId); - - if (hasDupe && index === 1) { - return bestScanResults.versions[0]; - } else { - return bestScanResults.versions[1]; - } - }); - - } diff --git a/awx/ui/client/src/system-tracking/data-services/fact-scan-data.service.js b/awx/ui/client/src/system-tracking/data-services/fact-scan-data.service.js deleted file mode 100644 index 9805dfdf2d20..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/fact-scan-data.service.js +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'GetBasePath', 'ProcessErrors', 'lodashAsPromised', -function (Rest, GetBasePath, ProcessErrors, _) { - - function buildUrl (host_id, module, startDate, endDate) { - var url = GetBasePath('hosts') + host_id + '/fact_versions/', - params= [["module", module] , ['from', startDate.format()], ['to', endDate.format()]]; - - params = params.filter(function(p){ - return !_.isEmpty(p[1]); - }); - params = params.map(function(p){ - return p.join("="); - }).join("&"); - url = _.compact([url, params]).join("?"); - return url; - } - - return { - getFacts: function(version) { - var promise; - Rest.setUrl(version.related.fact_view); - promise = Rest.get(); - return promise.then(function (response) { - return response.data; - }).catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get license info. GET returned status: ' + - response.status - }); - }); - }, - - getVersion: function(versionParams){ - //move the build url into getVersion and have the - // parameters passed into this - var promise; - var hostId = versionParams.hostId; - var startDate = versionParams.dateRange.from; - var endDate = versionParams.dateRange.to; - var module = versionParams.moduleName; - - var url = buildUrl(hostId, module, startDate, endDate); - - Rest.setUrl(url); - promise = Rest.get(); - return promise.then(function(response) { - versionParams.versions = response.data.results; - return versionParams; - }).catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get license info. GET returned status: ' + - response.status - }); - }); - } - }; -}]; diff --git a/awx/ui/client/src/system-tracking/data-services/get-data-for-comparison.factory.js b/awx/ui/client/src/system-tracking/data-services/get-data-for-comparison.factory.js deleted file mode 100644 index 0c29b2433cfa..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/get-data-for-comparison.factory.js +++ /dev/null @@ -1,68 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import dedupeVersions from './dedupe-versions'; - -export default - [ 'factScanDataService', - 'resolveEmptyVersions', - 'lodashAsPromised', - function(factScanDataService, resolveEmptyVersions, _) { - return function(hostIds, moduleName, leftDate, rightDate) { - - var singleHostMode = false; - - if (hostIds.length === 1) { - singleHostMode = true; - hostIds = hostIds.concat(hostIds[0]); - } - - var hostVersionParams = - [{ hostId: hostIds[0], - dateRange: leftDate, - moduleName: moduleName - }, - { hostId: hostIds[1], - dateRange: rightDate, - moduleName: moduleName - } - ]; - - return _(factScanDataService.getVersion(hostVersionParams[1])) - .then(function(result) { - return resolveEmptyVersions(result); - }).thenAll(function(firstResult) { - - return factScanDataService.getVersion(hostVersionParams[0]) - .then(function(secondResult) { - if (_.isEmpty(secondResult.versions)) { - secondResult = resolveEmptyVersions(secondResult); - } - - return [firstResult, secondResult]; - }); - }).thenAll(function(results) { - var finalSet; - - if (singleHostMode) { - finalSet = dedupeVersions(results.reverse()); - } else { - finalSet = _.pluck(results, 'versions[0]').reverse(); - } - - return finalSet; - }).thenMap(function(versionData) { - if (versionData) { - return factScanDataService.getFacts(versionData); - } else { - return { fact: [] }; - } - }).thenAll(function(hostFacts) { - return hostFacts; - }); - }; - } - ]; diff --git a/awx/ui/client/src/system-tracking/data-services/get-module-options.factory.js b/awx/ui/client/src/system-tracking/data-services/get-module-options.factory.js deleted file mode 100644 index 5a6b6f5eb42d..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/get-module-options.factory.js +++ /dev/null @@ -1,79 +0,0 @@ -var moduleConfig = - { 'packages': - { compareKey: ['release', 'version'], - nameKey: 'name', - sortKey: 1, - factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}", - supportsValueArray: true - }, - 'services': - { compareKey: ['state', 'source'], - nameKey: 'name', - factTemplate: '{{state}} ({{source}})', - sortKey: 2 - }, - 'files': - { compareKey: ['size', 'mode', 'checksum', 'mtime', 'gid', 'uid'], - keyNameMap: - { 'uid': 'ownership' - }, - factTemplate: - { 'uid': 'user id: {{uid}}, group id: {{gid}}', - 'mode': true, - 'checksum': true, - 'size': true, - 'mtime': '{{mtime|formatEpoch}}' - }, - nameKey: 'path', - sortKey: 3 - }, - 'ansible': - { sortKey: 4 - }, - 'custom': - { - } - }; - -function makeModule(option, index) { - var name = option[0]; - var displayName = option[1]; - var config = moduleConfig.hasOwnProperty(name) ? - moduleConfig[name] : moduleConfig.custom; - var modulesCount = _.keys(moduleConfig).length - 1; - - config.name = name; - config.displayName = displayName; - - // Use index to sort custom modules, - // offset by built-in modules since - // they have a hardcoded sort key - // - if (_.isUndefined(config.sortKey)) { - config.sortKey = (index - 1) + modulesCount; - } - - return config; -} - -function factory(hostId, rest, getBasePath, _) { - var url = [ getBasePath('hosts') + hostId, - 'fact_versions' - ].join('/'); - - rest.setUrl(url); - return _(rest.options()) - .then(function(response) { - var choices = response.data.actions.GET.module.choices; - return _.sortBy(choices, '1'); - }).thenMap(makeModule); -} - -export default - [ 'Rest', - 'GetBasePath', - 'lodashAsPromised', - function(rest, getBasePath, lodash) { - return _.partialRight(factory, rest, getBasePath, lodash); - } - ]; diff --git a/awx/ui/client/src/system-tracking/data-services/main.js b/awx/ui/client/src/system-tracking/data-services/main.js deleted file mode 100644 index d08b7baec792..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/main.js +++ /dev/null @@ -1,12 +0,0 @@ -import factScanDataService from './fact-scan-data.service'; -import getDataForComparison from './get-data-for-comparison.factory'; -import getModuleOptions from './get-module-options.factory'; -import resolveEmptyVersions from './resolve-empty-versions.factory'; -import shared from '../../shared/main'; - -export default - angular.module('systemTracking.dataServices', [shared.name]) - .factory('getModuleOptions', getModuleOptions) - .factory('getDataForComparison', getDataForComparison) - .factory('resolveEmptyVersions', resolveEmptyVersions) - .service('factScanDataService', factScanDataService); diff --git a/awx/ui/client/src/system-tracking/data-services/resolve-empty-versions.factory.js b/awx/ui/client/src/system-tracking/data-services/resolve-empty-versions.factory.js deleted file mode 100644 index 7c7552af870a..000000000000 --- a/awx/ui/client/src/system-tracking/data-services/resolve-empty-versions.factory.js +++ /dev/null @@ -1,33 +0,0 @@ -import moment from '../../shared/moment/moment'; - -function resolveEmptyVersions(service, _, candidate, previousResult) { - - candidate = _.merge({}, candidate); - - // theoretically, returning no versions, but also returning only a single version for _a particular date_ acts as an empty version problem. If there is only one version returned, you'll need to check previous dates as well. - if (_.isEmpty(candidate.versions) || candidate.versions.length === 1) { - // this marks the end of the date put in the datepicker. this needs to be the end, rather than the beginning of the date, because you may have returned one valid version on the date the datepicker had in it. - var originalStartDate = candidate.dateRange.to.clone(); - - if (!_.isUndefined(previousResult)) { - candidate.dateRange.from = moment(previousResult.versions[0].timestamp); - } else { - candidate.dateRange.from = originalStartDate.clone().subtract(1, 'year'); - } - - candidate.dateRange.to = originalStartDate; - - return service.getVersion(candidate); - } - - return _.promise(candidate); - -} - -export default - [ 'factScanDataService', - 'lodashAsPromised', - function(factScanDataService, lodash) { - return _.partial(resolveEmptyVersions, factScanDataService, lodash); - } - ]; diff --git a/awx/ui/client/src/system-tracking/date-picker/date-picker.block.less b/awx/ui/client/src/system-tracking/date-picker/date-picker.block.less deleted file mode 100644 index 207cfca6a578..000000000000 --- a/awx/ui/client/src/system-tracking/date-picker/date-picker.block.less +++ /dev/null @@ -1,37 +0,0 @@ -.DatePicker { - flex: 1 0 auto; - display: flex; - - &-icon { - flex: initial; - padding: 6px 12px; - font-size: 14px; - border-radius: 4px 0 0 4px; - border: 1px solid @b7grey; - border-right: 0; - background-color: @default-bg; - } - - &-icon:hover { - background-color: @f6grey; - } - - &-icon:focus, - &-icon:active { - background-color: @f6grey; - } - - &-input { - flex: 1 0 auto; - border-radius: 0 4px 4px 0; - border: 1px solid @b7grey; - padding: 6px 12px; - background-color: @fcgrey; - } - - &-input:focus, - &-input:active { - outline-offset: 0; - outline: 0; - } -} diff --git a/awx/ui/client/src/system-tracking/date-picker/date-picker.directive.js b/awx/ui/client/src/system-tracking/date-picker/date-picker.directive.js deleted file mode 100644 index ca972bfacfe5..000000000000 --- a/awx/ui/client/src/system-tracking/date-picker/date-picker.directive.js +++ /dev/null @@ -1,104 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/* jshint unused: vars */ - -export default ['moment', - 'templateUrl', - function(moment, templateUrl) { - return { - restrict: 'E', - scope: { - date: '=', - minDate: '=', - autoUpdate: '=?', - inputClass: '&' - }, - templateUrl: templateUrl('system-tracking/date-picker/date-picker'), - link: function(scope, element, attrs) { - - // We need to make sure this _never_ recurses, which sometimes happens - // with two-way binding. - var mustUpdateValue = true; - scope.autoUpdate = scope.autoUpdate === false ? false : true; - - scope.$watch('minDate', function(newValue) { - if (newValue) { - - if (scope.autoUpdate && scope.date.isBefore(newValue)) { - scope.date = newValue; - } - - $('.date', element).datepicker('setStartDate', newValue.toDate()); - } - }); - - scope.$watch('date', function(newValue) { - if (newValue) { - mustUpdateValue = false; - scope.dateValue = newValue.format('L'); - } - }, true); - - scope.$watch('dateValue', function(newValue) { - var newDate = moment(newValue, ['L'], moment.locale()); - - if (newValue && !newDate.isValid()) { - scope.error = "That is not a valid date."; - } else if (newValue) { - scope.date = newDate; - } - mustUpdateValue = true; - }); - - var localeData = - moment.localeData(); - var dateFormat = momentFormatToDPFormat(localeData._longDateFormat.L); - var localeKey = momentLocaleToDPLocale(moment.locale()); - - element.find(".DatePicker").addClass("input-prepend date"); - element.find(".DatePicker").find(".DatePicker-icon").addClass("add-on"); - $(".date").datepicker({ - autoclose: true, - language: localeKey, - format: dateFormat - }); - - function momentLocaleToDPLocale(localeKey) { - var parts = localeKey.split('-'); - - if (parts.length === 2) { - var lastPart = parts[1].toUpperCase(); - return [parts[0], lastPart].join('-'); - } else { - return localeKey; - } - - } - - function momentFormatToDPFormat(momentFormat) { - var resultFormat = momentFormat; - - function lowerCase(str) { - return str.toLowerCase(); - } - - resultFormat = resultFormat.replace(/D{1,2}/, lowerCase); - - if (/MMM/.test(resultFormat)) { - resultFormat = resultFormat.replace('MMM', 'M'); - } else { - resultFormat = resultFormat.replace(/M{1,2}/, 'm'); - } - - resultFormat = resultFormat.replace(/Y{2,4}/, lowerCase); - - return resultFormat; - } - } - }; - } -]; diff --git a/awx/ui/client/src/system-tracking/date-picker/date-picker.partial.html b/awx/ui/client/src/system-tracking/date-picker/date-picker.partial.html deleted file mode 100644 index 74bd409a6f11..000000000000 --- a/awx/ui/client/src/system-tracking/date-picker/date-picker.partial.html +++ /dev/null @@ -1,11 +0,0 @@ -
- - -

{{error}}

-
diff --git a/awx/ui/client/src/system-tracking/date-picker/main.js b/awx/ui/client/src/system-tracking/date-picker/main.js deleted file mode 100644 index 21bbf0432b98..000000000000 --- a/awx/ui/client/src/system-tracking/date-picker/main.js +++ /dev/null @@ -1,12 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import datePicker from './date-picker.directive'; - -export default - angular.module('systemTracking.datePicker', - []) - .directive('datePicker', datePicker); diff --git a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.block.less b/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.block.less deleted file mode 100644 index 62512a73cc69..000000000000 --- a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.block.less +++ /dev/null @@ -1,138 +0,0 @@ -/** @define FactDataTable */ - -.FactDataTable { - &-row, &-headingRow, &-groupHeadingRow { - display: flex; - } - - &-row { - padding: .5em 0; - align-items: center; - transition: background-color 100ms, border-color 100ms; - border: solid 1px @default-bg; - - &:nth-child(even) { - background-color: @default-no-items-bord; - } - - &:hover { - background-color: @default-list-header-bg; - border-color: @default-border; - } - - &--flexible { - max-height: initial; - align-items: flex-start; - } - - } - - &-repeat { - &:nth-child(even) { - background-color: @default-no-items-bord; - } - } - - &-headingRow { - background-color: @default-list-header-bg; - border: none; - padding: 8px 12px; - - .FactDataTable-column.FactDataTableHeading:first-child { - padding-left: 0; - } - } - - &-groupHeadingRow { - background-color: @default-icon-hov; - padding: 1em 12px; - color: @default-interface-txt; - font-size: 14px; - } - - &-column { - padding: 8px; - flex: 1 0 33%; - align-self: flex-start; - padding: 0; - margin: 0; - overflow: hidden; - padding: 8px; - word-wrap: break-word; - &--offsetLeft { - margin-left: 33%; - } - } - - &-columnArray { - display: flex; - flex-direction: column; - } - - &-columnMember { - margin-bottom: 16px; - &:last-child { - margin-bottom: inherit; - } - } -} - -.FactDataError { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 200px; - border-radius: 5px; - border: 1px solid @list-no-items-bord; - background-color: @default-no-items-bord; - color: @list-no-items-txt; - text-transform: uppercase; -} - -.FactDataGroup { - &-headings { - &:hover { - background-color: @default-bg; - border-color: transparent; - } - } - &-header { - padding: 0; - } -} - -.FactDataTableHeading { - display: flex; - flex-wrap: wrap; - align-items: flex-end; - font-size: 14px; - color: @default-interface-txt; - text-transform: uppercase; - - &-host { - margin: 0; - } - &-date { - flex-basis: auto; - } - - // Override some global styling on h3 tags - h3 { - margin: 1em initial; - } -} - -.FactDatum { - &--divergent { - //margin-bottom: 0.5rem; - background-color: @default-err; - border: none; - color: @default-bg; - - &:hover { - background-color: @default-err; - border: none; - } - } -} diff --git a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.directive.js b/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.directive.js deleted file mode 100644 index 1c99f546a081..000000000000 --- a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.directive.js +++ /dev/null @@ -1,21 +0,0 @@ -/* jshint unused: vars */ - -export default - [ 'templateUrl', - function(templateUrl) { - return { restrict: 'E', - templateUrl: templateUrl('system-tracking/fact-data-table/fact-data-table'), - scope: - { leftHostname: '=', - rightHostname: '=', - leftScanDate: '=', - rightScanDate: '=', - leftDataNoScans: '=', - rightDataNoScans: '=', - isNestedDisplay: '=', - singleResultView: '=', - factData: '=' - } - }; - } - ]; diff --git a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.partial.html b/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.partial.html deleted file mode 100644 index efb66303bcb5..000000000000 --- a/awx/ui/client/src/system-tracking/fact-data-table/fact-data-table.partial.html +++ /dev/null @@ -1,93 +0,0 @@ -
-
- The selected fact scans were identical for this module. Showing all facts from the latest selected scan instead. -
-
- - - Comparing facts from: - - - - - No scans for - {{leftHostname}} - on - - {{leftHostname}} -  - {{leftScanDate|longDate}} - {{rightScanDate|longDate}} - - - No scans for {{rightHostname}} on - {{rightHostname}} -  - {{rightScanDate|longDate}} - -
-
-
-
- {{group.facts.keyName}} - - - {{value}} - - - - - {{value}} - - -
-
- {{group.facts.keyName}} - {{group.facts.value1}} - {{group.facts.value2}} -
-
-
-
- -
- -
- - {{group.displayKeyPath}} - -
-
-
-
- - {{fact.keyName}} - - - {{fact.keyPath[0]}}.{{fact.keyName}} - - - {{fact.value1}} - - - {{fact.value2}} - -
-
-
- - {{fact.keyName}} - - - {{fact.keyPath[0]}}.{{fact.keyName}} - - - {{fact.value1}} - - - {{fact.value2}} - -
-
-
-
- -
diff --git a/awx/ui/client/src/system-tracking/fact-data-table/main.js b/awx/ui/client/src/system-tracking/fact-data-table/main.js deleted file mode 100644 index d77cd22feecb..000000000000 --- a/awx/ui/client/src/system-tracking/fact-data-table/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import factDataTable from './fact-data-table.directive'; - -export default - angular.module('systemTracking.factDataTable', []) - .directive('factDataTable', factDataTable); diff --git a/awx/ui/client/src/system-tracking/fact-module-filter.block.less b/awx/ui/client/src/system-tracking/fact-module-filter.block.less deleted file mode 100644 index 23466ebfe99f..000000000000 --- a/awx/ui/client/src/system-tracking/fact-module-filter.block.less +++ /dev/null @@ -1,54 +0,0 @@ -/** @define FactModuleFilter */ - -.FactModuleFilter { - width: 100%; - display: flex; - flex-flow: row wrap; - margin-bottom: 2.8rem; - - .btn, .btn-default { - margin-right: 20px; - width: 10rem; - } - - &-module { - - background-color: @enabled-item-background; - border-color: @default-icon-hov; - color: @default-interface-txt; - - @media screen and (max-width: 750px) { - flex-basis: 50%; - } - &:active, &:focus { - // copied from bootstrap's .btn:focus - background-color: @default-icon-hov; - border-color: @enabled-item-border; - color: @enabled-item-text; - box-shadow: none; - z-index: 2; - } - - &:hover { - border-color: @default-icon-hov; - } - } - - &-module.is-active { - cursor: default; - - z-index: 2; - - background-color: @default-icon; - color: @default-bg; - border-color: @default-icon; - - &:active, &:focus { - box-shadow: none; - } - - &:hover { - background-color: @default-interface-txt; - } - } -} diff --git a/awx/ui/client/src/system-tracking/fact-module-pickers.block.less b/awx/ui/client/src/system-tracking/fact-module-pickers.block.less deleted file mode 100644 index 6c5ebb4551cb..000000000000 --- a/awx/ui/client/src/system-tracking/fact-module-pickers.block.less +++ /dev/null @@ -1,16 +0,0 @@ -.FactModulePickers-label { - padding-right: 0; - text-align: right; - font-size: 11px; - text-transform: uppercase; - color: @default-interface-txt; - line-height: 17px; -} - -.FactModulePickers-warning { - float: right; - clear: both; - font-size: 12px; - width: 75%; - text-align: right; -} diff --git a/awx/ui/client/src/system-tracking/format-facts.js b/awx/ui/client/src/system-tracking/format-facts.js deleted file mode 100644 index 32ff9fed6cdc..000000000000 --- a/awx/ui/client/src/system-tracking/format-facts.js +++ /dev/null @@ -1,13 +0,0 @@ -export function formatFactForDisplay(fact, renderOptions) { - - var factTemplate = renderOptions.factTemplate; - - var template = factTemplate; - - // if (!renderOptions.supportsValueArray) { - // comparatorFact = comparatorFact[0]; - // } - - return template.render(fact); - -} diff --git a/awx/ui/client/src/system-tracking/main.js b/awx/ui/client/src/system-tracking/main.js deleted file mode 100644 index ae1ec2a51bbf..000000000000 --- a/awx/ui/client/src/system-tracking/main.js +++ /dev/null @@ -1,27 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './system-tracking.route'; -import controller from './system-tracking.controller'; -import shared from '../shared/main'; -import utilities from '../shared/Utilities'; - -import datePicker from './date-picker/main'; -import dataServices from './data-services/main'; -import factDataTable from './fact-data-table/main'; - -export default - angular.module('systemTracking', - [ utilities.name, - shared.name, - datePicker.name, - factDataTable.name, - dataServices.name - ]) - .controller('systemTracking', controller) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route); - }]); diff --git a/awx/ui/client/src/system-tracking/search-date-range.js b/awx/ui/client/src/system-tracking/search-date-range.js deleted file mode 100644 index 3b969672d605..000000000000 --- a/awx/ui/client/src/system-tracking/search-date-range.js +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import moment from '../shared/moment/moment'; - -export function searchDateRange(dateString) { - var date; - - switch(dateString) { - case 'yesterday': - date = moment().subtract(1, 'day'); - break; - case 'tomorrow': - date = moment().add(1, 'day'); - break; - default: - date = moment(dateString); - } - - - return { - from: date.clone().startOf('day'), - to: date.clone().add(1, 'day').startOf('day') - }; -} diff --git a/awx/ui/client/src/system-tracking/system-tracking-container.block.less b/awx/ui/client/src/system-tracking/system-tracking-container.block.less deleted file mode 100644 index c8252662ffeb..000000000000 --- a/awx/ui/client/src/system-tracking/system-tracking-container.block.less +++ /dev/null @@ -1,37 +0,0 @@ -.SystemTrackingContainer { - display: flex; - flex-direction: column; - min-height: 85vh; - > * { - flex: 0 0 auto; - } - - &-main { - flex: 1 0 auto; - align-self: stretch; - } - - .DatePicker { - flex: none; - } - - .DatePicker-input { - width: 100%; - flex: none; - background: @fcgrey; - } - - .DatePicker-icon { - i { - color: @default-icon; - } - } - - .SystemTrackingContainer-main { - margin-top: 20px; - } - - .FactDatum--divergent { - background-color: @default-err; - } -} diff --git a/awx/ui/client/src/system-tracking/system-tracking.controller.js b/awx/ui/client/src/system-tracking/system-tracking.controller.js deleted file mode 100644 index 2892fdd34732..000000000000 --- a/awx/ui/client/src/system-tracking/system-tracking.controller.js +++ /dev/null @@ -1,336 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {searchDateRange} from './search-date-range'; -import {compareFacts} from './compare-facts/main'; -import {formatFactForDisplay} from './format-facts'; -import FactTemplate from './compare-facts/fact-template'; - -function controller($scope, - $stateParams, - $location, - $q, - $state, - moduleOptions, - inventory, - hosts, - getDataForComparison, - waitIndicator, - moment, - _) { - - // var inventoryId = $stateParams.id; - var hostIds = $stateParams.hostIds.split(','); - var moduleParam = $stateParams.module || 'packages'; - - $scope.compareMode = - hostIds.length === 1 ? 'single-host' : 'host-to-host'; - $scope.hostIds = $stateParams.hosts; - $scope.inventory = inventory; - $scope.noModuleData = false; - - // this means no scans have been run - if (_.isEmpty(moduleOptions)) { - $scope.noModuleData = true; - return; - } - - if ($scope.compareMode === 'host-to-host') { - $scope.factModulePickersLabelLeft = "Compare latest facts collected across both hosts on or before"; - } else { - $scope.factModulePickersLabelLeft = "Compare latest facts collected on or before"; - $scope.factModulePickersLabelRight = "To latest facts collected on or before"; - } - - $scope.modules = _.clone(moduleOptions, true); - - var leftSearchRange = searchDateRange(); - var rightSearchRange = searchDateRange(); - - var searchConfig = - { leftRange: leftSearchRange, - rightRange: rightSearchRange - }; - - $scope.leftDate = leftSearchRange.from; - $scope.rightDate = rightSearchRange.from; - - $scope.leftHostname = hosts[0].name; - $scope.rightHostname = hosts.length > 1 ? hosts[1].name : hosts[0].name; - - function reloadData(params) { - - searchConfig = _.assign({}, searchConfig, params); - - var leftRange = searchConfig.leftRange; - var rightRange = searchConfig.rightRange; - var activeModule = searchConfig.module; - - if ($scope.compareMode === 'host-to-host') { - rightRange = searchConfig.leftRange; - } - - $scope.leftDataNoScans = false; - $scope.rightDataNoScans = false; - $scope.leftDateWarning = false; - $scope.rightDateWarning = false; - - $scope.singleFactOnly = false; - - waitIndicator('start'); - - return getDataForComparison( - hostIds, - activeModule.name, - leftRange, - rightRange) - .then(function(responses) { - var data = []; - _.each(responses, function(response) { - if(response.fact) { - data.push(response.fact); - } else if (response.facts) { - data.push(response.facts); - } - }); - - if (_.isEmpty(data[0]) && _.isEmpty(data[1])) { - return _.reject({ - name: 'NoScanData', - message: 'There was insufficient scan data for the date you selected. Please try selecting a different date or module.', - dateValues: - { leftDate: $scope.leftDate.clone(), - rightDate: $scope.rightDate.clone() - } - }); - } - if (_.isEmpty(data[0])) { - $scope.leftDataNoScans = true; - $scope.leftScanDate = $scope.leftDate; - } else { - $scope.leftScanDate = moment(responses[0].timestamp); - - if (!$scope.leftScanDate.isSame($scope.leftDate, 'd')) { - $scope.leftDateWarning = true; - } - } - - if (_.isEmpty(data[1])) { - $scope.rightDataNoScans = true; - $scope.rightScanDate = $scope.rightDate; - } else { - $scope.rightScanDate = moment(responses[1].timestamp); - - if (!$scope.rightScanDate.isSame($scope.rightDate, 'd')) { - $scope.rightDateWarning = true; - } - } - - return data; - }) - - .then(function(facts) { - // Make sure we always start comparison against - // a non-empty array - // - // Partition with _.isEmpty will give me an array - // with empty arrays in index 0, and non-empty - // arrays in index 1 - // - - var wrappedFacts = - facts.map(function(facts, index) { - return { position: index === 0 ? 'left' : 'right', - isEmpty: _.isEmpty(facts), - facts: facts - }; - }); - - var splitFacts = _.partition(facts, 'isEmpty'); - var emptyScans = splitFacts[0]; - var nonEmptyScans = splitFacts[1]; - var result; - - if (_.isEmpty(nonEmptyScans)) { - // we have NO data, throw an error - result = _.reject({ - name: 'NoScanData', - message: 'No scans ran on either of the dates you selected. Please try selecting different dates.', - dateValues: - { leftDate: $scope.leftDate.clone(), - rightDate: $scope.rightDate.clone() - } - }); - } else if (nonEmptyScans.length === 1) { - // one of them is not empty, throw an error - result = _.reject({ - name: 'InsufficientScanData', - message: 'No scans ran on one of the selected dates. Please try selecting a different date.', - dateValue: emptyScans[0].position === 'left' ? $scope.leftDate.clone() : $scope.rightDate.clone() - }); - } else { - result = _.promise(wrappedFacts); - } - - // all scans have data, rejoice! - return result; - - }) - .then(_.partial(compareFacts, activeModule)) - .then(function(info) { - - // Clear out any errors from the previous run... - $scope.error = null; - - if (_.isEmpty(info.factData)) { - - if ($scope.compareMode === 'host-to-host') { - info = _.reject({ - name: 'NoScanDifferences', - message: 'No differences in the scans on the dates you selected. Please try selecting different dates.', - dateValues: - { leftDate: $scope.leftDate.clone(), - rightDate: $scope.rightDate.clone() - } - }); - } else { - $scope.singleFactOnly = true; - $scope.factData = info.leftData.map(function(fact) { - var keyNameMap = activeModule.keyNameMap; - var nameKey = activeModule.nameKey; - var renderOptions = _.merge({}, activeModule); - var isNestedDisplay = false; - var facts; - - if (_.isObject(renderOptions.factTemplate) && - _.isArray(renderOptions.compareKey)) { - - isNestedDisplay = true; - - var templates = _.mapValues(renderOptions.factTemplate, function(template, key) { - if (template === true) { - return { render: function(fact) { - return fact[key]; - } - }; - } else { - return new FactTemplate(template); - } - }); - - facts = _.map(templates, function(template, key) { - var keyName = key; - - if (_.isObject(keyNameMap) && keyNameMap.hasOwnProperty(key)) { - keyName = keyNameMap[key]; - } - - renderOptions.factTemplate = template; - var formattedValue = formatFactForDisplay(fact, renderOptions); - return { keyName: keyName, - isNestedDisplay: true, - value1: formattedValue - }; - }); - - - } else { - renderOptions.factTemplate = new FactTemplate(renderOptions.factTemplate); - var formattedValue = formatFactForDisplay(fact, renderOptions); - isNestedDisplay = false; - facts = { keyName: fact[nameKey], - value1: formattedValue - }; - } - - $scope.isNestedDisplay = isNestedDisplay; - - return { displayKeyPath: fact[renderOptions.nameKey], - nestingLevel: 0, - containsValueArray: false, - facts: facts - }; - }); - } - } else { - $scope.singleFactOnly = false; - $scope.factData = info.factData; - $scope.isNestedDisplay = info.isNestedDisplay; - } - return info; - - }).catch(function(error) { - $scope.error = error; - }).finally(function() { - waitIndicator('stop'); - }); - } - - $scope.setActiveModule = function(newModuleName, initialData) { - var newModule = _.find($scope.modules, function(module) { - return module.name === newModuleName; - }); - - if (newModule) { - if (newModule.isActive) { - return; - } - $scope.modules.forEach(function(module) { - module.isActive = false; - }); - - newModule.isActive = true; - - $location.replace(); - $location.search('module', newModuleName); - - reloadData({ module: newModule - }, initialData).value(); - } - }; - - function dateWatcher(dateProperty) { - return function(newValue, oldValue) { - // passing in `true` for the 3rd param to $watch should make - // angular use `angular.equals` for comparing these values; - // the watcher should not fire, but it still is. Therefore, - // using `moment.isSame` to keep from reloading data when the - // dates did not actually change - if (newValue.isSame(oldValue)) { - return; - } - - var newDate = searchDateRange(newValue); - - var params = {}; - params[dateProperty] = newDate; - - reloadData(params).value(); - }; - } - - $scope.$watch('leftDate', dateWatcher('leftRange'), true); - - $scope.$watch('rightDate', dateWatcher('rightRange'), true); - - $scope.setActiveModule(moduleParam); -} - -export default - [ '$scope', - '$stateParams', - '$location', - '$q', - '$state', - 'moduleOptions', - 'inventory', - 'hosts', - 'getDataForComparison', - 'Wait', - 'moment', - 'lodashAsPromised', - controller - ]; diff --git a/awx/ui/client/src/system-tracking/system-tracking.partial.html b/awx/ui/client/src/system-tracking/system-tracking.partial.html deleted file mode 100644 index f920a0fdeed0..000000000000 --- a/awx/ui/client/src/system-tracking/system-tracking.partial.html +++ /dev/null @@ -1,66 +0,0 @@ -
-
-

- To set up scan jobs, create a job template that targets the "{{inventory.name}}" inventory and check "Store Ansible Facts." -

-
-
-
-
-
SYSTEM TRACKING
{{inventory.name}}
-
-
-
- {{ factModulePickersLabelLeft }} - - - - There were no fact scans on this date, using a prior scan instead. - -
-
- {{ factModulePickersLabelRight }} - - - - There were no fact scans on this date, using a prior scan instead. - -
-
-
-
- - - - -
-

- - There was insufficient scan data for one or both of the dates you selected. Please try selecting a different date or module. - - - There was insufficient scan data for the date you selected. Please try selecting a different date or module. - -

-

- There were no facts collected on or before one of the dates you selected ({{error.dateValue|amDateFormat:'L'}}). Please select a different date and try again. -

-

- The two fact scans were identical for this module. -

-

- We were not able to find any facts collected for this inventory or module. To setup or run scan jobs, edit the "{{inventory.name}}" inventory and check "Store Ansible Facts." -

-
- - -
diff --git a/awx/ui/client/src/system-tracking/system-tracking.route.js b/awx/ui/client/src/system-tracking/system-tracking.route.js deleted file mode 100644 index da803afc9105..000000000000 --- a/awx/ui/client/src/system-tracking/system-tracking.route.js +++ /dev/null @@ -1,108 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../shared/template-url/template-url.factory'; -import { N_ } from '../i18n'; - -export default { - name: 'systemTracking', - route: '/inventories/:inventoryId/system-tracking/:hostIds', - controller: 'systemTracking', - templateUrl: templateUrl('system-tracking/system-tracking'), - params: {hosts: null, inventory: null}, - reloadOnSearch: false, - ncyBreadcrumb: { - label: N_("SYSTEM TRACKING") - }, - resolve: { - moduleOptions: - [ 'getModuleOptions', - 'ProcessErrors', - '$stateParams', - function(getModuleOptions, ProcessErrors, $stateParams) { - - var hostIds = $stateParams.hostIds.split(','); - - var data = - getModuleOptions(hostIds[0]) - .catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get license info. GET returned status: ' + - response.status - }); - }) - .value(); - - return data; - - } - ], - inventory: - [ '$stateParams', - '$q', - 'Rest', - 'GetBasePath', - 'ProcessErrors', - function($stateParams, $q, rest, getBasePath, ProcessErrors) { - - if ($stateParams.inventory) { - return $q.when($stateParams.inventory); - } - - var inventoryId = $stateParams.inventoryId; - - var url = getBasePath('inventory') + inventoryId + '/'; - rest.setUrl(url); - return rest.get() - .then(function(data) { - return data.data; - }).catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get license info. GET returned status: ' + - response.status - }); - }); - } - ], - hosts: - [ '$stateParams', - '$q', - 'Rest', - 'GetBasePath', - 'ProcessErrors', - function($stateParams, $q, rest, getBasePath, ProcessErrors) { - if ($stateParams.hosts) { - return $q.when($stateParams.hosts); - } - - var hostIds = $stateParams.hostIds.split(','); - - var hosts = - hostIds.map(function(hostId) { - var url = getBasePath('hosts') + - hostId + '/'; - - rest.setUrl(url); - return rest.get() - .then(function(data) { - return data.data; - }).catch(function (response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get license info. GET returned status: ' + - response.status - }); - }); - }); - - return $q.all(hosts); - } - - ] - } -}; diff --git a/awx/ui/client/src/teams/add/teams-add.controller.js b/awx/ui/client/src/teams/add/teams-add.controller.js deleted file mode 100644 index e33c918a63b6..000000000000 --- a/awx/ui/client/src/teams/add/teams-add.controller.js +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', 'TeamForm', 'GenerateForm', 'Rest', - 'Alert', 'ProcessErrors', 'GetBasePath', 'Wait', '$state', - function($scope, $rootScope, TeamForm, GenerateForm, Rest, Alert, - ProcessErrors, GetBasePath, Wait, $state) { - - Rest.setUrl(GetBasePath('teams')); - Rest.options() - .then(({data}) => { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a team.', 'alert-info'); - } - }); - - // Inject dynamic view - var defaultUrl = GetBasePath('teams'), - form = TeamForm; - - init(); - - function init() { - $scope.canEditOrg = true; - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - $rootScope.flashMessage = null; - } - - // Save - $scope.formSave = function() { - var fld, data; - GenerateForm.clearApiErrors($scope); - Wait('start'); - Rest.setUrl(defaultUrl); - data = {}; - for (fld in form.fields) { - data[fld] = $scope[fld]; - } - Rest.post(data) - .then(({data}) => { - Wait('stop'); - $rootScope.flashMessage = "New team successfully created!"; - $rootScope.$broadcast("EditIndicatorChange", "users", data.id); - $state.go('teams.edit', { team_id: data.id }, { reload: true }); - }) - .catch(({data, status}) => { - Wait('stop'); - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new team. Post returned status: ' + - status - }); - }); - }; - - $scope.formCancel = function() { - $state.go('teams'); - }; - } -]; diff --git a/awx/ui/client/src/teams/edit/teams-edit.controller.js b/awx/ui/client/src/teams/edit/teams-edit.controller.js deleted file mode 100644 index 41a37b19cb5e..000000000000 --- a/awx/ui/client/src/teams/edit/teams-edit.controller.js +++ /dev/null @@ -1,118 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', '$rootScope', '$stateParams', 'TeamForm', 'Rest', - 'ProcessErrors', 'GetBasePath', 'Wait', '$state', 'OrgAdminLookup', 'resolvedModels', - function($scope, $rootScope, $stateParams, TeamForm, Rest, ProcessErrors, - GetBasePath, Wait, $state, OrgAdminLookup, models) { - - const { me } = models; - var form = TeamForm, - id = $stateParams.team_id, - defaultUrl = GetBasePath('teams') + id; - - init(); - - function init() { - $scope.canEdit = me.get('summary_fields.user_capabilities.edit'); - $scope.isOrgAdmin = me.get('related.admin_of_organizations.count') > 0; - $scope.team_id = id; - Rest.setUrl(defaultUrl); - Wait('start'); - Rest.get(defaultUrl).then(({data}) => { - setScopeFields(data); - $scope.organization_name = data.summary_fields.organization.name; - - OrgAdminLookup.checkForAdminAccess({organization: data.organization}) - .then(function(canEditOrg){ - $scope.canEditOrg = canEditOrg; - }); - - $scope.team_obj = data; - Wait('stop'); - }); - - $scope.$watch('team_obj.summary_fields.user_capabilities.edit', function(val) { - $scope.canAdd = (val === false) ? false : true; - }); - - - } - - // @issue I think all this really want to do is _.forEach(form.fields, (field) =>{ $scope[field] = data[field]}) - function setScopeFields(data) { - _(data) - .pick(function(value, key) { - return form.fields.hasOwnProperty(key) === true; - }) - .forEach(function(value, key) { - $scope[key] = value; - }) - .value(); - return; - } - - // prepares a data payload for a PUT request to the API - function processNewData(fields) { - var data = {}; - _.forEach(fields, function(value, key) { - if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) { - data[key] = $scope[key]; - } - }); - return data; - } - - $scope.formCancel = function() { - $state.go('teams', null, { reload: true }); - }; - - $scope.formSave = function() { - $rootScope.flashMessage = null; - if ($scope[form.name + '_form'].$valid) { - var data = processNewData(form.fields); - Rest.setUrl(defaultUrl); - Rest.put(data).then(() => { - $state.go($state.current, null, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to retrieve user: ' + - $stateParams.id + '. GET status: ' + status - }); - }); - } - }; - - init(); - - $scope.redirectToResource = function(resource) { - let type = resource.summary_fields.resource_type.replace(/ /g , "_"); - var id = resource.related[type].split("/")[4]; - switch (type) { - case 'organization': - $state.go('organizations.edit', { "organization_id": id }, { reload: true }); - break; - case 'credential': - $state.go('credentials.edit', { "credential_id": id }, { reload: true }); - break; - case 'project': - $state.go('projects.edit', { "project_id": id }, { reload: true }); - break; - case 'inventory': - $state.go('inventories.edit', { "inventory_id": id }, { reload: true }); - break; - case 'job_template': - $state.go('templates.editJobTemplate', { "job_template_id": id }, { reload: true }); - break; - case 'workflow_job_template': - $state.go('templates.editWorkflowJobTemplate', { "workflow_job_template_id": id }, { reload: true }); - break; - } - }; - } -]; diff --git a/awx/ui/client/src/teams/list/teams-list.controller.js b/awx/ui/client/src/teams/list/teams-list.controller.js deleted file mode 100644 index 024f74361b3d..000000000000 --- a/awx/ui/client/src/teams/list/teams-list.controller.js +++ /dev/null @@ -1,86 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['$scope', 'Rest', 'TeamList', 'Prompt', - 'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', - 'rbacUiControlService', 'Dataset', 'resolvedModels', 'i18n', - function($scope, Rest, TeamList, Prompt, ProcessErrors, - GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset, models, i18n) { - - const { me } = models; - var list = TeamList, - defaultUrl = GetBasePath('teams'); - - init(); - - function init() { - $scope.canEdit = me.get('summary_fields.user_capabilities.edit'); - $scope.canAdd = false; - - rbacUiControlService.canAdd('teams') - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.selected = []; - } - - $scope.addTeam = function() { - $state.go('teams.add'); - }; - - $scope.editTeam = function(id) { - $state.go('teams.edit', { team_id: id }); - }; - - $scope.deleteTeam = function(id, name) { - - var action = function() { - Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() - .then(() => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - - let reloadListStateParams = null; - - if($scope.teams.length === 1 && $state.params.team_search && !_.isEmpty($state.params.team_search.page) && $state.params.team_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.team_search.page = (parseInt(reloadListStateParams.team_search.page)-1).toString(); - } - - if (parseInt($state.params.team_id) === id) { - $state.go('^', reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, { reload: true }); - } - }) - .catch(({data, status}) => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status - }); - }); - }; - - Prompt({ - hdr: 'Delete', - resourceName: $filter('sanitize')(name), - body: '
' + i18n._('Are you sure you want to delete this team?') + '
', - action: action, - actionText: 'DELETE' - }); - }; - } -]; diff --git a/awx/ui/client/src/teams/main.js b/awx/ui/client/src/teams/main.js deleted file mode 100644 index 7140e9aaf938..000000000000 --- a/awx/ui/client/src/teams/main.js +++ /dev/null @@ -1,70 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import TeamsList from './list/teams-list.controller'; -import TeamsAdd from './add/teams-add.controller'; -import TeamsEdit from './edit/teams-edit.controller'; -import TeamList from './teams.list'; -import TeamForm from './teams.form'; -import { N_ } from '../i18n'; - -export default -angular.module('Teams', []) - .controller('TeamsList', TeamsList) - .controller('TeamsAdd', TeamsAdd) - .controller('TeamsEdit', TeamsEdit) - .factory('TeamList', TeamList) - .factory('TeamForm', TeamForm) - .config(['$stateProvider', 'stateDefinitionsProvider', - function($stateProvider, stateDefinitionsProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(); - - // lazily generate a tree of substates which will replace this node in ui-router's stateRegistry - // see: stateDefinition.factory for usage documentation - $stateProvider.state({ - name: 'teams.**', - url: '/teams', - lazyLoad: () => stateDefinitions.generateTree({ - parent: 'teams', - modes: ['add', 'edit'], - list: 'TeamList', - form: 'TeamForm', - controllers: { - list: TeamsList, - add: TeamsAdd, - edit: TeamsEdit - }, - data: { - activityStream: true, - activityStreamTarget: 'team' - }, - resolve: { - edit: { - resolvedModels: ['MeModel', '$q', function(Me, $q) { - const promises = { - me: new Me('get').then((me) => me.extend('get', 'admin_of_organizations')) - }; - - return $q.all(promises); - }] - }, - list: { - resolvedModels: ['MeModel', '$q', function(Me, $q) { - const promises = { - me: new Me('get') - }; - - return $q.all(promises); - }] - } - }, - ncyBreadcrumb: { - label: N_('TEAMS') - } - }) - }); - } - ]); diff --git a/awx/ui/client/src/teams/teams.form.js b/awx/ui/client/src/teams/teams.form.js deleted file mode 100644 index 1b3fa842ad4e..000000000000 --- a/awx/ui/client/src/teams/teams.form.js +++ /dev/null @@ -1,166 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Teams - * @description This form is for adding/editing teams -*/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW TEAM'), //Legend in add mode - editTitle: '{{ name }}', //Legend in edit mode - name: 'team', - // the top-most node of generated state tree - stateTree: 'teams', - tabs: true, - messageBar: { - ngShow: 'isOrgAdmin && !canEdit', - message: i18n._("Contact your System Administrator to grant you the appropriate permissions to add and edit Users and Teams.") - }, - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: false - }, - description: { - label: i18n._('Description'), - type: 'text', - ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - list: 'OrganizationList', - sourceModel: 'organization', - basePath: 'organizations', - sourceField: 'name', - ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', - awLookupWhen: '(team_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg', - required: true, - } - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - users: { - name: 'users', - dataPlacement: 'top', - awToolTip: i18n._('Please save before adding users.'), - basePath: 'api/v2/teams/{{$stateParams.team_id}}/access_list/', - search: { - order_by: 'username' - }, - type: 'collection', - title: i18n._('Users'), - iterator: 'user', - index: false, - open: false, - actions: { - add: { - ngClick: "$state.go('.add')", - label: i18n._('Add'), - awToolTip: i18n._('Add User'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - fields: { - username: { - key: true, - label: i18n._('User'), - linkBase: 'users', - class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' - }, - role: { - label: i18n._('Role'), - type: 'role', - nosort: true, - class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4' - } - } - }, - permissions: { - name: 'permissions', - basePath: 'api/v2/teams/{{$stateParams.team_id}}/roles/', - search: { - page_size: '10', - // @todo ask about name field / serializer on this endpoint - order_by: 'id' - }, - awToolTip: i18n._('Please save before assigning permissions.'), - dataPlacement: 'top', - hideSearchAndActions: true, - type: 'collection', - title: i18n._('Permissions'), - iterator: 'permission', - open: false, - index: false, - emptyListText: i18n._('No permissions have been granted'), - fields: { - name: { - label: i18n._('Name'), - ngBind: 'permission.summary_fields.resource_name', - ngClick: "redirectToResource(permission)", - nosort: true - }, - type: { - label: i18n._('Type'), - ngBind: 'permission.summary_fields.resource_type_display_name', - nosort: true - }, - role: { - label: i18n._('Role'), - ngBind: 'permission.name', - nosort: true - } - }, - fieldActions: { - "delete": { - label: i18n._('Remove'), - ngClick: 'deletePermissionFromTeam(team_id, team_obj.name, permission.name, permission.summary_fields.resource_name, permission.related.teams)', - 'class': "List-actionButton--delete", - iconClass: 'fa fa-times', - awToolTip: i18n._('Dissasociate permission from team'), - dataPlacement: 'top', - ngShow: 'permission.summary_fields.user_capabilities.unattach' - } - }, - actions: { - add: { - ngClick: "$state.go('.add')", - label: 'Add', - awToolTip: i18n._('Grant Permission'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)' - } - } - } - }, - };}]; diff --git a/awx/ui/client/src/teams/teams.list.js b/awx/ui/client/src/teams/teams.list.js deleted file mode 100644 index 6de884f04041..000000000000 --- a/awx/ui/client/src/teams/teams.list.js +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['i18n', function(i18n) { - return { - - name: 'teams', - iterator: 'team', - selectTitle: i18n._('Add Team'), - editTitle: i18n._('TEAMS'), - listTitle: i18n._('TEAMS'), - selectInstructions: i18n.sprintf(i18n._("Click on a row to select it, and click Finished when done. Click the %s button to create a new team."), " "), - index: false, - hover: true, - - fields: { - name: { - key: true, - label: i18n._('Name'), - columnClass: 'col-lg-3 col-md-4 col-sm-9 col-xs-9', - modalColumnClass: 'col-md-8', - awToolTip: '{{team.description | sanitize}}', - dataPlacement: 'top' - }, - organization: { - label: i18n._('Organization'), - ngBind: 'team.summary_fields.organization.name', - sourceModel: 'organization', - sourceField: 'name', - columnClass: 'col-md-3 hidden-sm hidden-xs', - excludeModal: true - } - }, - - actions: { - add: { - mode: 'all', // One of: edit, select, all - ngClick: 'addTeam()', - awToolTip: i18n._('Create a new team'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd && canEdit' - } - }, - - fieldActions: { - - columnClass: 'col-lg-3 col-md-2 col-sm-3 col-xs-3', - - edit: { - label: i18n._('Edit'), - ngClick: "editTeam(team.id)", - icon: 'icon-edit', - "class": 'btn-xs btn-default', - awToolTip: i18n._('Edit team'), - dataPlacement: 'top', - ngShow: 'team.summary_fields.user_capabilities.edit' - }, - view: { - label: i18n._('View'), - ngClick: "editTeam(team.id)", - "class": 'btn-xs btn-default', - awToolTip: i18n._('View team'), - dataPlacement: 'top', - ngShow: '!team.summary_fields.user_capabilities.edit' - }, - "delete": { - label: i18n._('Delete'), - ngClick: "deleteTeam(team.id, team.name)", - icon: 'icon-trash', - "class": 'btn-xs btn-danger', - awToolTip: i18n._('Delete team'), - dataPlacement: 'top', - ngShow: 'team.summary_fields.user_capabilities.delete' - } - } - };}]; diff --git a/awx/ui/client/src/templates/inventory-sources.list.js b/awx/ui/client/src/templates/inventory-sources.list.js deleted file mode 100644 index 712a81835fa7..000000000000 --- a/awx/ui/client/src/templates/inventory-sources.list.js +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default { - name: 'workflow_inventory_sources', - iterator: 'inventory_source', - basePath: 'inventory_sources', - listTitle: 'INVENTORY SOURCES', - index: false, - hover: true, - searchBarFullWidth: true, - - fields: { - name: { - label: 'Name', - columnClass: 'col-md-11', - simpleTip: { - awToolTip: "Inventory: {{inventory_source.summary_fields.inventory.name}}", - dataPlacement: "top" - } - } - }, - - actions: {}, - - fieldActions: {} -}; diff --git a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js deleted file mode 100644 index be9ebd5ed38c..000000000000 --- a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js +++ /dev/null @@ -1,499 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - [ '$filter', '$scope', - '$stateParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', - 'ProcessErrors', 'GetBasePath', 'md5Setup', 'ParseTypeChange', 'Wait', - 'Empty', 'ToJSON', 'CallbackHelpInit', 'GetChoices', '$state', 'availableLabels', - 'CreateSelect2', '$q', 'i18n', 'Inventory', 'Project', 'InstanceGroupsService', - 'MultiCredentialService', 'ConfigData', 'resolvedModels', - function( - $filter, $scope, - $stateParams, JobTemplateForm, GenerateForm, Rest, Alert, - ProcessErrors, GetBasePath, md5Setup, ParseTypeChange, Wait, - Empty, ToJSON, CallbackHelpInit, GetChoices, - $state, availableLabels, CreateSelect2, $q, i18n, Inventory, Project, InstanceGroupsService, - MultiCredentialService, ConfigData, resolvedModels - ) { - - // Inject dynamic view - let defaultUrl = GetBasePath('job_templates'), - form = JobTemplateForm(), - generator = GenerateForm, - master = {}, - selectPlaybook, checkSCMStatus, - callback; - - const jobTemplate = resolvedModels[0]; - - $scope.canAddJobTemplate = jobTemplate.options('actions.POST'); - - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - $scope.can_edit = true; - $scope.allow_callbacks = false; - $scope.playbook_options = []; - $scope.mode = "add"; - $scope.parseType = 'yaml'; - $scope.credentialNotPresent = false; - $scope.canGetAllRelatedResources = true; - - md5Setup({ - scope: $scope, - master: master, - check_field: 'allow_callbacks', - default_val: false - }); - CallbackHelpInit({ scope: $scope }); - - $scope.surveyTooltip = i18n._('Please save before adding a survey to this job template.'); - - MultiCredentialService.getCredentialTypes() - .then(({ data }) => { - $scope.multiCredential = { - credentialTypes: data.results, - selectedCredentials: [] - }; - }); - - callback = function() { - // Make sure the form controller knows there was a change - $scope[form.name + '_form'].$setDirty(); - }; - - var selectCount = 0; - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReadyVerbosity', function () { - ParseTypeChange({ - scope: $scope, - field_id: 'extra_vars', - variable: 'extra_vars', - onChange: callback - }); - - selectCount++; - if (selectCount === 3) { - var verbosity; - // this sets the default options for the selects as specified by the controller. - for (verbosity in $scope.verbosity_options) { - if ($scope.verbosity_options[verbosity].isDefault) { - $scope.verbosity = $scope.verbosity_options[verbosity]; - } - } - $scope.job_type = $scope.job_type_options[form.fields.job_type.default]; - $scope.custom_virtualenvs_options = ConfigData.custom_virtualenvs; - - CreateSelect2({ - element:'#job_template_job_type', - multiple: false - }); - CreateSelect2({ - element:'#job_template_labels', - multiple: true, - addNew: true - }); - CreateSelect2({ - element:'#playbook-select', - multiple: false - }); - CreateSelect2({ - element:'#job_template_verbosity', - multiple: false - }); - CreateSelect2({ - element:'#job_template_job_tags', - multiple: true, - addNew: true - }); - - CreateSelect2({ - element:'#job_template_skip_tags', - multiple: true, - addNew: true - }); - - CreateSelect2({ - element: '#job_template_custom_virtualenv', - multiple: false, - opts: $scope.custom_virtualenvs_options - }); - } - }); - - // setup verbosity options select - GetChoices({ - scope: $scope, - url: defaultUrl, - field: 'verbosity', - variable: 'verbosity_options', - callback: 'choicesReadyVerbosity' - }); - - // setup job type options select - GetChoices({ - scope: $scope, - url: defaultUrl, - field: 'job_type', - variable: 'job_type_options', - callback: 'choicesReadyVerbosity' - }); - - $scope.labelOptions = availableLabels - .map((i) => ({label: i.name, value: i.id})); - $scope.$emit("choicesReadyVerbosity"); - - function sync_playbook_select2() { - CreateSelect2({ - element:'#playbook-select', - multiple: false - }); - } - - $scope.toggleForm = function(key) { - $scope[key] = !$scope[key]; - }; - - // Update playbook select whenever project value changes - selectPlaybook = function (oldValue, newValue) { - var url; - if (oldValue !== newValue) { - if ($scope.project) { - Wait('start'); - url = GetBasePath('projects') + $scope.project + '/playbooks/'; - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - var i, opts = []; - for (i = 0; i < data.length; i++) { - opts.push(data[i]); - } - $scope.playbook_options = opts; - sync_playbook_select2(); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to get playbook list for ' + url + '. GET returned status: ' + status }); - }); - } - } - }; - - $scope.jobTypeChange = function() { - sync_playbook_select2(); - }; - - // Detect and alert user to potential SCM status issues - checkSCMStatus = function (oldValue, newValue) { - if (oldValue !== newValue && !Empty($scope.project)) { - Rest.setUrl(GetBasePath('projects') + $scope.project + '/'); - Rest.get() - .then(({data}) => { - var msg; - switch (data.status) { - case 'failed': - msg = "
The Project selected has a status of \"failed\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook."; - break; - case 'never updated': - msg = "
The Project selected has a status of \"never updated\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook."; - break; - case 'missing': - msg = '
The selected project has a status of \"missing\". Please check the server and make sure ' + - ' the directory exists and file permissions are set correctly.
'; - break; - } - if (msg) { - Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to get project ' + $scope.project + '. GET returned status: ' + status }); - }); - } - }; - - if(Inventory){ - $scope.inventory = Inventory.id; - $scope.inventory_name = Inventory.name; - } - if(Project){ - $scope.project = Project.id; - $scope.project_name = Project.name; - selectPlaybook('force_load'); - checkSCMStatus(); - } - - // Register a watcher on project_name - if ($scope.selectPlaybookUnregister) { - $scope.selectPlaybookUnregister(); - } - $scope.selectPlaybookUnregister = $scope.$watch('project', function (newValue, oldValue) { - if (newValue !== oldValue) { - selectPlaybook(oldValue, newValue); - checkSCMStatus(); - } - }); - - if ($scope.removeSurveySaved) { - $scope.removeSurveySaved(); - } - $scope.removeSurveySaved = $scope.$on('SurveySaved', function() { - Wait('stop'); - $scope.survey_exists = true; - $scope.invalid_survey = false; - }); - - - function saveCompleted(id) { - $state.go('templates.editJobTemplate', {job_template_id: id}, {reload: true}); - } - - // Save - $scope.formSave = function () { - var fld, data = {}; - $scope.invalid_survey = false; - - // Can't have a survey enabled without a survey - if($scope.survey_enabled === true && - $scope.survey_exists !== true){ - $scope.survey_enabled = false; - } - - generator.clearApiErrors($scope); - - Wait('start'); - - try { - for (fld in form.fields) { - if (form.fields[fld].type === 'select' && - fld !== 'playbook' && fld !== 'custom_virtualenv' && $scope[fld]) { - data[fld] = $scope[fld].value; - } - else if(form.fields[fld].type === 'checkbox_group') { - // Loop across the checkboxes - for(var i=0; i option").filter("[data-select2-tag=true]").each(function(optionIndex, option) { - $("#job_template_labels").siblings(".select2").first().find(".select2-selection__choice").each(function(labelIndex, label) { - if($(option).text() === $(label).attr('title')) { - // Mark that the option has a label present so that we can filter by that down below - $(option).attr('data-label-is-present', true); - } - }); - }); - - $scope.newLabels = $("#job_template_labels > option") - .filter("[data-select2-tag=true]") - .filter("[data-label-is-present=true]") - .map((i, val) => ({name: $(val).text()})); - - $scope.job_tags = _.map($scope.job_tags, function(i){return i.value;}); - $("#job_template_job_tags").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ - $scope.job_tags.push(option.title); - }); - - $scope.skip_tags = _.map($scope.skip_tags, function(i){return i.value;}); - $("#job_template_skip_tags").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ - $scope.skip_tags.push(option.title); - }); - - data.job_tags = (Array.isArray($scope.job_tags)) ? _.uniq($scope.job_tags).join() : ""; - data.skip_tags = (Array.isArray($scope.skip_tags)) ? _.uniq($scope.skip_tags).join() : ""; - - Rest.setUrl(defaultUrl); - Rest.post(data) - .then(({data}) => { - if (data.related && data.related.callback) { - Alert('Callback URL', - `Host callbacks are enabled for this template. The callback URL is: -

- - ${$scope.callback_server_path} - ${data.related.callback} - -

-

The host configuration key is: - - ${$filter('sanitize')(data.host_config_key)} - -

`, - 'alert-danger', saveCompleted, null, null, - null, true); - } - - var orgDefer = $q.defer(); - var associationDefer = $q.defer(); - Rest.setUrl(data.related.labels); - - var currentLabels = Rest.get() - .then(function(data) { - return data.data.results - .map(val => val.id); - }); - - currentLabels.then(function (current) { - var labelsToAdd = ($scope.labels || []) - .map(val => val.value); - var labelsToDisassociate = current - .filter(val => labelsToAdd - .indexOf(val) === -1) - .map(val => ({id: val, disassociate: true})); - var labelsToAssociate = labelsToAdd - .filter(val => current - .indexOf(val) === -1) - .map(val => ({id: val, associate: true})); - var pass = labelsToDisassociate - .concat(labelsToAssociate); - associationDefer.resolve(pass); - }); - - Rest.setUrl(GetBasePath("organizations")); - Rest.get() - .then(({data}) => { - orgDefer.resolve(data.results[0].id); - }); - - orgDefer.promise.then(function(orgId) { - var toPost = []; - $scope.newLabels = $scope.newLabels - .map(function(i, val) { - val.organization = orgId; - return val; - }); - - $scope.newLabels.each(function(i, val) { - toPost.push(val); - }); - - associationDefer.promise.then(function(arr) { - toPost = toPost - .concat(arr); - - Rest.setUrl(data.related.labels); - - var defers = []; - for (var i = 0; i < toPost.length; i++) { - defers.push(Rest.post(toPost[i])); - } - $q.all(defers) - .then(function() { - $scope.addedItem = data.id; - - if($scope.survey_questions && - $scope.survey_questions.length > 0){ - //once the job template information - // is saved we submit the survey - // info to the correct endpoint - var url = data.url+ 'survey_spec/'; - Rest.setUrl(url); - Rest.post({ name: $scope.survey_name, - description: $scope.survey_description, - spec: $scope.survey_questions }) - .then(() => { - Wait('stop'); - }) - .error(function (data, - status) { - ProcessErrors( - $scope, - data, - status, - form, - { - hdr: 'Error!', - msg: 'Failed to add new ' + - 'survey. Post returned ' + - 'status: ' + - status - }); - }); - } - - MultiCredentialService - .saveRelated(data, $scope.multiCredential.selectedCredentials) - .then(() => saveCompleted(data.id)); - }); - }); - }); - - const instance_group_url = data.related.instance_groups; - InstanceGroupsService.addInstanceGroups(instance_group_url, $scope.instance_groups) - .then(() => { - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to post instance groups. POST returned ' + - 'status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to add new job ' + - 'template. POST returned status: ' + status - }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error parsing extra variables. " + - "Parser returned: " + err); - } - }; - - $scope.formCancel = function () { - $state.transitionTo('templates'); - }; - } - ]; diff --git a/awx/ui/client/src/templates/job_templates/add-job-template/main.js b/awx/ui/client/src/templates/job_templates/add-job-template/main.js deleted file mode 100644 index fedbed489819..000000000000 --- a/awx/ui/client/src/templates/job_templates/add-job-template/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './job-template-add.controller'; - -export default - angular.module('jobTemplateAdd', []) - .controller('JobTemplateAdd', controller); diff --git a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js deleted file mode 100644 index 85bc0882a2ae..000000000000 --- a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js +++ /dev/null @@ -1,727 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:JobTemplatesEdit - * @description This controller's for Job Template Edit -*/ - -export default - [ '$filter', '$scope', '$rootScope', - '$location', '$stateParams', 'JobTemplateForm', 'GenerateForm', - 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', 'md5Setup', - 'ParseTypeChange', 'Wait', 'selectedLabels', 'i18n', - 'Empty', 'Prompt', 'ToJSON', 'GetChoices', 'CallbackHelpInit', - 'initSurvey', '$state', 'CreateSelect2', - 'ToggleNotification','$q', 'InstanceGroupsService', 'InstanceGroupsData', - 'MultiCredentialService', 'availableLabels', 'projectGetPermissionDenied', - 'inventoryGetPermissionDenied', 'jobTemplateData', 'ParseVariableString', 'ConfigData', - function( - $filter, $scope, $rootScope, - $location, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert, - ProcessErrors, GetBasePath, md5Setup, - ParseTypeChange, Wait, selectedLabels, i18n, - Empty, Prompt, ToJSON, GetChoices, CallbackHelpInit, - SurveyControllerInit, $state, CreateSelect2, - ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData, - MultiCredentialService, availableLabels, projectGetPermissionDenied, - inventoryGetPermissionDenied, jobTemplateData, ParseVariableString, ConfigData - ) { - - $scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) { - if (val === false) { - $scope.canAddJobTemplate = false; - } - }); - - let defaultUrl = GetBasePath('job_templates'), - generator = GenerateForm, - form = JobTemplateForm(), - master = {}, - id = $stateParams.job_template_id, - callback, - choicesCount = 0, - instance_group_url = defaultUrl + id + '/instance_groups'; - - init(); - function init() { - - CallbackHelpInit({ scope: $scope }); - - $scope.playbook_options = null; - $scope.playbook = null; - $scope.mode = 'edit'; - $scope.parseType = 'yaml'; - $scope.showJobType = false; - $scope.instance_groups = InstanceGroupsData; - $scope.credentialNotPresent = false; - $scope.surveyTooltip = i18n._('Surveys allow users to be prompted at job launch with a series of questions related to the job. This allows for variables to be defined that affect the playbook run at time of launch.'); - $scope.job_tag_options = []; - $scope.skip_tag_options = []; - $scope.custom_virtualenvs_options = ConfigData.custom_virtualenvs; - - SurveyControllerInit({ - scope: $scope, - parent_scope: $scope, - id: id, - templateType: 'job_template' - }); - - $scope.$watch('project', function (newValue, oldValue) { - if (newValue !== oldValue) { - var url; - if ($scope.playbook) { - $scope.playbook_options = [$scope.playbook]; - } - - if (!Empty($scope.project) && $scope.job_template_obj.summary_fields.user_capabilities.edit) { - let promises = []; - url = GetBasePath('projects') + $scope.project + '/playbooks/'; - Wait('start'); - Rest.setUrl(url); - promises.push(Rest.get() - .then(({data}) => { - $scope.disablePlaybookBecausePermissionDenied = false; - $scope.playbook_options = []; - var playbookNotFound = true; - for (var i = 0; i < data.length; i++) { - $scope.playbook_options.push(data[i]); - if (data[i] === $scope.playbook) { - $scope.job_template_form.playbook.$setValidity('required', true); - playbookNotFound = false; - } - } - $scope.playbookNotFound = playbookNotFound; - sync_playbook_select2(); - if ($scope.playbook) { - jobTemplateLoadFinished(); - } - }) - .catch( (error) => { - if (error.status === 403) { - /* user doesn't have access to see the project, no big deal. */ - $scope.disablePlaybookBecausePermissionDenied = true; - } else { - Alert('Missing Playbooks', 'Unable to retrieve the list of playbooks for this project. Choose a different ' + - ' project or make the playbooks available on the file system.', 'alert-info'); - } - Wait('stop'); - })); - - - Rest.setUrl(GetBasePath('projects') + $scope.project + '/'); - promises.push(Rest.get() - .then(({data}) => { - var msg; - switch (data.status) { - case 'failed': - msg = "
The Project selected has a status of \"failed\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook."; - break; - case 'never updated': - msg = "
The Project selected has a status of \"never updated\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook."; - break; - case 'missing': - msg = '
The selected project has a status of \"missing\". Please check the server and make sure ' + - ' the directory exists and file permissions are set correctly.
'; - break; - } - if (msg) { - Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true); - } - }) - .catch(({data, status}) => { - if (status === 403) { - /* User doesn't have read access to the project, no problem. */ - } else { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to get project ' + $scope.project + - '. GET returned status: ' + status }); - } - })); - - $q.all(promises) - .then(function(){ - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call failed. Returned status: ' + status - }); - }); - } - } - }); - - // watch for changes to 'verbosity', ensure we keep our select2 in sync when it changes. - $scope.$watch('verbosity', sync_verbosity_select2); - } - - callback = function() { - // Make sure the form controller knows there was a change - $scope[form.name + '_form'].$setDirty(); - }; - - function sync_playbook_select2() { - CreateSelect2({ - element:'#playbook-select', - multiple: false - }); - } - - function sync_verbosity_select2() { - CreateSelect2({ - element:'#job_template_verbosity', - multiple: false - }); - } - - function jobTemplateLoadFinished(){ - CreateSelect2({ - element:'#job_template_job_type', - multiple: false - }); - - CreateSelect2({ - element:'#playbook-select', - multiple: false - }); - - CreateSelect2({ - element:'#job_template_job_tags', - multiple: true, - addNew: true - }); - - CreateSelect2({ - element:'#job_template_skip_tags', - multiple: true, - addNew: true - }); - - CreateSelect2({ - element: '#job_template_custom_virtualenv', - multiple: false, - opts: $scope.custom_virtualenvs_options - }); - } - - $scope.toggleForm = function(key) { - $scope[key] = !$scope[key]; - }; - - $scope.jobTypeChange = function() { - sync_playbook_select2(); - }; - - $scope.toggleNotification = function(event, notifier_id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } - catch(e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: defaultUrl + id, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - - // Retrieve each related set and populate the playbook list - if ($scope.jobTemplateLoadedRemove) { - $scope.jobTemplateLoadedRemove(); - } - $scope.jobTemplateLoadedRemove = $scope.$on('jobTemplateLoaded', function (e, masterObject) { - var dft; - - master = masterObject; - - dft = ($scope.host_config_key === "" || $scope.host_config_key === null) ? false : true; - md5Setup({ - scope: $scope, - master: master, - check_field: 'allow_callbacks', - default_val: dft - }); - - ParseTypeChange({ - scope: $scope, - field_id: 'extra_vars', - variable: 'extra_vars', - onChange: callback - }); - - jobTemplateLoadFinished(); - }); - - Wait('start'); - - if ($scope.removeSurveySaved) { - $scope.removeSurveySaved(); - } - $scope.removeSurveySaved = $scope.$on('SurveySaved', function() { - Wait('stop'); - $scope.survey_exists = true; - $scope.invalid_survey = false; - }); - - if ($scope.removeLoadJobs) { - $scope.rmoveLoadJobs(); - } - $scope.removeLoadJobs = $scope.$on('LoadJobs', function() { - $scope.job_template_obj = jobTemplateData; - $scope.name = jobTemplateData.name; - $scope.breadcrumb.job_template_name = jobTemplateData.name; - var fld, i; - for (fld in form.fields) { - if (fld !== 'extra_vars' && fld !== 'survey' && fld !== 'forks' && jobTemplateData[fld] !== null && jobTemplateData[fld] !== undefined) { - if (form.fields[fld].type === 'select') { - if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) { - for (i = 0; i < $scope[fld + '_options'].length; i++) { - if (jobTemplateData[fld] === $scope[fld + '_options'][i].value) { - $scope[fld] = $scope[fld + '_options'][i]; - } - } - } else { - $scope[fld] = jobTemplateData[fld]; - } - } else { - $scope[fld] = jobTemplateData[fld]; - if(!Empty(jobTemplateData.summary_fields.survey)) { - $scope.survey_exists = true; - } - } - master[fld] = $scope[fld]; - } - if (fld === 'forks') { - if (jobTemplateData[fld] !== 0) { - $scope[fld] = jobTemplateData[fld]; - master[fld] = $scope[fld]; - } - } - if (fld === 'extra_vars') { - // Parse extra_vars, converting to YAML. - $scope.extra_vars = ParseVariableString(jobTemplateData.extra_vars); - master.extra_vars = $scope.extra_vars; - } - if (form.fields[fld].type === 'lookup' && jobTemplateData.summary_fields[form.fields[fld].sourceModel]) { - $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - jobTemplateData.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; - } - if (form.fields[fld].type === 'checkbox_group') { - for(var j=0; j ({name: i, label: i, value: i})) : []; - $scope.job_tags = $scope.job_tag_options; - master.job_tags = $scope.job_tags; - - $scope.skip_tag_options = (jobTemplateData.skip_tags) ? jobTemplateData.skip_tags.split(',') - .map((i) => ({name: i, label: i, value: i})) : []; - $scope.skip_tags = $scope.skip_tag_options; - master.skip_tags = $scope.skip_tags; - - $scope.ask_job_type_on_launch = (jobTemplateData.ask_job_type_on_launch) ? true : false; - master.ask_job_type_on_launch = $scope.ask_job_type_on_launch; - - $scope.ask_inventory_on_launch = (jobTemplateData.ask_inventory_on_launch) ? true : false; - master.ask_inventory_on_launch = $scope.ask_inventory_on_launch; - - $scope.ask_credential_on_launch = (jobTemplateData.ask_credential_on_launch) ? true : false; - master.ask_credential_on_launch = $scope.ask_credential_on_launch; - - if (jobTemplateData.host_config_key) { - $scope.example_config_key = jobTemplateData.host_config_key; - } - $scope.example_template_id = id; - $scope.setCallbackHelp(); - - $scope.callback_url = $scope.callback_server_path + ((jobTemplateData.related.callback) ? jobTemplateData.related.callback : - GetBasePath('job_templates') + id + '/callback/'); - master.callback_url = $scope.callback_url; - - $scope.can_edit = jobTemplateData.summary_fields.user_capabilities.edit; - - const multiCredential = {}; - const credentialTypesPromise = MultiCredentialService.getCredentialTypes() - .then(({ data }) => { - multiCredential.credentialTypes = data.results; - }); - const multiCredentialPromises = [credentialTypesPromise]; - - if ($scope.can_edit) { - const selectedCredentialsPromise = MultiCredentialService - .getRelated(jobTemplateData, { permitted: [403] }) - .then(({ data, status }) => { - if (status === 403) { - $scope.canGetAllRelatedResources = false; - multiCredential.selectedCredentials = _.get(jobTemplateData, 'summary_fields.credentials'); - } else { - $scope.canGetAllRelatedResources = !projectGetPermissionDenied && !inventoryGetPermissionDenied; - multiCredential.selectedCredentials = data.results; - } - }); - - multiCredentialPromises.push(selectedCredentialsPromise); - } else { - $scope.canGetAllRelatedResources = false; - multiCredential.selectedCredentials = _.get(jobTemplateData, 'summary_fields.credentials'); - } - - $q.all(multiCredentialPromises) - .then(() => { - $scope.multiCredential = multiCredential; - $scope.$emit('jobTemplateLoaded', master); - }); - }); - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReady', function() { - choicesCount++; - if (choicesCount === 5) { - $scope.$emit('LoadJobs'); - } - }); - - GetChoices({ - scope: $scope, - url: GetBasePath('unified_jobs'), - field: 'status', - variable: 'status_choices', - callback: 'choicesReady' - }); - - GetChoices({ - scope: $scope, - url: GetBasePath('unified_jobs'), - field: 'type', - variable: 'type_choices', - callback: 'choicesReady' - }); - - // setup verbosity options lookup - GetChoices({ - scope: $scope, - url: defaultUrl, - field: 'verbosity', - variable: 'verbosity_options', - callback: 'choicesReady' - }); - sync_verbosity_select2(); - - // setup job type options lookup - GetChoices({ - scope: $scope, - url: defaultUrl, - field: 'job_type', - variable: 'job_type_options', - callback: 'choicesReady' - }); - - $scope.labelOptions = availableLabels - .map((i) => ({label: i.name, value: i.id})); - - var opts = selectedLabels - .map(i => ({id: i.id + "", - test: i.name})); - - CreateSelect2({ - element:'#job_template_labels', - multiple: true, - addNew: true, - opts: opts - }); - - $scope.$emit("choicesReady"); - - function saveCompleted() { - $state.go($state.current, {}, {reload: true}); - } - - if ($scope.removeTemplateSaveSuccess) { - $scope.removeTemplateSaveSuccess(); - } - $scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) { - - if (data.related && - data.related.callback) { - Alert('Callback URL', -`Host callbacks are enabled for this template. The callback URL is: -

- - ${$scope.callback_server_path}${data.related.callback} - -

-

The host configuration key is: - - ${$filter('sanitize')(data.host_config_key)} - -

-`, - 'alert-danger', saveCompleted, null, null, - null, true); - } - - MultiCredentialService - .saveRelated(jobTemplateData, $scope.multiCredential.selectedCredentials); - - InstanceGroupsService.editInstanceGroups(instance_group_url, $scope.instance_groups) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update instance groups. POST returned status: ' + status - }); - }); - - - var orgDefer = $q.defer(); - var associationDefer = $q.defer(); - var associatedLabelsDefer = $q.defer(); - - var getNext = function(data, arr, resolve) { - Rest.setUrl(data.next); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, arr.concat(data.results), resolve); - } else { - resolve.resolve(arr.concat(data.results)); - } - }); - }; - - Rest.setUrl(data.related.labels); - - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, data.results, associatedLabelsDefer); - } else { - associatedLabelsDefer.resolve(data.results); - } - }); - - associatedLabelsDefer.promise.then(function (current) { - current = current.map(data => data.id); - var labelsToAdd = $scope.labels - .map(val => val.value); - var labelsToDisassociate = current - .filter(val => labelsToAdd - .indexOf(val) === -1) - .map(val => ({id: val, disassociate: true})); - var labelsToAssociate = labelsToAdd - .filter(val => current - .indexOf(val) === -1) - .map(val => ({id: val, associate: true})); - var pass = labelsToDisassociate - .concat(labelsToAssociate); - associationDefer.resolve(pass); - }); - - Rest.setUrl(GetBasePath("organizations")); - Rest.get() - .then(({data}) => { - orgDefer.resolve(data.results[0].id); - }); - - orgDefer.promise.then(function(orgId) { - var toPost = []; - $scope.newLabels = $scope.newLabels - .map(function(i, val) { - val.organization = orgId; - return val; - }); - - $scope.newLabels.each(function(i, val) { - toPost.push(val); - }); - - associationDefer.promise.then(function(arr) { - toPost = toPost - .concat(arr); - - Rest.setUrl(data.related.labels); - - var defers = []; - for (var i = 0; i < toPost.length; i++) { - defers.push(Rest.post(toPost[i])); - } - $q.all(defers) - .then(function() { - Wait('stop'); - saveCompleted(); - }); - }); - }); - }); - - - - // Save changes to the parent - // Save - $scope.formSave = function () { - var fld, data = {}; - $scope.invalid_survey = false; - - // Can't have a survey enabled without a survey - if($scope.survey_enabled === true && - $scope.survey_exists!==true){ - $scope.survey_enabled = false; - } - - generator.clearApiErrors($scope); - - Wait('start'); - - try { - for (fld in form.fields) { - if (form.fields[fld].type === 'select' && - fld !== 'playbook' && fld !== 'custom_virtualenv' && $scope[fld]) { - data[fld] = $scope[fld].value; - } - else if(form.fields[fld].type === 'checkbox_group') { - // Loop across the checkboxes - for(var i=0; i option").filter("[data-select2-tag=true]").each(function(optionIndex, option) { - $("#job_template_labels").siblings(".select2").first().find(".select2-selection__choice").each(function(labelIndex, label) { - if($(option).text() === $(label).attr('title')) { - // Mark that the option has a label present so that we can filter by that down below - $(option).attr('data-label-is-present', true); - } - }); - }); - - $scope.newLabels = $("#job_template_labels > option") - .filter("[data-select2-tag=true]") - .filter("[data-label-is-present=true]") - .map((i, val) => ({name: $(val).text()})); - - $scope.job_tags = _.map($scope.job_tags, function(i){return i.value;}); - $("#job_template_job_tags").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ - $scope.job_tags.push(option.title); - }); - - $scope.skip_tags = _.map($scope.skip_tags, function(i){return i.value;}); - $("#job_template_skip_tags").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ - $scope.skip_tags.push(option.title); - }); - - data.job_tags = (Array.isArray($scope.job_tags)) ? _.uniq($scope.job_tags).join() : ""; - data.skip_tags = (Array.isArray($scope.skip_tags)) ? _.uniq($scope.skip_tags).join() : ""; - - // drop legacy 'credential' and 'vault_credential' keys from the update request as they will - // be provided to the related credentials endpoint by the template save success handler. - delete data.credential; - delete data.vault_credential; - - Rest.setUrl(defaultUrl + $state.params.job_template_id); - Rest.put(data) - .then(({data}) => { - $scope.$emit('templateSaveSuccess', data); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to update job template. PUT returned status: ' + status }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error saving job template. " + - "Error: " + err); - } - }; - - $scope.formCancel = function () { - $state.go('templates'); - }; - } - ]; diff --git a/awx/ui/client/src/templates/job_templates/edit-job-template/main.js b/awx/ui/client/src/templates/job_templates/edit-job-template/main.js deleted file mode 100644 index ede92fbe00d9..000000000000 --- a/awx/ui/client/src/templates/job_templates/edit-job-template/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import controller from './job-template-edit.controller'; - -export default - angular.module('jobTemplateEdit', []) - .controller('JobTemplateEdit', controller); diff --git a/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js b/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js deleted file mode 100644 index e1c027a4e0cd..000000000000 --- a/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js +++ /dev/null @@ -1,47 +0,0 @@ -export default - function CallbackHelpInit($q, $location, GetBasePath, Rest, JobTemplateForm, GenerateForm, $stateParams, ProcessErrors, - ParseVariableString, Empty, Wait, MultiCredentialService, $rootScope) { - return function(params) { - var scope = params.scope; - // checkSCMStatus, getPlaybooks, callback, - // choicesCount = 0; - - // The form uses awPopOverWatch directive to 'watch' scope.callback_help for changes. Each time the - // popover is activated, a function checks the value of scope.callback_help before constructing the content. - scope.setCallbackHelp = function() { - scope.callback_help = "

With a provisioning callback URL and a host config key a host can contact " + $rootScope.BRAND_NAME + " and request a configuration update using this job " + - "template. The request from the host must be a POST. Here is an example using curl:

\n" + - "
curl --data \"host_config_key=" + scope.example_config_key + "\" " +
-                    scope.callback_server_path + GetBasePath('job_templates') + scope.example_template_id + "/callback/
\n" + - "

Note the requesting host must be defined in the inventory associated with the job template. If " + $rootScope.BRAND_NAME + " fails to " + - "locate the host, the request will be denied.

" + - "

Successful requests create an entry on the Jobs page, where results and history can be viewed.

"; - }; - - // The md5 helper emits NewMD5Generated whenever a new key is available - if (scope.removeNewMD5Generated) { - scope.removeNewMD5Generated(); - } - scope.removeNewMD5Generated = scope.$on('NewMD5Generated', function() { - scope.configKeyChange(); - }); - - // Fired when user enters a key value - scope.configKeyChange = function() { - scope.example_config_key = scope.host_config_key; - scope.setCallbackHelp(); - }; - - // Set initial values and construct help text - scope.callback_server_path = $location.protocol() + '://' + $location.host() + (($location.port()) ? ':' + $location.port() : ''); - scope.example_config_key = '5a8ec154832b780b9bdef1061764ae5a'; - scope.example_template_id = 'N'; - scope.setCallbackHelp(); - }; - } - -CallbackHelpInit.$inject = - [ '$q', '$location', 'GetBasePath', 'Rest', 'JobTemplateForm', 'GenerateForm', - '$stateParams', 'ProcessErrors', 'ParseVariableString', - 'Empty', 'Wait', 'MultiCredentialService', '$rootScope' - ]; diff --git a/awx/ui/client/src/templates/job_templates/factories/md-5-setup.factory.js b/awx/ui/client/src/templates/job_templates/factories/md-5-setup.factory.js deleted file mode 100644 index bce1485d7aea..000000000000 --- a/awx/ui/client/src/templates/job_templates/factories/md-5-setup.factory.js +++ /dev/null @@ -1,30 +0,0 @@ -export default - function md5Setup(md5) { - return function(params) { - var scope = params.scope, - master = params.master, - check_field = params.check_field, - default_val = params.default_val; - - scope[check_field] = default_val; - master[check_field] = default_val; - - scope.genMD5 = function (fld) { - var now = new Date(); - scope[fld] = md5.createHash('AnsibleWorks' + now.getTime()); - scope.$emit('NewMD5Generated'); - }; - - scope.toggleCallback = function (fld) { - if (scope.allow_callbacks === false) { - scope[fld] = ''; - } - }; - - scope.selectAll = function (fld) { - $('input[name="' + fld + '"]').focus().select(); - }; - }; - } - -md5Setup.$inject = [ 'md5' ]; diff --git a/awx/ui/client/src/templates/job_templates/job-template.form.js b/awx/ui/client/src/templates/job_templates/job-template.form.js deleted file mode 100644 index bfc1073c7fdb..000000000000 --- a/awx/ui/client/src/templates/job_templates/job-template.form.js +++ /dev/null @@ -1,489 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name forms.function:JobTemplate - * @description This form is for adding/editing a Job Template -*/ - - -export default ['NotificationsList', 'i18n', -function(NotificationsList, i18n) { - return function() { - var JobTemplateFormObject = { - - addTitle: i18n._('NEW JOB TEMPLATE'), - editTitle: '{{ name }}', - name: 'job_template', - breadcrumbName: i18n._('JOB TEMPLATE'), - basePath: 'job_templates', - // the top-most node of generated state tree - stateTree: 'templates', - tabs: true, - activeEditState: 'templates.editJobTemplate', - // (optional) array of supporting templates to ng-include inside generated html - include: ['/static/partials/survey-maker-modal.html'], - detailsClick: "$state.go('templates.editJobTemplate')", - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)', - required: true, - column: 1 - }, - description: { - label: i18n._('Description'), - type: 'text', - column: 1, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - job_type: { - label: i18n._('Job Type'), - type: 'select', - ngOptions: 'type.label for type in job_type_options track by type.value', - ngChange: 'jobTypeChange()', - "default": 0, - required: true, - column: 1, - awPopOver: i18n._('For job templates, select run to execute the playbook. Select check to only check playbook syntax, test environment setup, and report problems without executing the playbook.'), - dataTitle: i18n._('Job Type'), - dataPlacement: 'right', - dataContainer: "body", - subCheckbox: { - variable: 'ask_job_type_on_launch', - text: i18n._('Prompt on launch'), - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - inventory: { - label: i18n._('Inventory'), - type: 'lookup', - basePath: 'inventory', - list: 'InventoryList', - sourceModel: 'inventory', - sourceField: 'name', - autopopulateLookup: false, - awRequiredWhen: { - reqExpression: '!ask_inventory_on_launch', - alwaysShowAsterisk: true - }, - requiredErrorMsg: i18n._("Please select an Inventory or check the Prompt on launch option."), - column: 1, - awPopOver: "

" + i18n._("Select the inventory containing the hosts you want this job to manage.") + "

", - dataTitle: i18n._('Inventory'), - dataPlacement: 'right', - dataContainer: "body", - subCheckbox: { - variable: 'ask_inventory_on_launch', - ngChange: 'job_template_form.inventory_name.$validate()', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canGetAllRelatedResources' - }, - project: { - label: i18n._('Project'), - type: 'lookup', - list: 'ProjectList', - basePath: 'projects', - sourceModel: 'project', - sourceField: 'name', - required: true, - column: 1, - awPopOver: "

" + i18n._("Select the project containing the playbook you want this job to execute.") + "

", - dataTitle: i18n._('Project'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canGetAllRelatedResources', - awLookupWhen: 'canGetAllRelatedResources' - }, - playbook: { - label: i18n._('Playbook'), - type:'select', - ngOptions: 'book for book in playbook_options track by book', - ngDisabled: "!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canGetAllRelatedResources", - id: 'playbook-select', - required: true, - column: 1, - awPopOver: "

" + i18n._("Select the playbook to be executed by this job.") + "

", - dataTitle: i18n._('Playbook'), - dataPlacement: 'right', - dataContainer: "body", - includePlaybookNotFoundError: true - }, - credential: { - label: i18n._('Credential'), - type: 'custom', - control: ` - - `, - awPopOver: i18n._('Select credentials that allow Tower to access the nodes this job will be ran against. You can only select one credential of each type. For machine credentials (SSH), checking "Prompt on launch" without selecting credentials will require you to select a machine credential at run time. If you select credentials and check "Prompt on launch", the selected credential(s) become the defaults that can be updated at run time.'), - dataTitle: i18n._('Credentials'), - dataPlacement: 'right', - dataContainer: "body", - subCheckbox: { - variable: 'ask_credential_on_launch', - text: i18n._('Prompt on launch'), - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - } - }, - forks: { - label: i18n._('Forks'), - id: 'forks-number', - type: 'number', - integer: true, - min: 1, - spinner: true, - 'class': "input-small", - column: 1, - awPopOver: i18n._('The number of parallel or simultaneous processes to use while executing the playbook. Value defaults to 0. Refer to the Ansible documentation for details about the configuration file.'), - placeholder: 'DEFAULT', - dataTitle: i18n._('Forks'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - limit: { - label: i18n._('Limit'), - type: 'text', - column: 1, - awPopOver: i18n._('Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. Multiple patterns are allowed. Refer to Ansible documentation for more information and examples on patterns.'), - dataTitle: i18n._('Limit'), - dataPlacement: 'right', - dataContainer: "body", - subCheckbox: { - variable: 'ask_limit_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - verbosity: { - label: i18n._('Verbosity'), - type: 'select', - ngOptions: 'v.label for v in verbosity_options track by v.value', - "default": 1, - required: true, - column: 1, - awPopOver: "

" + i18n._("Control the level of output ansible will produce as the playbook executes.") + "

", - dataTitle: i18n._('Verbosity'), - dataPlacement: 'right', - dataContainer: "body", - subCheckbox: { - variable: 'ask_verbosity_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)', - }, - job_tags: { - label: i18n._('Job Tags'), - type: 'select', - multiSelect: true, - 'elementClass': 'Form-textInput', - ngOptions: 'tag.label for tag in job_tag_options track by tag.value', - column: 2, - awPopOver: i18n._('Tags are useful when you have a large playbook, and you want to run a specific part of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags.'), - dataTitle: i18n._("Job Tags"), - dataPlacement: "right", - dataContainer: "body", - subCheckbox: { - variable: 'ask_tags_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - skip_tags: { - label: i18n._('Skip Tags'), - type: 'select', - multiSelect: true, - 'elementClass': 'Form-textInput', - ngOptions: 'tag.label for tag in skip_tag_options track by tag.value', - column: 2, - awPopOver: i18n._('Skip tags are useful when you have a large playbook, and you want to skip specific parts of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags.'), - dataTitle: i18n._("Skip Tags"), - dataPlacement: "right", - dataContainer: "body", - subCheckbox: { - variable: 'ask_skip_tags_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - labels: { - label: i18n._('Labels'), - type: 'select', - ngOptions: 'label.label for label in labelOptions track by label.value', - multiSelect: true, - dataTitle: i18n._('Labels'), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.") + "

", - dataContainer: 'body', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - custom_virtualenv: { - label: i18n._('Ansible Environment'), - type: 'select', - defaultText: i18n._('Default Environment'), - ngOptions: 'venv for venv in custom_virtualenvs_options track by venv', - awPopOver: "

" + i18n._("Select the custom Python virtual environment for this job template to run on.") + "

", - dataTitle: i18n._('Ansible Environment'), - dataContainer: 'body', - dataPlacement: 'right', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)', - ngShow: 'custom_virtualenvs_options.length > 0' - }, - instance_groups: { - label: i18n._('Instance Groups'), - type: 'custom', - awPopOver: "

" + i18n._("Select the Instance Groups for this Job Template to run on.") + "

", - dataTitle: i18n._('Instance Groups'), - dataContainer: 'body', - dataPlacement: 'right', - control: '', - }, - diff_mode: { - label: i18n._('Show Changes'), - type: 'toggleSwitch', - toggleSource: 'diff_mode', - dataTitle: i18n._('Show Changes'), - dataPlacement: 'right', - dataContainer: 'body', - awPopOver: "

" + i18n._("If enabled, show the changes made by Ansible tasks, where supported. This is equivalent to Ansible’s --diff mode.") + "

", - subCheckbox: { - variable: 'ask_diff_mode_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - checkbox_group: { - label: i18n._('Options'), - type: 'checkbox_group', - fields: [{ - name: 'become_enabled', - label: i18n._('Enable Privilege Escalation'), - type: 'checkbox', - column: 2, - awPopOver: i18n._('If enabled, run this playbook as an administrator.'), - dataPlacement: 'right', - dataTitle: i18n._('Enable Privilege Escalation'), - dataContainer: "body", - labelClass: 'stack-inline', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, { - name: 'allow_callbacks', - label: i18n._('Allow Provisioning Callbacks'), - type: 'checkbox', - ngChange: "toggleCallback('host_config_key')", - column: 2, - awPopOver: "

" + i18n._("Enables creation of a provisioning callback URL. Using the URL a host can contact {{BRAND_NAME}} and request a configuration update " + - "using this job template.") + "

", - dataPlacement: 'right', - dataTitle: i18n._('Allow Provisioning Callbacks'), - dataContainer: "body", - labelClass: 'stack-inline', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, { - name: 'allow_simultaneous', - label: i18n._('Enable Concurrent Jobs'), - type: 'checkbox', - column: 2, - awPopOver: "

" + i18n._("If enabled, simultaneous runs of this job template will be allowed.") + "

", - dataPlacement: 'right', - dataTitle: i18n._('Enable Concurrent Jobs'), - dataContainer: "body", - labelClass: 'stack-inline', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, { - name: 'use_fact_cache', - label: i18n._('Use Fact Cache'), - type: 'checkbox', - column: 2, - awPopOver: "

" + i18n._("If enabled, use cached facts if available and store discovered facts in the cache.") + "

", - dataPlacement: 'right', - dataTitle: i18n._('Use Fact Cache'), - dataContainer: "body", - labelClass: 'stack-inline', - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }] - }, - callback_url: { - label: i18n._('Provisioning Callback URL'), - type: 'text', - readonly: true, - ngShow: "allow_callbacks && allow_callbacks !== 'false'", - column: 2, - awPopOver: "callback_help", - awPopOverWatch: "callback_help", - dataPlacement: 'top', - dataTitle: i18n._('Provisioning Callback URL'), - dataContainer: "body", - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' - }, - host_config_key: { - label: i18n._('Host Config Key'), - type: 'text', - ngShow: "allow_callbacks && allow_callbacks !== 'false'", - ngChange: "configKeyChange()", - genMD5: true, - column: 2, - awPopOver: "callback_help", - awPopOverWatch: "callback_help", - dataPlacement: 'right', - dataTitle: i18n._("Host Config Key"), - dataContainer: "body", - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)', - awRequiredWhen: { - reqExpression: 'allow_callbacks', - alwaysShowAsterisk: true - } - }, - extra_vars: { - label: i18n._('Extra Variables'), - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - "default": "---", - column: 2, - awPopOver: i18n._('Pass extra command line variables to the playbook. Provide key/value pairs using either YAML or JSON. Refer to the Ansible Tower documentation for example syntax.'), - dataTitle: i18n._('Extra Variables'), - dataPlacement: 'right', - dataContainer: "body", - id: 'extra_vars', - subCheckbox: { - variable: 'ask_variables_on_launch', - text: i18n._('Prompt on launch') - }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' // TODO: get working - } - }, - - buttons: { //for now always generates -
-
- - -
-
- diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less deleted file mode 100644 index 887cdb09617b..000000000000 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less +++ /dev/null @@ -1,165 +0,0 @@ -.MultiCredential-selectedBar { - display: flex; - padding: 5px 10px; - background: @default-no-items-bord; - margin-bottom: 20px; - border: 1px solid @default-icon-hov; - border-radius: 5px; - max-height: 120px; - overflow-y: auto; -} - -.MultiCredential-selectedBarLabel { - align-self: center; - margin-right: 20px; - font-size: 12px; - color: @default-icon; -} - -.MultiCredential-tags { - padding-left: 0px; -} - -.MultiCredential-bar i { - font-size: 16px; - color: @default-icon; -} - -.MultiCredential-flexContainer { - display: flex; - width: 100%; - flex-wrap: wrap; -} - -.MultiCredential-tagContainer { - display: flex; - max-width: 100%; - background-color: @default-link; - color: @default-bg; - border-radius: 5px; - padding: 0px 0px 0px 10px; - margin: 3px 10px 3px 0px; -} - -.MultiCredential-tagContainer--disabled { - background-color: @default-icon; -} - -.MultiCredential-tag { - font-size: 12px; - margin-right: 10px; - max-width: 100%; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - padding: 2px 0px 2px 15px; -} - -.MultiCredential-tag--disabled { - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - padding-left: 10px; -} - -.MultiCredential-tag--deletable { - margin-right: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - border-right: 0; - max-width: ~"calc(100% - 23px)"; - padding-left: 10px; -} - -.MultiCredential-deleteContainer { - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - padding: 2px 5px; - align-items: center; - display: flex; - cursor: pointer; -} - -.MultiCredential-tagDelete { - font-size: 11px; -} - -.MultiCredential-iconContainer { - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - padding: 0px 5px; - margin: 3px 0px; - margin-left: -3px; - align-items: center; - display: flex; -} - -.MultiCredential-iconContainer--disabled { - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - padding: 0 5px; - padding-left: 10px; - margin: 3px 0px; - align-items: center; - display: flex; -} - - -.MultiCredential-tagIcon { - margin: 0px 0px; - font-size: 12px; -} - -.MultiCredential-name { - flex: initial; - font-size: 12px; - max-width: 100%; -} - -.MultiCredential-name--label { - color: @default-list-header-bg; - font-size: 12px; - margin-left: -8px; - margin-right: 5px; -} - -.MultiCredential-tag--deletable > .MultiCredential-name { - max-width: ~"calc(100% - 23px)"; -} - -.MultiCredential-deleteContainer:hover { - border-color: @default-err; - background-color: @default-err!important; -} - -.MultiCredential-deleteContainer:hover > .MultiCredential-tagDelete { - color: @default-bg; -} - -.MultiCredential-credentialSubSection { - display: flex; - justify-content: flex-end; - align-items: center; - margin-bottom: 15px; -} - -.MultiCredential-credentialSubSection .select2 { - width: 50% !important; -} - -.MultiCredential-selectLabel { - color: @default-interface-txt; - margin-right: 10px; - line-height: 24px; - text-transform: uppercase; -} - -.MultiCredential-previewTagRevert { - flex: 0 0 60px; - line-height: 29px; - margin-left: auto; - text-align: right; -} - -.MultiCredential-revertLink { - font-size: 12px; -} diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.directive.js b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.directive.js deleted file mode 100644 index bca3e1e29219..000000000000 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.directive.js +++ /dev/null @@ -1,70 +0,0 @@ -/************************************************* - * Copyright (c) 2018 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -const templatePath = 'templates/job_templates/multi-credential/multi-credential'; - -function MultiCredential ($compile, templateUrl) { - return { - templateUrl: templateUrl(templatePath), - require: ['multiCredential'], - restrict: 'E', - controllerAs: 'vm', - scope: { - selectedCredentials: '=', - prompt: '=', - credentialNotPresent: '=', - fieldIsDisabled: '=', - credentialTypes: '=', - }, - link: (scope, element, attrs, controllers) => { - const [controller] = controllers; - - scope.openModal = () => { - const containerElement = $('#content-container'); - const templateFunction = $compile(` - - `); - containerElement.append(templateFunction(scope)); - }; - - controller.init(scope); - }, - controller: multiCredentialController, - }; -} - -function multiCredentialController (MultiCredentialService) { - const vm = this; - const { createTag } = MultiCredentialService; - - let scope; - - vm.init = _scope_ => { - scope = _scope_; - scope.$watchCollection('selectedCredentials', onSelectedCredentialsChanged); - }; - - function onSelectedCredentialsChanged (oldValues, newValues) { - if (oldValues !== newValues) { - scope.fieldDirty = (scope.prompt && scope.selectedCredentials.length > 0); - scope.tags = scope.selectedCredentials.map(c => createTag(c, scope.credentialTypes)); - } - } - - vm.deselectCredential = ({ id }) => { - const index = scope.selectedCredentials.map(c => c.id).indexOf(id); - - if (index > -1) { - scope.selectedCredentials.splice(index, 1); - } - }; -} - -MultiCredential.$inject = ['$compile', 'templateUrl']; -multiCredentialController.$inject = ['MultiCredentialService']; - -export default MultiCredential; diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html deleted file mode 100644 index 25692aa17749..000000000000 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html +++ /dev/null @@ -1,56 +0,0 @@ -
- - - - -
-
-
-
-
- - - - - - -
-
- - - - - - -
-
- - {{ tag.name }} - - - {{ tag.name }} | {{ tag.info }} - -
-
- -
-
-
-
-
-
-
diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js deleted file mode 100644 index ecb2512247fe..000000000000 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js +++ /dev/null @@ -1,102 +0,0 @@ -function MultiCredentialService (Rest, ProcessErrors, $q, GetBasePath) { - - const handleError = (method, resource, permitted = []) => { - return ({ data, status }) => { - if (permitted.indexOf(status) > -1) { - return { data, status }; - } - const hdr = 'Error!'; - const msg = `${resource} request failed. ${method} returned status: ${status}`; - return ProcessErrors(null, data, status, null, { hdr, msg }); - }; - }; - - const associate = ({ related }, id) => { - Rest.setUrl(related.credentials); - return Rest - .post({ id }) - .then(({ data }) => data.results) - .catch(handleError('POST', 'credential association')); - }; - - const disassociate = ({ related }, id) => { - Rest.setUrl(related.credentials); - return Rest - .post({ id, disassociate: true }) - .catch(handleError('POST', 'credential disassociation')); - }; - - this.saveRelated = ({ related }, credentials) => { - Rest.setUrl(related.credentials); - return Rest - .get() - .then(({ data }) => { - const currentlyAssociated = data.results.map(c => c.id); - const selected = credentials.map(c => c.id); - - const disassociationPromises = currentlyAssociated - .filter(id => selected.indexOf(id) < 0) - .map(id => disassociate({ related }, id)); - - const associationPromises = selected - .filter(id => currentlyAssociated.indexOf(id) < 0) - .map(id => associate({ related }, id)); - - const promises = disassociationPromises - .concat(associationPromises); - - return $q.all(promises); - }); - }; - - this.getRelated = ({ related }, params = { permitted: [] }) => { - Rest.setUrl(related.credentials); - return Rest - .get() - .catch(handleError('GET', 'related credentials', params.permitted)); - }; - - this.getCredentials = () => { - Rest.setUrl(GetBasePath('credentials')); - return Rest - .get() - .catch(handleError('GET', 'related credentials')); - }; - - this.getCredentialTypes = () => { - Rest.setUrl(GetBasePath('credential_types')); - return Rest - .get({ params: { page_size: 200 }}) - .catch(handleError('GET', 'credential types')); - }; - - this.isReadOnly = credential => { - const canEdit = _.get(credential, 'summary_fields.user_capabilities.edit'); - const canDelete = _.get(credential, 'summary_fields.user_capabilities.delete'); - - return !(canEdit || canDelete); - }; - - this.createTag = (credential, credential_types) => { - const credentialTypeId = credential.credential_type || credential.credential_type_id; - const credentialType = credential_types.find(t => t.id === credentialTypeId); - - return { - id: credential.id, - name: credential.name, - kind: _.get(credentialType, 'kind'), - typeName: _.get(credentialType, 'name'), - info: _.get(credential, 'inputs.vault_id'), - readOnly: this.isReadOnly(credential), - }; - }; -} - -MultiCredentialService.$inject = [ - 'Rest', - 'ProcessErrors', - '$q', - 'GetBasePath', -]; - -export default MultiCredentialService; diff --git a/awx/ui/client/src/templates/labels/labelsList.block.less b/awx/ui/client/src/templates/labels/labelsList.block.less deleted file mode 100644 index 39041117a06c..000000000000 --- a/awx/ui/client/src/templates/labels/labelsList.block.less +++ /dev/null @@ -1,117 +0,0 @@ -/** @define LabelList */ - -.LabelList { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -.LabelList-tagContainer { - height: fit-content; -} - -.LabelList-tagContainer, -.LabelList-seeMoreLess { - display: flex; - max-width: 200px; -} - -.LabelList-tag, .JobSubmission-previewTag { - border-radius: 5px; - padding: 2px 10px; - margin: 3px 0px; - font-size: 12px; - color: @default-interface-txt; - background-color: @default-list-header-bg; - margin-right: 5px; - max-width: 100%; - display: inline-block; -} - -.LabelList-seeMoreLess { - color: @default-link; - margin: 4px 0px; - text-transform: uppercase; - padding: 2px 0px; - cursor: pointer; - border-radius: 5px; - font-size: 11px; -} - -.LabelList-seeMoreLess:hover { - color: @default-link-hov; -} - -.LabelList-tag--deletable, .JobSubmission-previewTag--deletable, .Prompt-previewTag--deletable { - color: @default-bg; - background-color: @default-link; - margin-right: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - border-right: 0; - max-width: ~"calc(100% - 23px)"; -} - -.LabelList-deleteContainer, .JobSubmission-previewTagContainerDelete, .Prompt-previewTagContainerDelete { - background-color: @default-link; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - color: @default-bg; - padding: 0 5px; - margin: 3px 0px; - align-items: center; - display: flex; - cursor: pointer; - margin-right: 5px; -} - -.LabelList-tagDelete { - font-size: 13px; - color: @default-bg; -} - -.LabelList-name { - flex: initial; - max-width: 100%; - word-break: break-word; -} - -.LabelList-tag--deletable > .LabelList-name { - max-width: ~"calc(100% - 23px)"; -} - -.LabelList-deleteContainer:hover, .JobSubmission-previewTagContainerDelete:hover, .Prompt-previewTagContainerDelete:hover { - border-color: @default-err; - background-color: @default-err; -} - -.LabelList-deleteContainer:hover > .LabelList-tagDelete, .JobSubmission-previewTagContainerDelete:hover > .JobSubmission-previewTagContainerTagDelete, .Prompt-previewTagContainerDelete:hover > .Prompt-previewTagContainerTagDelete { - color: @default-bg; -} - -.LabelList-lookupTags { - display: flex; - padding: 0 12px; - overflow-y: hidden; -} - -.LabelList-lookupTags[disabled] { - pointer-events: none; -} - -.LabelList-lookupTags--disabled { - cursor: not-allowed; - background-color: @default-list-header-bg; - .LabelList-tag { - color: @default-bg; - background-color: @default-icon; - } -} - -.JobSubmission-previewTagContainer--vault{ - flex: 1 0 auto; -} - -.JobSubmission-previewTag--vault{ - border-radius: 5px; -} diff --git a/awx/ui/client/src/templates/labels/labelsList.directive.js b/awx/ui/client/src/templates/labels/labelsList.directive.js deleted file mode 100644 index 422f04da33ea..000000000000 --- a/awx/ui/client/src/templates/labels/labelsList.directive.js +++ /dev/null @@ -1,120 +0,0 @@ -/* jshint unused: vars */ -export default - [ 'templateUrl', - 'Wait', - 'Rest', - 'GetBasePath', - 'ProcessErrors', - 'Prompt', - '$q', - '$filter', - '$state', - function(templateUrl, Wait, Rest, GetBasePath, ProcessErrors, Prompt, $q, $filter, $state) { - return { - restrict: 'E', - scope: { - state: '=' - }, - templateUrl: templateUrl('templates/labels/labelsList'), - link: function(scope, element, attrs) { - scope.showDelete = attrs.showDelete === 'true'; - scope.isRowItem = attrs.isRowItem === 'true'; - scope.seeMoreInactive = true; - - var getNext = function(data, arr, resolve) { - Rest.setUrl(data.next); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, arr.concat(data.results), resolve); - } else { - resolve.resolve(arr.concat(data.results)); - } - }); - }; - - scope.seeMore = function () { - var seeMoreResolve = $q.defer(); - if (scope.state) { - Rest.setUrl(scope.state.related.labels); - } - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, data.results, seeMoreResolve); - } else { - seeMoreResolve.resolve(data.results); - } - }); - - seeMoreResolve.promise.then(function (labels) { - scope.labels = labels; - scope.seeMoreInactive = false; - }); - }; - - scope.seeLess = function() { - // Trim the labels array back down to 10 items - scope.labels = scope.labels.slice(0, 5); - // Re-set the seeMoreInteractive flag so that the "See More" will be displayed - scope.seeMoreInactive = true; - }; - - scope.deleteLabel = function(template, label) { - var action = function () { - $('#prompt-modal').modal('hide'); - scope.seeMoreInactive = true; - Wait('start'); - let url; - if(template.type === 'job_template') { - url = GetBasePath("job_templates") + template.id + "/labels/"; - } - else if(template.type === 'workflow_job_template') { - url = GetBasePath("workflow_job_templates") + template.id + "/labels/"; - } - - if(url) { - Rest.setUrl(url); - Rest.post({"disassociate": true, "id": label.id}) - .then(() => { - Wait('stop'); - $state.go('.', null, {reload: true}); - }) - .catch(({data, status}) => { - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Could not disassociate label from JT. Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - } - }; - - Prompt({ - hdr: 'Remove Label from ' + template.name , - body: '
Confirm the removal of the ' + $filter('sanitize')(label.name) + ' label.
', - action: action, - actionText: 'REMOVE' - }); - }; - - if (_.has(scope.state, 'summary_fields.labels.results')) { - scope.labels = scope.state.summary_fields.labels.results.slice(0, 5); - scope.count = scope.state.summary_fields.labels.count; - } else { - scope.$watchCollection(scope.state, function() { - // To keep the array of labels fresh, we need to set up a watcher - otherwise, the - // array will get set initially and then never be updated as labels are removed - if (scope.state.summary_fields.labels){ - scope.labels = scope.state.summary_fields.labels.results.slice(0, 5); - scope.count = scope.state.summary_fields.labels.count; - } - else{ - scope.labels = null; - scope.count = null; - } - }); - } - - } - }; - } - ]; diff --git a/awx/ui/client/src/templates/labels/labelsList.partial.html b/awx/ui/client/src/templates/labels/labelsList.partial.html deleted file mode 100644 index fce351f8006d..000000000000 --- a/awx/ui/client/src/templates/labels/labelsList.partial.html +++ /dev/null @@ -1,35 +0,0 @@ -
-
- -
-
- {{ label.name }} -
-
-
View More
-
View Less
-
-
- Labels -
-
-
-
- {{ label.name }} -
-
- -
-
-
View More
-
View Less
-
-
diff --git a/awx/ui/client/src/templates/labels/main.js b/awx/ui/client/src/templates/labels/main.js deleted file mode 100644 index 6d325ff42c1d..000000000000 --- a/awx/ui/client/src/templates/labels/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import labelsList from './labelsList.directive'; - -export default - angular.module('labels', []) - .directive('labelsList', labelsList); diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js deleted file mode 100644 index 4bb8a15b49ab..000000000000 --- a/awx/ui/client/src/templates/main.js +++ /dev/null @@ -1,786 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import templatesService from './templates.service'; -import surveyMaker from './survey-maker/main'; -import jobTemplates from './job_templates/main'; -import workflowAdd from './workflows/add-workflow/main'; -import workflowEdit from './workflows/edit-workflow/main'; -import labels from './labels/main'; -import prompt from './prompt/main'; -import workflowChart from './workflows/workflow-chart/main'; -import workflowMaker from './workflows/workflow-maker/main'; -import workflowControls from './workflows/workflow-controls/main'; -import workflowService from './workflows/workflow.service'; -import WorkflowForm from './workflows.form'; -import InventorySourcesList from './inventory-sources.list'; -import TemplateList from './templates.list'; -import listRoute from '~features/templates/routes/templatesList.route.js'; -import templateCompletedJobsRoute from '~features/jobs/routes/templateCompletedJobs.route.js'; -import workflowJobTemplateCompletedJobsRoute from '~features/jobs/routes/workflowJobTemplateCompletedJobs.route.js'; -import { - jobTemplatesSchedulesListRoute, - jobTemplatesSchedulesAddRoute, - jobTemplatesSchedulesEditRoute, - workflowSchedulesRoute, - workflowSchedulesAddRoute, - workflowSchedulesEditRoute -} from '../scheduler/schedules.route'; - -export default -angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, prompt.name, workflowAdd.name, workflowEdit.name, - workflowChart.name, workflowMaker.name, workflowControls.name - ]) - .service('TemplatesService', templatesService) - .service('WorkflowService', workflowService) - .factory('WorkflowForm', WorkflowForm) - // TODO: currently being kept arround for rbac selection, templates within projects and orgs, etc. - .factory('TemplateList', TemplateList) - .value('InventorySourcesList', InventorySourcesList) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { - let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow, - workflowMaker, - stateDefinitions = stateDefinitionsProvider.$get(), - stateExtender = $stateExtenderProvider.$get(); - - function generateStateTree() { - - addJobTemplate = stateDefinitions.generateTree({ - name: 'templates.addJobTemplate', - url: '/add_job_template?inventory_id&credential_id&project_id', - modes: ['add'], - form: 'JobTemplateForm', - controllers: { - add: 'JobTemplateAdd' - }, - resolve: { - add: { - Inventory: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - if($stateParams.inventory_id){ - let path = `${GetBasePath('inventory')}${$stateParams.inventory_id}`; - Rest.setUrl(path); - return Rest.get(). - then(function(data){ - return data.data; - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get inventory info. GET returned status: ' + - response.status - }); - }); - } - }], - Project: ['Rest', 'GetBasePath', 'ProcessErrors', '$transition$', - function(Rest, GetBasePath, ProcessErrors, $transition$){ - if($transition$.params().credential_id){ - let path = `${GetBasePath('projects')}?credential__id=${Number($transition$.params().credential_id)}`; - Rest.setUrl(path); - return Rest.get(). - then(function(data){ - return data.data.results[0]; - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get project info. GET returned status: ' + - response.status - }); - }); - } - else if($transition$.params().project_id){ - let path = `${GetBasePath('projects')}${$transition$.params().project_id}`; - Rest.setUrl(path); - return Rest.get(). - then(function(data){ - return data.data; - }).catch(function(response) { - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get project info. GET returned status: ' + - response.status - }); - }); - } - }], - availableLabels: ['ProcessErrors', 'TemplatesService', - function(ProcessErrors, TemplatesService) { - return TemplatesService.getAllLabelOptions() - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get labels. GET returned status: ' + - response.status - }); - }); - }], - checkPermissions: ['Rest', 'GetBasePath', 'TemplatesService', 'Alert', 'ProcessErrors', '$state', - function(Rest, GetBasePath, TemplatesService, Alert, ProcessErrors, $state) { - return TemplatesService.getJobTemplateOptions() - .then(function(data) { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a job template.', 'alert-info'); - } - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get job template options. OPTIONS returned status: ' + - response.status - }); - }); - }], - ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => { - return ConfigService.getConfig() - .then(response => response) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get config. GET returned status: ' + - 'status: ' + status - }); - }); - }] - } - } - }); - - editJobTemplate = stateDefinitions.generateTree({ - name: 'templates.editJobTemplate', - url: '/job_template/:job_template_id', - modes: ['edit'], - form: 'JobTemplateForm', - controllers: { - edit: 'JobTemplateEdit' - }, - data: { - activityStream: true, - activityStreamTarget: 'job_template', - activityStreamId: 'job_template_id' - }, - breadcrumbs: { - edit: '{{breadcrumb.job_template_name}}' - }, - resolve: { - edit: { - jobTemplateData: ['$stateParams', 'TemplatesService', 'ProcessErrors', - function($stateParams, TemplatesService, ProcessErrors) { - return TemplatesService.getJobTemplate($stateParams.job_template_id) - .then(function(res) { - return res.data; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get job template. GET returned status: ' + - response.status - }); - }); - }], - projectGetPermissionDenied: ['Rest', 'ProcessErrors', 'jobTemplateData', - function(Rest, ProcessErrors, jobTemplateData) { - if(jobTemplateData.related.project) { - Rest.setUrl(jobTemplateData.related.project); - return Rest.get() - .then(() => { - return false; - }) - .catch(({data, status}) => { - if (status !== 403) { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get project. GET returned ' + - 'status: ' + status - }); - return false; - } - else { - return true; - } - }); - } - else { - return false; - } - }], - inventoryGetPermissionDenied: ['Rest', 'ProcessErrors', 'jobTemplateData', - function(Rest, ProcessErrors, jobTemplateData) { - if(jobTemplateData.related.inventory) { - Rest.setUrl(jobTemplateData.related.inventory); - return Rest.get() - .then(() => { - return false; - }) - .catch(({data, status}) => { - if (status !== 403) { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get project. GET returned ' + - 'status: ' + status - }); - return false; - } - else { - return true; - } - }); - } - else { - return false; - } - }], - InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}/instance_groups/`; - Rest.setUrl(path); - return Rest.get() - .then(({data}) => { - if (data.results.length > 0) { - return data.results; - } - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get instance groups. GET returned ' + - 'status: ' + status - }); - }); - }], - availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', - function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) { - return TemplatesService.getAllLabelOptions() - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get labels. GET returned status: ' + - response.status - }); - }); - }], - selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors', - function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) { - return TemplatesService.getAllJobTemplateLabels($stateParams.job_template_id) - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get workflow job template labels. GET returned status: ' + - response.status - }); - }); - }], - ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => { - return ConfigService.getConfig() - .then(response => response) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get config. GET returned status: ' + - 'status: ' + status - }); - }); - }] - } - } - }); - - addWorkflow = stateDefinitions.generateTree({ - name: 'templates.addWorkflowJobTemplate', - url: '/add_workflow_job_template', - modes: ['add'], - form: 'WorkflowForm', - controllers: { - add: 'WorkflowAdd' - }, - resolve: { - add: { - availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', - function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) { - return TemplatesService.getAllLabelOptions() - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get labels. GET returned status: ' + - response.status - }); - }); - }], - checkPermissions: ['Rest', 'GetBasePath', 'TemplatesService', 'Alert', 'ProcessErrors', '$state', - function(Rest, GetBasePath, TemplatesService, Alert, ProcessErrors, $state) { - return TemplatesService.getWorkflowJobTemplateOptions() - .then(function(data) { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a workflow job template.', 'alert-info'); - } - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get workflow job template options. OPTIONS returned status: ' + - response.status - }); - }); - }] - } - } - }); - - editWorkflow = stateDefinitions.generateTree({ - name: 'templates.editWorkflowJobTemplate', - url: '/workflow_job_template/:workflow_job_template_id', - modes: ['edit'], - form: 'WorkflowForm', - controllers: { - edit: 'WorkflowEdit' - }, - data: { - activityStream: true, - activityStreamTarget: 'workflow_job_template', - activityStreamId: 'workflow_job_template_id' - }, - breadcrumbs: { - edit: '{{breadcrumb.workflow_job_template_name}}' - }, - resolve: { - edit: { - availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', - function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) { - return TemplatesService.getAllLabelOptions() - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get labels. GET returned status: ' + - response.status - }); - }); - }], - selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors', - function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) { - return TemplatesService.getAllWorkflowJobTemplateLabels($stateParams.workflow_job_template_id) - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get workflow job template labels. GET returned status: ' + - response.status - }); - }); - }], - workflowJobTemplateData: ['$stateParams', 'TemplatesService', 'ProcessErrors', - function($stateParams, TemplatesService, ProcessErrors) { - return TemplatesService.getWorkflowJobTemplate($stateParams.workflow_job_template_id) - .then(function(res) { - return res.data; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get workflow job template. GET returned status: ' + - response.status - }); - }); - }], - workflowLaunch: ['$stateParams', 'WorkflowJobTemplateModel', - function($stateParams, WorkflowJobTemplate) { - let workflowJobTemplate = new WorkflowJobTemplate(); - - return workflowJobTemplate.getLaunch($stateParams.workflow_job_template_id) - .then(({data}) => { - return data; - }); - }] - } - } - }); - - workflowMaker = { - name: 'templates.editWorkflowJobTemplate.workflowMaker', - url: '/workflow-maker', - // ncyBreadcrumb: { - // label: 'WORKFLOW MAKER' - // }, - data: { - formChildState: true - }, - params: { - job_template_search: { - value: { - page_size: '5', - order_by: 'name' - }, - squash: false, - dynamic: true - }, - project_search: { - value: { - page_size: '5', - order_by: 'name' - }, - squash: true, - dynamic: true - }, - inventory_source_search: { - value: { - page_size: '5', - not__source: '', - order_by: 'name' - }, - squash: true, - dynamic: true - } - }, - views: { - 'modal': { - template: `` - }, - 'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': { - templateProvider: function(WorkflowMakerJobTemplateList, generateList) { - - let html = generateList.build({ - list: WorkflowMakerJobTemplateList, - input_type: 'radio', - mode: 'lookup' - }); - return html; - }, - // $scope encapsulated in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy - controller: ['$scope', 'WorkflowMakerJobTemplateList', 'JobTemplateDataset', - function($scope, list, Dataset) { - - init(); - - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watch('job_templates', function(){ - if($scope.selectedTemplate){ - $scope.job_templates.forEach(function(row, i) { - if(row.id === $scope.selectedTemplate.id) { - $scope.job_templates[i].checked = 1; - } - else { - $scope.job_templates[i].checked = 0; - } - }); - } - }); - } - - $scope.toggle_row = function(selectedRow) { - - $scope.job_templates.forEach(function(row, i) { - if (row.id === selectedRow.id) { - $scope.job_templates[i].checked = 1; - $scope.selection[list.iterator] = { - id: row.id, - name: row.name - }; - - $scope.templateManuallySelected(row); - } - }); - - }; - - $scope.$watch('selectedTemplate', () => { - $scope.job_templates.forEach(function(row, i) { - if(_.has($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) { - $scope.job_templates[i].checked = 1; - } - else { - $scope.job_templates[i].checked = 0; - } - }); - }); - - $scope.$watch('activeTab', () => { - if(!$scope.activeTab || $scope.activeTab !== "jobs") { - $scope.job_templates.forEach(function(row, i) { - $scope.job_templates[i].checked = 0; - }); - } - }); - - $scope.$on('clearWorkflowLists', function() { - $scope.job_templates.forEach(function(row, i) { - $scope.job_templates[i].checked = 0; - }); - }); - } - ] - }, - 'inventorySyncList@templates.editWorkflowJobTemplate.workflowMaker': { - templateProvider: function(WorkflowInventorySourcesList, generateList) { - let html = generateList.build({ - list: WorkflowInventorySourcesList, - input_type: 'radio', - mode: 'lookup' - }); - return html; - }, - // encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy - controller: ['$scope', 'WorkflowInventorySourcesList', 'InventorySourcesDataset', - function($scope, list, Dataset) { - - init(); - - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watch('workflow_inventory_sources', function(){ - if($scope.selectedTemplate){ - $scope.workflow_inventory_sources.forEach(function(row, i) { - if(row.id === $scope.selectedTemplate.id) { - $scope.workflow_inventory_sources[i].checked = 1; - } - else { - $scope.workflow_inventory_sources[i].checked = 0; - } - }); - } - }); - } - - $scope.toggle_row = function(selectedRow) { - - $scope.workflow_inventory_sources.forEach(function(row, i) { - if (row.id === selectedRow.id) { - $scope.workflow_inventory_sources[i].checked = 1; - $scope.selection[list.iterator] = { - id: row.id, - name: row.name - }; - - $scope.templateManuallySelected(row); - } - }); - - }; - - $scope.$watch('selectedTemplate', () => { - $scope.workflow_inventory_sources.forEach(function(row, i) { - if(_.has($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) { - $scope.workflow_inventory_sources[i].checked = 1; - } - else { - $scope.workflow_inventory_sources[i].checked = 0; - } - }); - }); - - $scope.$watch('activeTab', () => { - if(!$scope.activeTab || $scope.activeTab !== "inventory_sync") { - $scope.workflow_inventory_sources.forEach(function(row, i) { - $scope.workflow_inventory_sources[i].checked = 0; - }); - } - }); - - $scope.$on('clearWorkflowLists', function() { - $scope.workflow_inventory_sources.forEach(function(row, i) { - $scope.workflow_inventory_sources[i].checked = 0; - }); - }); - } - ] - }, - 'projectSyncList@templates.editWorkflowJobTemplate.workflowMaker': { - templateProvider: function(WorkflowProjectList, generateList) { - let html = generateList.build({ - list: WorkflowProjectList, - input_type: 'radio', - mode: 'lookup' - }); - return html; - }, - // encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy - controller: ['$scope', 'WorkflowProjectList', 'ProjectDataset', - function($scope, list, Dataset) { - - init(); - - function init() { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $scope.$watch('projects', function(){ - if($scope.selectedTemplate){ - $scope.projects.forEach(function(row, i) { - if(row.id === $scope.selectedTemplate.id) { - $scope.projects[i].checked = 1; - } - else { - $scope.projects[i].checked = 0; - } - }); - } - }); - } - - $scope.toggle_row = function(selectedRow) { - - $scope.projects.forEach(function(row, i) { - if (row.id === selectedRow.id) { - $scope.projects[i].checked = 1; - $scope.selection[list.iterator] = { - id: row.id, - name: row.name - }; - - $scope.templateManuallySelected(row); - } - }); - - }; - - $scope.$watch('selectedTemplate', () => { - $scope.projects.forEach(function(row, i) { - if(_.has($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) { - $scope.projects[i].checked = 1; - } - else { - $scope.projects[i].checked = 0; - } - }); - }); - - $scope.$watch('activeTab', () => { - if(!$scope.activeTab || $scope.activeTab !== "project_sync") { - $scope.projects.forEach(function(row, i) { - $scope.projects[i].checked = 0; - }); - } - }); - - $scope.$on('clearWorkflowLists', function() { - $scope.projects.forEach(function(row, i) { - $scope.projects[i].checked = 0; - }); - }); - } - ] - } - }, - resolve: { - JobTemplateDataset: ['WorkflowMakerJobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - let path = GetBasePath(list.basePath); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ProjectDataset: ['WorkflowProjectList', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - let path = GetBasePath(list.basePath); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - InventorySourcesDataset: ['InventorySourcesList', 'QuerySet', '$stateParams', 'GetBasePath', - (list, qs, $stateParams, GetBasePath) => { - let path = GetBasePath(list.basePath); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - WorkflowMakerJobTemplateList: ['TemplateList', - (TemplateList) => { - let list = _.cloneDeep(TemplateList); - delete list.actions; - delete list.fields.type; - delete list.fields.description; - delete list.fields.smart_status; - delete list.fields.labels; - delete list.fieldActions; - list.fields.name.columnClass = "col-md-8"; - list.iterator = 'job_template'; - list.name = 'job_templates'; - list.basePath = "job_templates"; - list.fields.info = { - ngInclude: "'/static/partials/job-template-details.html'", - type: 'template', - columnClass: 'col-md-3', - label: '', - nosort: true - }; - list.maxVisiblePages = 5; - list.searchBarFullWidth = true; - - return list; - } - ], - WorkflowProjectList: ['ProjectList', - (ProjectList) => { - let list = _.cloneDeep(ProjectList); - delete list.fields.status; - delete list.fields.scm_type; - delete list.fields.last_updated; - list.fields.name.columnClass = "col-md-11"; - list.maxVisiblePages = 5; - list.searchBarFullWidth = true; - - return list; - } - ], - WorkflowInventorySourcesList: ['InventorySourcesList', - (InventorySourcesList) => { - let list = _.cloneDeep(InventorySourcesList); - list.maxVisiblePages = 5; - list.searchBarFullWidth = true; - - return list; - } - ] - } - }; - - return Promise.all([ - addJobTemplate, - editJobTemplate, - addWorkflow, - editWorkflow - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(listRoute), - stateExtender.buildDefinition(templateCompletedJobsRoute), - stateExtender.buildDefinition(workflowJobTemplateCompletedJobsRoute), - stateExtender.buildDefinition(workflowMaker), - stateExtender.buildDefinition(jobTemplatesSchedulesListRoute), - stateExtender.buildDefinition(jobTemplatesSchedulesAddRoute), - stateExtender.buildDefinition(jobTemplatesSchedulesEditRoute), - stateExtender.buildDefinition(workflowSchedulesRoute), - stateExtender.buildDefinition(workflowSchedulesAddRoute), - stateExtender.buildDefinition(workflowSchedulesEditRoute) - ]) - }; - }); - } - - stateTree = { - name: 'templates.**', - url: '/templates', - lazyLoad: () => generateStateTree() - }; - - $stateProvider.state(stateTree); - - } - ]); diff --git a/awx/ui/client/src/templates/prompt/main.js b/awx/ui/client/src/templates/prompt/main.js deleted file mode 100644 index dd97c78cf129..000000000000 --- a/awx/ui/client/src/templates/prompt/main.js +++ /dev/null @@ -1,17 +0,0 @@ -import promptDirective from './prompt.directive'; -import promptInventory from './steps/inventory/prompt-inventory.directive'; -import promptCredential from './steps/credential/prompt-credential.directive'; -import promptOtherPrompts from './steps/other-prompts/prompt-other-prompts.directive'; -import promptSurvey from './steps/survey/prompt-survey.directive'; -import promptPreview from './steps/preview/prompt-preview.directive'; -import promptService from './prompt.service'; - -export default - angular.module('prompt', []) - .directive('prompt', promptDirective) - .directive('promptInventory', promptInventory) - .directive('promptCredential', promptCredential) - .directive('promptOtherPrompts', promptOtherPrompts) - .directive('promptSurvey', promptSurvey) - .directive('promptPreview', promptPreview) - .service('PromptService', promptService); diff --git a/awx/ui/client/src/templates/prompt/prompt.block.less b/awx/ui/client/src/templates/prompt/prompt.block.less deleted file mode 100644 index 4b2814d5f5c1..000000000000 --- a/awx/ui/client/src/templates/prompt/prompt.block.less +++ /dev/null @@ -1,178 +0,0 @@ -.Prompt .modal-dialog { - width: 700px; -} -.Prompt-step { - margin-top: 20px; -} -.Prompt-footer { - display: flex; - flex: 0 0 auto; - margin-top: 15px; - justify-content: flex-end; - align-items: flex-end; -} -.Prompt-actionButton { - background-color: @submit-button-bg; - border: 1px solid @submit-button-bg; - color: @submit-button-text; - text-transform: uppercase; - border-radius: 5px; - height: 30px; - padding-left:15px; - padding-right: 15px; - min-width: 85px; -} -.Prompt-actionButton:disabled { - background-color: @d7grey; - border-color: @d7grey; - opacity: 0.65; -} -.Prompt-actionButton:enabled:hover, -.Prompt-actionButton:enabled:focus { - background-color: @submit-button-bg-hov; - border: 1px solid @submit-button-bg-hov; -} -.Prompt-defaultButton{ - background-color: @default-bg; - color: @btn-txt; - text-transform: uppercase; - border-radius: 5px; - border: 1px solid @btn-bord; - padding-left:15px; - padding-right: 15px; - height: 30px; - min-width: 85px; - margin-right: 20px; -} -.Prompt-defaultButton:hover{ - background-color: @btn-bg-hov; - color: @btn-txt; -} -.Prompt-revertLink { - font-size: 12px; -} - -.Prompt-selectedItem { - display: flex; - flex: 1 0 auto; - margin-bottom: 15px; - align-items: baseline; -} -.Prompt-selectedItemInfo { - display: flex; - flex: 0 0 100%; - background-color: @default-no-items-bord; - border: 1px solid @default-border; - padding: 10px; - border-radius: 5px; - max-height: 120px; - overflow-y: auto; -} -.Prompt-selectedItemRevert { - display: flex; - flex: 0 0 auto; -} -.Prompt-credentialSubSection { - display: flex; - justify-content: flex-end; - align-items: center; - margin-bottom: 15px; -} -.Prompt-selectedItemLabel, .Prompt-label { - color: @default-interface-txt; - margin-right: 10px; -} -.Prompt-label { - line-height: 24px; -} -.Prompt-selectedItemNone { - color: @default-icon; -} -.Prompt-selectedItemContainer { - display: block; - width: 100%; -} -.Prompt-instructions { - color: @default-interface-txt; - margin-top: 25px; - margin-bottom: 15px; -} -.Prompt-passwordButton { - padding: 4px 13px; -} -.Prompt .List-noItems { - margin-top: auto; -} -.Prompt-selectedItemLabel { - flex: 0 0 80px; - line-height: 29px; -} -.Prompt-previewTags--outer { - flex: 1 0 auto; - max-width: ~"calc(100% - 140px)"; -} -.Prompt-previewTags--inner { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} -.Prompt-previewTagLabel { - color: @default-interface-txt; -} -.Prompt-previewTagLabel--deletable{ - color: @default-list-header-bg; -} -.Prompt-previewTagRevert { - flex: 0 0 60px; - line-height: 29px; -} -.Prompt-previewTagContainer { - display: flex; -} -.Prompt-previewRow--flex { - display: flex; - margin-bottom: 10px; -} -.Prompt-previewRow--noflex { - margin-bottom: 10px; -} -.Prompt-previewRowTitle { - width: 150px; - color: @default-interface-txt; - text-transform: uppercase; -} -.Prompt-previewRowValue { - flex: 1 0 auto; - max-width: 508px; -} -.Prompt-noSelectedItem { - height: 30px; - line-height: 30px; - font-style: italic; - color: @default-interface-txt; -} -.Prompt-previewTag { - border-radius: 5px; - padding: 2px 10px; - margin: 3px 0px; - font-size: 12px; - color: @default-bg; - background-color: @default-link; - margin-right: 5px; - max-width: 100%; - display: inline-block; -} -.Prompt-credentialSubSection .select2 { - width: 50% !important; -} -.Prompt-credentialTypeMissing { - margin-bottom: 20px; - color: @default-err; -} -.Prompt-credsWarning { - margin-bottom: 5px; - color: @default-err; -} -.Prompt-credsWarningList { - margin-bottom: 20px; -} diff --git a/awx/ui/client/src/templates/prompt/prompt.controller.js b/awx/ui/client/src/templates/prompt/prompt.controller.js deleted file mode 100644 index 362e1223fef0..000000000000 --- a/awx/ui/client/src/templates/prompt/prompt.controller.js +++ /dev/null @@ -1,223 +0,0 @@ -export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel', 'TemplatesStrings', - function (Rest, GetBasePath, ProcessErrors, CredentialType, strings) { - - // strings.get('deleteResource.HEADER') - // ${strings.get('deleteResource.CONFIRM', 'template')} - - const vm = this || {}; - - vm.strings = strings; - - let scope; - let modal; - - vm.init = (_scope_) => { - scope = _scope_; - ({ modal } = scope[scope.ns]); - - scope.$watch('vm.promptData.triggerModalOpen', () => { - - vm.actionButtonClicked = false; - if(vm.promptData && vm.promptData.triggerModalOpen) { - - vm.promptDataClone = _.cloneDeep(vm.promptData); - - vm.steps = { - inventory: { - includeStep: false - }, - credential: { - includeStep: false - }, - other_prompts: { - includeStep: false - }, - survey: { - includeStep: false - }, - preview: { - includeStep: true, - tab: { - _active: false, - _disabled: true - } - } - }; - - let order = 1; - - vm.actionText = vm.actionText ? vm.actionText : strings.get('prompt.LAUNCH'); - - vm.forms = {}; - - let credentialType = new CredentialType(); - - credentialType.http.get() - .then( (response) => { - vm.promptDataClone.prompts.credentials.credentialTypes = {}; - vm.promptDataClone.prompts.credentials.credentialTypeOptions = []; - let machineCredTypeId = null; - response.data.results.forEach((credentialTypeRow => { - vm.promptDataClone.prompts.credentials.credentialTypes[credentialTypeRow.id] = credentialTypeRow.kind; - if(credentialTypeRow.kind.match(/^(cloud|net|ssh|vault)$/)) { - if(credentialTypeRow.kind === 'ssh') { - machineCredTypeId = credentialTypeRow.id; - vm.promptDataClone.prompts.credentials.credentialKind = credentialTypeRow.id.toString(); - } - vm.promptDataClone.prompts.credentials.credentialTypeOptions.push({ - name: credentialTypeRow.name, - value: credentialTypeRow.id - }); - } - })); - - vm.promptDataClone.prompts.credentials.passwords = {}; - - if(vm.promptDataClone.launchConf.passwords_needed_to_start) { - let machineCredPassObj = null; - vm.promptDataClone.launchConf.passwords_needed_to_start.forEach((passwordNeeded) => { - if (passwordNeeded === "ssh_password" || - passwordNeeded === "become_password" || - passwordNeeded === "ssh_key_unlock" - ) { - if (!machineCredPassObj) { - vm.promptDataClone.prompts.credentials.value.forEach((defaultCredential) => { - if (defaultCredential.kind && defaultCredential.kind === "ssh") { - machineCredPassObj = { - id: defaultCredential.id, - name: defaultCredential.name - }; - } else if (defaultCredential.passwords_needed) { - defaultCredential.passwords_needed.forEach((neededPassword) => { - if (neededPassword === passwordNeeded) { - machineCredPassObj = { - id: defaultCredential.id, - name: defaultCredential.name - }; - } - }); - } - }); - } - - vm.promptDataClone.prompts.credentials.passwords[passwordNeeded] = angular.copy(machineCredPassObj); - } else if (passwordNeeded.startsWith("vault_password")) { - let vault_id = null; - if (passwordNeeded.includes('.')) { - vault_id = passwordNeeded.split(/\.(.+)/)[1]; - } - - if (!vm.promptDataClone.prompts.credentials.passwords.vault) { - vm.promptDataClone.prompts.credentials.passwords.vault = []; - } - - // Loop across the default credentials to find the name of the - // credential that requires a password - vm.promptDataClone.prompts.credentials.value.forEach((defaultCredential) => { - if (vm.promptDataClone.prompts.credentials.credentialTypes[defaultCredential.credential_type] === "vault") { - let defaultCredVaultId = defaultCredential.vault_id || _.get(defaultCredential, 'inputs.vault_id') || null; - if (defaultCredVaultId === vault_id) { - vm.promptDataClone.prompts.credentials.passwords.vault.push({ - id: defaultCredential.id, - name: defaultCredential.name, - vault_id: defaultCredVaultId - }); - } - } - }); - } - }); - } - - vm.promptDataClone.credentialTypeMissing = []; - - vm.promptDataClone.prompts.variables.ignore = vm.promptDataClone.launchConf.ignore_ask_variables; - - if(vm.promptDataClone.launchConf.ask_inventory_on_launch) { - vm.steps.inventory.includeStep = true; - vm.steps.inventory.tab = { - _active: true, - order: order - }; - order++; - } - if(vm.promptDataClone.launchConf.ask_credential_on_launch || (vm.promptDataClone.launchConf.passwords_needed_to_start && vm.promptDataClone.launchConf.passwords_needed_to_start.length > 0)) { - vm.steps.credential.includeStep = true; - vm.steps.credential.tab = { - _active: order === 1 ? true : false, - _disabled: order === 1 ? false : true, - order: order - }; - order++; - } - if(vm.promptDataClone.launchConf.ask_verbosity_on_launch || vm.promptDataClone.launchConf.ask_job_type_on_launch || vm.promptDataClone.launchConf.ask_limit_on_launch || vm.promptDataClone.launchConf.ask_tags_on_launch || vm.promptDataClone.launchConf.ask_skip_tags_on_launch || (vm.promptDataClone.launchConf.ask_variables_on_launch && !vm.promptDataClone.launchConf.ignore_ask_variables) || vm.promptDataClone.launchConf.ask_diff_mode_on_launch) { - vm.steps.other_prompts.includeStep = true; - vm.steps.other_prompts.tab = { - _active: order === 1 ? true : false, - _disabled: order === 1 ? false : true, - order: order - }; - order++; - } - if(vm.promptDataClone.launchConf.survey_enabled) { - vm.steps.survey.includeStep = true; - vm.steps.survey.tab = { - _active: order === 1 ? true : false, - _disabled: order === 1 ? false : true, - order: order - }; - order++; - } - vm.steps.preview.tab.order = order; - modal.show('PROMPT'); - vm.promptData.triggerModalOpen = false; - - modal.onClose = () => { - scope.$emit('launchModalOpen', false); - }; - - scope.$emit('launchModalOpen', true); - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get credential types. GET status: ' + status - }); - }); - } - }, true); - }; - - vm.next = (currentTab) => { - Object.keys(vm.steps).forEach(step => { - if(vm.steps[step].tab) { - if(vm.steps[step].tab.order === currentTab.order) { - vm.steps[step].tab._active = false; - } else if(vm.steps[step].tab.order === currentTab.order + 1) { - vm.steps[step].tab._active = true; - vm.steps[step].tab._disabled = false; - } - } - }); - }; - - vm.finish = () => { - // Disable the action button to prevent double clicking - vm.actionButtonClicked = true; - - _.forEach(vm.promptDataClone, (value, key) => { - vm.promptData[key] = value; - }); - - vm.promptData.triggerModalOpen = false; - if(vm.onFinish) { - vm.onFinish(); - } - modal.hide(); - }; - - vm.cancel = () => { - vm.promptData.triggerModalOpen = false; - modal.hide(); - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/prompt.directive.js b/awx/ui/client/src/templates/prompt/prompt.directive.js deleted file mode 100644 index e151760bb7f2..000000000000 --- a/awx/ui/client/src/templates/prompt/prompt.directive.js +++ /dev/null @@ -1,25 +0,0 @@ -import promptController from './prompt.controller'; -export default [ 'templateUrl', - function(templateUrl) { - return { - scope: { - promptData: '=', - onFinish: '&', - actionText: '@', - preventCredsWithPasswords: '<' - }, - templateUrl: templateUrl('templates/prompt/prompt'), - replace: true, - transclude: true, - restrict: 'E', - controller: promptController, - controllerAs: 'vm', - bindToController: true, - link: function(scope, el, attrs, promptController) { - scope.ns = 'launch'; - scope[scope.ns] = { modal: {} }; - - promptController.init(scope); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/prompt.partial.html b/awx/ui/client/src/templates/prompt/prompt.partial.html deleted file mode 100644 index 820ea8553d3a..000000000000 --- a/awx/ui/client/src/templates/prompt/prompt.partial.html +++ /dev/null @@ -1,45 +0,0 @@ -
- - - {{:: vm.strings.get('prompt.INVENTORY') }} - {{:: vm.strings.get('prompt.CREDENTIAL') }} - {{:: vm.strings.get('prompt.OTHER_PROMPTS') }} - {{:: vm.strings.get('prompt.SURVEY') }} - {{:: vm.strings.get('prompt.PREVIEW') }} - -
-
- -
-
- - -
-
- -
-
- -
-
- -
-
- -
-
diff --git a/awx/ui/client/src/templates/prompt/prompt.service.js b/awx/ui/client/src/templates/prompt/prompt.service.js deleted file mode 100644 index f29e3ca85601..000000000000 --- a/awx/ui/client/src/templates/prompt/prompt.service.js +++ /dev/null @@ -1,275 +0,0 @@ -function PromptService (Empty, $filter) { - - this.processPromptValues = (params) => { - const prompts = { - credentials: {}, - inventory: {}, - variables: {}, - verbosity: {}, - jobType: {}, - limit: {}, - tags: {}, - skipTags: {}, - diffMode: {} - }; - - prompts.credentials.value = _.has(params, 'launchConf.defaults.credentials') ? _.cloneDeep(params.launchConf.defaults.credentials) : []; - prompts.inventory.value = _.has(params, 'currentValues.summary_fields.inventory') ? params.currentValues.summary_fields.inventory : (_.has(params, 'launchConf.defaults.inventory') ? params.launchConf.defaults.inventory : null); - - const skipTags = _.has(params, 'currentValues.skip_tags') && params.currentValues.skip_tags ? params.currentValues.skip_tags : (_.has(params, 'launchConf.defaults.skip_tags') ? params.launchConf.defaults.skip_tags : ""); - const jobTags = _.has(params, 'currentValues.job_tags') && params.currentValues.job_tags ? params.currentValues.job_tags : (_.has(params, 'launchConf.defaults.job_tags') ? params.launchConf.defaults.job_tags : ""); - - let extraVars = ''; - - const hasCurrentExtraVars = _.get(params, 'currentValues.extra_data'), - hasDefaultExtraVars = _.get(params, 'launchConf.defaults.extra_vars'); - - if(hasCurrentExtraVars && hasDefaultExtraVars) { - extraVars = _.merge(jsyaml.safeLoad(params.launchConf.defaults.extra_vars), params.currentValues.extra_data); - } else if(hasCurrentExtraVars) { - extraVars = params.currentValues.extra_data; - } else if(hasDefaultExtraVars) { - extraVars = jsyaml.safeLoad(params.launchConf.defaults.extra_vars); - } - - prompts.variables.value = extraVars && extraVars !== '' ? '---\n' + jsyaml.safeDump(extraVars) : '---\n'; - prompts.verbosity.choices = _.get(params, 'launchOptions.actions.POST.verbosity.choices', []).map(c => ({label: c[1], value: c[0]})); - prompts.verbosity.value = _.has(params, 'currentValues.verbosity') && params.currentValues.verbosity ? _.find(prompts.verbosity.choices, item => item.value === params.currentValues.verbosity) : _.find(prompts.verbosity.choices, item => item.value === params.launchConf.defaults.verbosity); - prompts.jobType.choices = _.get(params, 'launchOptions.actions.POST.job_type.choices', []).map(c => ({label: c[1], value: c[0]})); - prompts.jobType.value = _.has(params, 'currentValues.job_type') && params.currentValues.job_type ? _.find(prompts.jobType.choices, item => item.value === params.currentValues.job_type) : _.find(prompts.jobType.choices, item => item.value === params.launchConf.defaults.job_type); - prompts.limit.value = _.has(params, 'currentValues.limit') && params.currentValues.limit ? params.currentValues.limit : (_.has(params, 'launchConf.defaults.limit') ? params.launchConf.defaults.limit : ""); - prompts.tags.options = prompts.tags.value = (jobTags && jobTags !== "") ? jobTags.split(',').map((i) => ({name: i, label: i, value: i})) : []; - prompts.skipTags.options = prompts.skipTags.value = (skipTags && skipTags !== "") ? skipTags.split(',').map((i) => ({name: i, label: i, value: i})) : []; - prompts.diffMode.value = _.has(params, 'currentValues.diff_mode') && typeof params.currentValues.diff_mode === 'boolean' ? params.currentValues.diff_mode : (_.has(params, 'launchConf.defaults.diff_mode') ? params.launchConf.defaults.diff_mode : null); - - return prompts; - }; - - this.processSurveyQuestions = (params) => { - - let missingSurveyValue = false; - - for(let i=0; i { - const launchData = { - extra_vars: promptData.extraVars - }; - - if (promptData.launchConf.ask_tags_on_launch){ - launchData.job_tags = promptData.prompts.tags.value.map(a => a.value).join(); - } - if (promptData.launchConf.ask_skip_tags_on_launch){ - launchData.skip_tags = promptData.prompts.skipTags.value.map(a => a.value).join(); - } - if (promptData.launchConf.ask_limit_on_launch && _.has(promptData, 'prompts.limit.value')){ - launchData.limit = promptData.prompts.limit.value; - } - if (promptData.launchConf.ask_job_type_on_launch && _.has(promptData, 'prompts.jobType.value.value')) { - launchData.job_type = promptData.prompts.jobType.value.value; - } - if (promptData.launchConf.ask_verbosity_on_launch && _.has(promptData, 'prompts.verbosity.value.value')) { - launchData.verbosity = promptData.prompts.verbosity.value.value; - } - if (promptData.launchConf.ask_inventory_on_launch && !Empty(promptData.prompts.inventory.value.id)){ - launchData.inventory_id = promptData.prompts.inventory.value.id; - } - if (promptData.launchConf.ask_credential_on_launch){ - launchData.credentials = []; - promptData.prompts.credentials.value.forEach((credential) => { - launchData.credentials.push(credential.id); - }); - } - if (promptData.launchConf.ask_diff_mode_on_launch && _.has(promptData, 'prompts.diffMode.value')) { - launchData.diff_mode = promptData.prompts.diffMode.value; - } - if (promptData.prompts.credentials.passwords) { - _.forOwn(promptData.prompts.credentials.passwords, (val, key) => { - if (!launchData.credential_passwords) { - launchData.credential_passwords = {}; - } - if (key === "ssh_key_unlock") { - launchData.credential_passwords.ssh_key_unlock = val.value; - } else if (key !== "vault") { - launchData.credential_passwords[`${key}`] = val.value; - } else { - _.each(val, (vaultCred) => { - launchData.credential_passwords[vaultCred.vault_id ? `${key}_password.${vaultCred.vault_id}` : `${key}_password`] = vaultCred.value; - }); - } - }); - } - - return launchData; - }; - - this.bundlePromptDataForRelaunch = (promptData) => { - const launchData = {}; - - if(promptData.relaunchHostType) { - launchData.hosts = promptData.relaunchHostType; - } - - if (promptData.prompts.credentials.passwords) { - _.forOwn(promptData.prompts.credentials.passwords, (val, key) => { - if (!launchData.credential_passwords) { - launchData.credential_passwords = {}; - } - if (key === "ssh_key_unlock") { - launchData.credential_passwords.ssh_key_unlock = val.value; - } else if (key !== "vault") { - launchData.credential_passwords[`${key}`] = val.value; - } else { - _.each(val, (vaultCred) => { - launchData.credential_passwords[vaultCred.vault_id ? `${key}_password.${vaultCred.vault_id}` : `${key}_password`] = vaultCred.value; - }); - } - }); - } - - return launchData; - }; - - this.bundlePromptDataForSaving = (params) => { - - const promptDataToSave = params.dataToSave ? params.dataToSave : {}; - - if(params.promptData.launchConf.survey_enabled){ - for (var i=0; i < params.promptData.surveyQuestions.length; i++){ - var fld = params.promptData.surveyQuestions[i].variable; - // grab all survey questions that have answers - if(params.promptData.surveyQuestions[i].required || (params.promptData.surveyQuestions[i].required === false && params.promptData.surveyQuestions[i].model.toString()!=="")) { - if(!promptDataToSave.extra_data) { - promptDataToSave.extra_data = {}; - } - promptDataToSave.extra_data[fld] = params.promptData.surveyQuestions[i].model; - } - - if(params.promptData.surveyQuestions[i].required === false && _.isEmpty(params.promptData.surveyQuestions[i].model)) { - switch (params.promptData.surveyQuestions[i].type) { - // for optional text and text-areas, submit a blank string if min length is 0 - // -- this is confusing, for an explanation see: - // http://docs.ansible.com/ansible-tower/latest/html/userguide/job_templates.html#optional-survey-questions - // - case "text": - case "textarea": - if (params.promptData.surveyQuestions[i].min === 0) { - promptDataToSave.extra_data[fld] = ""; - } - break; - } - } - } - } - - if(_.has(params, 'promptData.prompts.jobType.value.value') && _.get(params, 'promptData.launchConf.ask_job_type_on_launch')) { - promptDataToSave.job_type = params.promptData.launchConf.defaults.job_type && params.promptData.launchConf.defaults.job_type === params.promptData.prompts.jobType.value.value ? null : params.promptData.prompts.jobType.value.value; - } - if(_.has(params, 'promptData.prompts.tags.value') && _.get(params, 'promptData.launchConf.ask_tags_on_launch')){ - const templateDefaultJobTags = params.promptData.launchConf.defaults.job_tags.split(','); - promptDataToSave.job_tags = (_.isEqual(templateDefaultJobTags.sort(), params.promptData.prompts.tags.value.map(a => a.value).sort())) ? null : params.promptData.prompts.tags.value.map(a => a.value).join(); - } - if(_.has(params, 'promptData.prompts.skipTags.value') && _.get(params, 'promptData.launchConf.ask_skip_tags_on_launch')){ - const templateDefaultSkipTags = params.promptData.launchConf.defaults.skip_tags.split(','); - promptDataToSave.skip_tags = (_.isEqual(templateDefaultSkipTags.sort(), params.promptData.prompts.skipTags.value.map(a => a.value).sort())) ? null : params.promptData.prompts.skipTags.value.map(a => a.value).join(); - } - if(_.has(params, 'promptData.prompts.limit.value') && _.get(params, 'promptData.launchConf.ask_limit_on_launch')){ - promptDataToSave.limit = params.promptData.launchConf.defaults.limit && params.promptData.launchConf.defaults.limit === params.promptData.prompts.limit.value ? null : params.promptData.prompts.limit.value; - } - if(_.has(params, 'promptData.prompts.verbosity.value.value') && _.get(params, 'promptData.launchConf.ask_verbosity_on_launch')){ - promptDataToSave.verbosity = params.promptData.launchConf.defaults.verbosity && params.promptData.launchConf.defaults.verbosity === params.promptData.prompts.verbosity.value.value ? null : params.promptData.prompts.verbosity.value.value; - } - if(_.has(params, 'promptData.prompts.inventory.value') && _.get(params, 'promptData.launchConf.ask_inventory_on_launch')){ - promptDataToSave.inventory = params.promptData.launchConf.defaults.inventory && params.promptData.launchConf.defaults.inventory.id === params.promptData.prompts.inventory.value.id ? null : params.promptData.prompts.inventory.value.id; - } - if(_.has(params, 'promptData.prompts.diffMode.value') && _.get(params, 'promptData.launchConf.ask_diff_mode_on_launch')){ - promptDataToSave.diff_mode = params.promptData.launchConf.defaults.diff_mode && params.promptData.launchConf.defaults.diff_mode === params.promptData.prompts.diffMode.value ? null : params.promptData.prompts.diffMode.value; - } - - return promptDataToSave; - }; -} - -PromptService.$inject = ['Empty', '$filter']; - -export default PromptService; diff --git a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.controller.js b/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.controller.js deleted file mode 100644 index f42792a822e5..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.controller.js +++ /dev/null @@ -1,340 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ 'CredentialList', 'QuerySet', 'GetBasePath', 'CreateSelect2', 'TemplatesStrings', - function(CredentialList, qs, GetBasePath, CreateSelect2, strings) { - const vm = this; - - vm.strings = strings; - - let scope; - let launch; - - let updateSelectedRow = () => { - if(scope.credentials && scope.credentials.length > 0) { - scope.credentials.forEach((credential, i) => { - scope.credentials[i].checked = 0; - }); - scope.promptData.prompts.credentials.value.forEach((selectedCredential) => { - if(selectedCredential.credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) { - scope.credentials.forEach((credential, i) => { - if(scope.credentials[i].id === selectedCredential.id) { - scope.credentials[i].checked = 1; - } - }); - } - }); - } - }; - - let wipePasswords = (cred) => { - if(cred.passwords_needed) { - cred.passwords_needed.forEach((passwordNeeded => { - if(passwordNeeded === 'ssh_password') { - delete scope.promptData.prompts.credentials.passwords.ssh_password; - } else if(passwordNeeded === 'become_password') { - delete scope.promptData.prompts.credentials.passwords.become_password; - } else if(passwordNeeded === 'ssh_key_unlock') { - delete scope.promptData.prompts.credentials.passwords.ssh_key_unlock; - } else if(passwordNeeded.startsWith("vault_password")) { - for (let i = scope.promptData.prompts.credentials.passwords.vault.length - 1; i >= 0; i--) { - if(cred.id === scope.promptData.prompts.credentials.passwords.vault[i].id) { - scope.promptData.prompts.credentials.passwords.vault.splice(i, 1); - } - } - } - })); - } else if(cred.inputs && !_.isEmpty(cred.inputs)) { - if(cred.inputs.password && cred.inputs.password === "ASK") { - delete scope.promptData.prompts.credentials.passwords.ssh_password; - } - if(cred.inputs.become_password && cred.inputs.become_password === "ASK") { - delete scope.promptData.prompts.credentials.passwords.become_password; - } - if(cred.inputs.ssh_key_unlock && cred.inputs.ssh_key_unlock === "ASK") { - delete scope.promptData.prompts.credentials.passwords.ssh_key_unlock; - } - if(cred.inputs.vault_password && cred.inputs.vault_password === "ASK") { - for (let i = scope.promptData.prompts.credentials.passwords.vault.length - 1; i >= 0; i--) { - if(cred.id === scope.promptData.prompts.credentials.passwords.vault[i].id) { - scope.promptData.prompts.credentials.passwords.vault.splice(i, 1); - } - } - } - } - - }; - - let updateNeededPasswords = (cred) => { - if(cred.inputs) { - if(cred.inputs.password && cred.inputs.password === "ASK") { - scope.promptData.prompts.credentials.passwords.ssh_password = { - id: cred.id, - name: cred.name - }; - } - if(cred.inputs.become_password && cred.inputs.become_password === "ASK") { - scope.promptData.prompts.credentials.passwords.become_password = { - id: cred.id, - name: cred.name - }; - } - if(cred.inputs.ssh_key_unlock && cred.inputs.ssh_key_unlock === "ASK") { - scope.promptData.prompts.credentials.passwords.ssh_key_unlock = { - id: cred.id, - name: cred.name - }; - } - if(cred.inputs.vault_password && cred.inputs.vault_password === "ASK") { - if(!scope.promptData.prompts.credentials.passwords.vault) { - scope.promptData.prompts.credentials.passwords.vault = []; - } - scope.promptData.prompts.credentials.passwords.vault.push({ - id: cred.id, - name: cred.name, - vault_id: cred.inputs.vault_id - }); - } - } - }; - - let checkMissingCredType = (cred) => { - scope.promptData.launchConf.defaults.credentials.forEach((defaultCred) => { - if(cred.credential_type === defaultCred.credential_type) { - let credTypeLabel = ""; - scope.promptData.prompts.credentials.credentialTypeOptions.forEach((credTypeOption) => { - if(credTypeOption.value === defaultCred.credential_type) { - credTypeLabel = credTypeOption.name; - } - }); - - if(scope.promptData.prompts.credentials.credentialTypes[cred.credential_type] === "vault") { - if((_.get(cred, 'inputs.vault_id') ? _.get(cred, 'inputs.vault_id') : _.get(cred, 'vault_id')) === _.get(defaultCred, 'vault_id')) { - scope.promptData.credentialTypeMissing.push({ - credential_type: defaultCred.credential_type, - vault_id: defaultCred.vault_id, - label: defaultCred.vault_id ? `${credTypeLabel} (id: ${defaultCred.vault_id})` : credTypeLabel - }); - } - } else { - scope.promptData.credentialTypeMissing.push({ - credential_type: defaultCred.credential_type, - label: credTypeLabel - }); - } - } - }); - }; - - vm.init = (_scope_, _launch_) => { - scope = _scope_; - launch = _launch_; - - scope.toggle_row = (selectedRow) => { - let selectedCred = _.cloneDeep(selectedRow); - - for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) { - if(scope.promptData.prompts.credentials.value[i].credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) { - wipePasswords(scope.promptData.prompts.credentials.value[i]); - scope.promptData.prompts.credentials.value.splice(i, 1); - } - } - - scope.promptData.prompts.credentials.value.push(selectedCred); - updateNeededPasswords(selectedRow); - - for (let i = scope.promptData.credentialTypeMissing.length - 1; i >= 0; i--) { - if(scope.promptData.credentialTypeMissing[i].credential_type === selectedRow.credential_type) { - scope.promptData.credentialTypeMissing.splice(i,1); - i = -1; - } - } - }; - - scope.toggle_credential = (cred) => { - // This is a checkbox click. At the time of writing this the only - // multi-select credentials on launch are vault credentials so this - // logic should only get executed when a vault credential checkbox - // is clicked. - - let uncheck = false; - - let removeCredential = (credentialToRemove, index) => { - wipePasswords(credentialToRemove); - scope.promptData.prompts.credentials.value.splice(index, 1); - }; - - // Only one vault credential per vault_id is allowed so we need to check - // to see if one has already been selected and if so replace it. - for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) { - if(cred.credential_type === scope.promptData.prompts.credentials.value[i].credential_type) { - if(scope.promptData.prompts.credentials.value[i].id === cred.id) { - removeCredential(scope.promptData.prompts.credentials.value[i], i); - i = -1; - uncheck = true; - } - else if(scope.promptData.prompts.credentials.value[i].inputs) { - if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].inputs.vault_id) { - removeCredential(scope.promptData.prompts.credentials.value[i], i); - } - } else if(scope.promptData.prompts.credentials.value[i].vault_id) { - if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].vault_id) { - removeCredential(scope.promptData.prompts.credentials.value[i], i); - } - } else { - // The currently selected vault credential does not have a vault_id - if(!cred.inputs.vault_id || cred.inputs.vault_id === "") { - removeCredential(scope.promptData.prompts.credentials.value[i], i); - } - } - } - } - - if(!uncheck) { - scope.promptData.prompts.credentials.value.push(cred); - updateNeededPasswords(cred); - - _.remove(scope.promptData.credentialTypeMissing, (missingCredType) => { - return ( - missingCredType.credential_type === cred.credential_type && - _.get(cred, 'inputs.vault_id') === _.get(missingCredType, 'vault_id') - ); - }); - } else { - if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) { - checkMissingCredType(cred); - } - } - }; - - scope.credential_dataset = []; - scope.credentials = []; - - let credList = _.cloneDeep(CredentialList); - credList.emptyListText = strings.get('prompt.NO_CREDS_MATCHING_TYPE'); - scope.list = credList; - scope.generateCredentialList(scope.promptData.prompts.credentials.credentialKind); - - scope.credential_default_params = { - order_by: 'name', - page_size: 5 - }; - - scope.credential_queryset = { - order_by: 'name', - page_size: 5 - }; - - scope.$watch('promptData.prompts.credentials.credentialKind', (oldKind, newKind) => { - if (scope.promptData.prompts.credentials && scope.promptData.prompts.credentials.credentialKind) { - if(scope.promptData.prompts.credentials.credentialTypes[oldKind] === "vault" || scope.promptData.prompts.credentials.credentialTypes[newKind] === "vault") { - scope.generateCredentialList(scope.promptData.prompts.credentials.credentialKind); - } - scope.credential_queryset.page = 1; - scope.credential_default_params.credential_type = scope.credential_queryset.credential_type = parseInt(scope.promptData.prompts.credentials.credentialKind); - - qs.search(GetBasePath('credentials'), scope.credential_default_params) - .then(res => { - scope.credential_dataset = res.data; - scope.credentials = scope.credential_dataset.results; - }); - } - }); - - scope.$watchCollection('promptData.prompts.credentials.value', () => { - updateSelectedRow(); - }); - - scope.$watchCollection('credentials', () => { - updateSelectedRow(); - }); - - CreateSelect2({ - element: '#launch-kind-select', - multiple: false - }); - }; - - vm.deleteSelectedCredential = (credentialToDelete) => { - for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) { - if(scope.promptData.prompts.credentials.value[i].id === credentialToDelete.id) { - if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) { - checkMissingCredType(credentialToDelete); - } - wipePasswords(credentialToDelete); - scope.promptData.prompts.credentials.value.splice(i, 1); - } - } - - scope.credentials.forEach((credential, i) => { - if(credential.id === credentialToDelete.id) { - scope.credentials[i].checked = 0; - } - }); - }; - - vm.revert = () => { - scope.promptData.prompts.credentials.value = _.has(scope, 'promptData.launchConf.defaults.credentials') ? _.cloneDeep(scope.promptData.launchConf.defaults.credentials) : []; - scope.promptData.prompts.credentials.passwords = { - vault: [] - }; - scope.promptData.prompts.credentials.value.forEach((credential) => { - if (credential.passwords_needed && credential.passwords_needed.length > 0) { - credential.passwords_needed.forEach(passwordNeeded => { - let credPassObj = { - id: credential.id, - name: credential.name - }; - - if(passwordNeeded === "ssh_password") { - scope.promptData.prompts.credentials.passwords.ssh_password = credPassObj; - } - if(passwordNeeded === "become_password") { - scope.promptData.prompts.credentials.passwords.become_password = credPassObj; - } - if(passwordNeeded === "ssh_key_unlock") { - scope.promptData.prompts.credentials.passwords.ssh_key_unlock = credPassObj; - } - if(passwordNeeded.startsWith("vault_password")) { - credPassObj.vault_id = credential.vault_id; - scope.promptData.prompts.credentials.passwords.vault.push(credPassObj); - } - }); - - } - }); - - scope.promptData.credentialTypeMissing = []; - }; - - vm.showRevertCredentials = () => { - if(scope.promptData.launchConf.ask_credential_on_launch) { - if(scope.promptData.prompts.credentials.value && _.has(scope, 'promptData.launchConf.defaults.credentials') && (scope.promptData.prompts.credentials.value.length === scope.promptData.launchConf.defaults.credentials.length)) { - let selectedIds = scope.promptData.prompts.credentials.value.map((x) => { return x.id; }).sort(); - let defaultIds = _.has(scope, 'promptData.launchConf.defaults.credentials') ? scope.promptData.launchConf.defaults.credentials.map((x) => { return x.id; }).sort() : []; - return !selectedIds.every((e, i) => { return defaultIds.indexOf(e) === i; }); - } else { - return true; - } - } else { - return false; - } - }; - - vm.togglePassword = (id) => { - var buttonId = id + "_show_input_button", - inputId = id; - if ($(inputId).attr("type") === "password") { - $(buttonId).html(strings.get('HIDE')); - $(inputId).attr("type", "text"); - } else { - $(buttonId).html(strings.get('SHOW')); - $(inputId).attr("type", "password"); - } - }; - } - ]; diff --git a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.directive.js b/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.directive.js deleted file mode 100644 index 80d277db7a8b..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.directive.js +++ /dev/null @@ -1,57 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import promptCredentialController from './prompt-credential.controller'; - -export default [ 'templateUrl', '$compile', 'generateList', - (templateUrl, $compile, GenerateList) => { - return { - scope: { - promptData: '=', - credentialPasswordsForm: '=', - preventCredsWithPasswords: '<' - }, - templateUrl: templateUrl('templates/prompt/steps/credential/prompt-credential'), - controller: promptCredentialController, - controllerAs: 'vm', - require: ['^^prompt', 'promptCredential'], - restrict: 'E', - replace: true, - transclude: true, - link: (scope, el, attrs, controllers) => { - - const launchController = controllers[0]; - const promptCredentialController = controllers[1]; - - scope.generateCredentialList = (credKind) => { - let inputType = (credKind && scope.promptData.prompts.credentials.credentialTypes[credKind] === "vault") ? null : 'radio'; - let list = _.cloneDeep(scope.list); - - if(credKind && scope.promptData.prompts.credentials.credentialTypes[credKind] === "vault") { - list.fields.name.modalColumnClass = 'col-md-6'; - list.fields.info = { - label: 'Vault ID', - ngBind: 'credential.inputs.vault_id', - key: false, - nosort: true, - modalColumnClass: 'col-md-6', - infoHeaderClass: '', - dataPlacement: 'top', - }; - } - - let html = GenerateList.build({ - list: list, - input_type: inputType, - mode: 'lookup' - }); - $('#prompt-credential').empty().append($compile(html)(scope)); - }; - - promptCredentialController.init(scope, launchController); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.partial.html b/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.partial.html deleted file mode 100644 index 7b1ca2b0936e..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/credential/prompt-credential.partial.html +++ /dev/null @@ -1,130 +0,0 @@ -
-
-
-
- {{:: vm.strings.get('prompt.SELECTED') }} -
-
-
{{:: vm.strings.get('prompt.NO_CREDENTIALS_SELECTED') }}
-
-
-
- - - - - - -
-
- - {{ credential.name }} - - - {{ credential.name }} | {{ credential.vault_id ? credential.vault_id : credential.inputs.vault_id }} - -
-
- -
-
-
-
- -
-
-
-
-  {{:: vm.strings.get('prompt.CREDENTIAL_TYPE_MISSING', missingCred.label) }} -
-
- -
-
- - {{ vm.strings.get('prompt.CREDENTIAL_PASSWORD_WARNING')}} -
-
-
{{promptData.prompts.credentials.passwords.ssh_password.name || promptData.prompts.credentials.passwords.become_password.name || promptData.prompts.credentials.passwords.ssh_key_unlock.name}}
-
{{vaultCred.name}}
-
-
-
- -
- {{:: vm.strings.get('prompt.CREDENTIAL_TYPE') }}: - -
-
-
-
-
{{:: vm.strings.get('prompt.PASSWORDS_REQUIRED_HELP') }}
-
-
- -
- - - - -
-
{{:: vm.strings.get('prompt.PLEASE_ENTER_PASSWORD') }}
-
-
-
- -
- - - - -
-
{{:: vm.strings.get('prompt.PLEASE_ENTER_PASSWORD') }}
-
-
-
- -
- - - - -
-
{{:: vm.strings.get('prompt.PLEASE_ENTER_PASSWORD') }}
-
-
- -
- -
- - - - -
-
{{:: vm.strings.get('prompt.PLEASE_ENTER_PASSWORD') }}
-
-
- -
-
diff --git a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.controller.js b/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.controller.js deleted file mode 100644 index 25295583493d..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.controller.js +++ /dev/null @@ -1,37 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ 'TemplatesStrings', function(strings) { - const vm = this; - - vm.strings = strings; - - let scope; - let launch; - - vm.init = (_scope_, _launch_) => { - scope = _scope_; - launch = _launch_; - - scope.toggle_row = (row) => { - scope.promptData.prompts.inventory.value = row; - }; - }; - - vm.deleteSelectedInventory = () => { - scope.promptData.prompts.inventory.value = null; - - scope.inventories.forEach((inventory) => { - inventory.checked = 0; - }); - }; - - vm.revert = () => { - scope.promptData.prompts.inventory.value = scope.promptData.launchConf.defaults.inventory; - }; - } - ]; diff --git a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.directive.js b/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.directive.js deleted file mode 100644 index e3b1d24823c9..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.directive.js +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import promptInventoryController from './prompt-inventory.controller'; - -export default [ 'templateUrl', 'QuerySet', 'GetBasePath', 'generateList', '$compile', 'InventoryList', - (templateUrl, qs, GetBasePath, GenerateList, $compile, InventoryList) => { - return { - scope: { - promptData: '=' - }, - templateUrl: templateUrl('templates/prompt/steps/inventory/prompt-inventory'), - controller: promptInventoryController, - controllerAs: 'vm', - require: ['^^prompt', 'promptInventory'], - restrict: 'E', - replace: true, - transclude: true, - link: (scope, el, attrs, controllers) => { - - const launchController = controllers[0]; - const promptInventoryController = controllers[1]; - - promptInventoryController.init(scope, launchController); - - scope.inventory_default_params = { - order_by: 'name', - page_size: 5 - }; - - scope.inventory_queryset = { - order_by: 'name', - page_size: 5 - }; - - // Fire off the initial search - qs.search(GetBasePath('inventory'), scope.inventory_default_params) - .then(res => { - scope.inventory_dataset = res.data; - scope.inventories = scope.inventory_dataset.results; - - let invList = _.cloneDeep(InventoryList); - let html = GenerateList.build({ - list: invList, - input_type: 'radio', - mode: 'lookup' - }); - - scope.list = invList; - - $('#prompt-inventory').append($compile(html)(scope)); - - scope.$watch('promptData.prompts.inventory.value', () => { - scope.inventories.forEach((row, i) => { - if ( - _.has(scope, 'promptData.prompts.inventory.value.id') && - row.id === scope.promptData.prompts.inventory.value.id - ) { - scope.inventories[i].checked = 1; - } - else { - scope.inventories[i].checked = 0; - } - }); - }); - }); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.partial.html b/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.partial.html deleted file mode 100644 index 3292da4a98b3..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/inventory/prompt-inventory.partial.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
-
-
- {{:: vm.strings.get('prompt.SELECTED') }} -
-
-
{{:: vm.strings.get('prompt.NO_INVENTORY_SELECTED') }}
-
-
-
- {{promptData.prompts.inventory.value.name}} -
-
- -
-
-
-
- -
-
-
-
diff --git a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.controller.js b/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.controller.js deleted file mode 100644 index 96a087218dcf..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.controller.js +++ /dev/null @@ -1,94 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - ['ParseTypeChange', 'CreateSelect2', 'TemplatesStrings', '$timeout', function(ParseTypeChange, CreateSelect2, strings, $timeout) { - const vm = this; - - vm.strings = strings; - - let scope; - let launch; - - vm.init = (_scope_, _launch_) => { - scope = _scope_; - launch = _launch_; - - scope.parseType = 'yaml'; - - // Can't pass otherPrompts.variables.value into ParseTypeChange - // due to the fact that Angular CodeMirror uses scope[string] - // notation. - scope.extraVariables = scope.promptData.prompts.variables.value; - - scope.$watch('extraVariables', () => { - scope.promptData.prompts.variables.value = scope.extraVariables; - }); - - let codemirrorExtraVars = () => { - if(scope.promptData.launchConf.ask_variables_on_launch && !scope.promptData.prompts.variables.ignore) { - $timeout(() => { - ParseTypeChange({ - scope: scope, - variable: 'extraVariables', - field_id: 'job_launch_variables' - }); - }); - } - }; - - if(scope.promptData.launchConf.ask_job_type_on_launch) { - CreateSelect2({ - element: '#job_launch_job_type', - multiple: false - }); - } - - if(scope.promptData.launchConf.ask_verbosity_on_launch) { - CreateSelect2({ - element: '#job_launch_verbosity', - multiple: false - }); - } - - if(scope.promptData.launchConf.ask_tags_on_launch) { - CreateSelect2({ - element: '#job_launch_job_tags', - multiple: true, - addNew: true - }); - } - - if(scope.promptData.launchConf.ask_skip_tags_on_launch) { - CreateSelect2({ - element: '#job_launch_skip_tags', - multiple: true, - addNew: true - }); - } - - if(scope.isActiveStep) { - codemirrorExtraVars(); - } - - scope.$watch('isActiveStep', () => { - if(scope.isActiveStep) { - codemirrorExtraVars(); - } - }); - }; - - vm.toggleDiff = () => { - scope.promptData.prompts.diffMode.value = !scope.promptData.prompts.diffMode.value; - }; - - vm.updateParseType = (parseType) => { - scope.parseType = parseType; - // This function gets added to scope by the ParseTypeChange factory - scope.parseTypeChange('parseType', 'extraVariables'); - }; - } - ]; diff --git a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.directive.js b/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.directive.js deleted file mode 100644 index c551fc8bd727..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.directive.js +++ /dev/null @@ -1,32 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import promptOtherPrompts from './prompt-other-prompts.controller'; - -export default [ 'templateUrl', - (templateUrl) => { - return { - scope: { - promptData: '=', - otherPromptsForm: '=', - isActiveStep: '=' - }, - templateUrl: templateUrl('templates/prompt/steps/other-prompts/prompt-other-prompts'), - controller: promptOtherPrompts, - controllerAs: 'vm', - require: ['^^prompt', 'promptOtherPrompts'], - restrict: 'E', - replace: true, - transclude: true, - link: (scope, el, attrs, controllers) => { - - const launchController = controllers[0]; - const promptOtherPromptsController = controllers[1]; - - promptOtherPromptsController.init(scope, launchController); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html b/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html deleted file mode 100644 index 9d731d185f67..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html +++ /dev/null @@ -1,110 +0,0 @@ -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
-
- - -
-
-
-
- -
- -
-
- diff --git a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.controller.js b/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.controller.js deleted file mode 100644 index 2eeddc48837e..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.controller.js +++ /dev/null @@ -1,97 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ 'ParseTypeChange', 'ToJSON', 'TemplatesStrings', function(ParseTypeChange, ToJSON, strings) { - const vm = this; - - vm.strings = strings; - - let scope; - let launch; - - let consolidateTags = (tagModel, tagId) => { - let tags = angular.copy(tagModel); - $(tagId).siblings(".select2").first().find(".select2-selection__choice").each((optionIndex, option) => { - tags.push({ - value: option.title, - name: option.title, - label: option.title - }); - }); - - return [...tags.reduce((map, tag) => map.has(tag.value) ? map : map.set(tag.value, tag), new Map()).values()]; - }; - - vm.init = (_scope_, _launch_) => { - scope = _scope_; - launch = _launch_; - - vm.showJobTags = true; - vm.showSkipTags = true; - - scope.parseType = 'yaml'; - - scope.promptData.extraVars = ToJSON(scope.parseType, scope.promptData.prompts.variables.value, false); - - const surveyPasswords = {}; - - if (scope.promptData.launchConf.ask_tags_on_launch) { - scope.promptData.prompts.tags.value = consolidateTags(scope.promptData.prompts.tags.value, "#job_launch_job_tags"); - } - - if (scope.promptData.launchConf.ask_skip_tags_on_launch) { - scope.promptData.prompts.skipTags.value = consolidateTags(scope.promptData.prompts.skipTags.value, "#job_launch_skip_tags"); - } - - if (scope.promptData.launchConf.survey_enabled){ - scope.promptData.surveyQuestions.forEach(surveyQuestion => { - // grab all survey questions that have answers - if (surveyQuestion.required || (surveyQuestion.required === false && surveyQuestion.model.toString()!=="")) { - if (!scope.promptData.extraVars) { - scope.promptData.extraVars = {}; - } - scope.promptData.extraVars[surveyQuestion.variable] = surveyQuestion.model; - } - - if (surveyQuestion.required === false && _.isEmpty(surveyQuestion.model)) { - switch (surveyQuestion.type) { - // for optional text and text-areas, submit a blank string if min length is 0 - // -- this is confusing, for an explanation see: - // http://docs.ansible.com/ansible-tower/latest/html/userguide/job_templates.html#optional-survey-questions - // - case "text": - case "textarea": - if (surveyQuestion.min === 0) { - scope.promptData.extraVars[surveyQuestion.variable] = ""; - } - break; - } - } - - if (surveyQuestion.type === 'password' && surveyQuestion.model.toString()!=="") { - surveyPasswords[surveyQuestion.variable] = '$encrypted$'; - } - }); - } - - // We don't want to modify the extra vars when we merge them with the survey - // password $encrypted$ strings so we clone it - const extraVarsClone = _.cloneDeep(scope.promptData.extraVars); - // Replace the survey passwords with $encrypted$ to display to the user - const cleansedExtraVars = extraVarsClone ? Object.assign(extraVarsClone, surveyPasswords) : {}; - - scope.promptExtraVars = $.isEmptyObject(scope.promptData.extraVars) ? '---' : '---\n' + jsyaml.safeDump(cleansedExtraVars); - - ParseTypeChange({ - scope: scope, - variable: 'promptExtraVars', - field_id: 'job_launch_preview_variables', - readOnly: true - }); - }; - } - ]; diff --git a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.directive.js b/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.directive.js deleted file mode 100644 index 034236cc4355..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.directive.js +++ /dev/null @@ -1,30 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import promptPreview from './prompt-preview.controller'; - -export default [ 'templateUrl', - (templateUrl) => { - return { - scope: { - promptData: '=' - }, - templateUrl: templateUrl('templates/prompt/steps/preview/prompt-preview'), - controller: promptPreview, - controllerAs: 'vm', - require: ['^^prompt', 'promptPreview'], - restrict: 'E', - replace: true, - transclude: true, - link: (scope, el, attrs, controllers) => { - - const launchController = controllers[0]; - const promptPreviewController = controllers[1]; - - promptPreviewController.init(scope, launchController); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.partial.html b/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.partial.html deleted file mode 100644 index ba83655f9b54..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/preview/prompt-preview.partial.html +++ /dev/null @@ -1,84 +0,0 @@ -
-
-
{{:: vm.strings.get('prompt.JOB_TYPE') }}
-
- {{:: vm.strings.get('prompt.PLAYBOOK_RUN') }} - {{:: vm.strings.get('prompt.CHECK') }} -
-
-
-
{{:: vm.strings.get('prompt.CREDENTIAL') }}
-
-
-
- - - - - - - - - -
-
-
-
-
-
{{:: vm.strings.get('prompt.INVENTORY') }}
-
-
-
-
{{:: vm.strings.get('prompt.LIMIT') }}
-
-
-
-
{{:: vm.strings.get('prompt.VERBOSITY') }}
-
-
-
-
- {{:: vm.strings.get('prompt.JOB_TAGS') }}  - - - - -
-
-
-
- {{tag.name}} -
-
-
-
-
-
- {{:: vm.strings.get('prompt.SKIP_TAGS') }}  - - - - -
-
-
-
- {{tag.name}} -
-
-
-
-
-
{{:: vm.strings.get('prompt.SHOW_CHANGES') }}
-
- {{:: vm.strings.get('ON') }} - {{:: vm.strings.get('OFF') }} -
-
-
-
{{:: vm.strings.get('prompt.EXTRA_VARIABLES') }}
-
- -
-
-
diff --git a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.controller.js b/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.controller.js deleted file mode 100644 index e37afa49fb22..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.controller.js +++ /dev/null @@ -1,35 +0,0 @@ -/************************************************* - * Copyright (c) 2017 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default - [ 'TemplatesStrings', function(strings) { - const vm = this; - - vm.strings = strings; - - let scope; - let launch; - - vm.init = (_scope_, _launch_) => { - scope = _scope_; - launch = _launch_; - }; - - // This function is used to hide/show the contents of a password - // within a form - vm.togglePassword = (id) => { - var buttonId = id + "_show_input_button", - inputId = id; - if ($(inputId).attr("type") === "password") { - $(buttonId).html(strings.get('HIDE')); - $(inputId).attr("type", "text"); - } else { - $(buttonId).html(strings.get('SHOW')); - $(inputId).attr("type", "password"); - } - }; - } - ]; diff --git a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.directive.js b/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.directive.js deleted file mode 100644 index 80e07fd40490..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.directive.js +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import promptSurvey from './prompt-survey.controller'; - -export default [ 'templateUrl', - (templateUrl) => { - return { - scope: { - promptData: '=', - surveyForm: '=' - }, - templateUrl: templateUrl('templates/prompt/steps/survey/prompt-survey'), - controller: promptSurvey, - controllerAs: 'vm', - require: ['^^prompt', 'promptSurvey'], - restrict: 'E', - replace: true, - transclude: true, - link: (scope, el, attrs, controllers) => { - - const launchController = controllers[0]; - const promptSurveyController = controllers[1]; - - promptSurveyController.init(scope, launchController); - } - }; -}]; diff --git a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.partial.html b/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.partial.html deleted file mode 100644 index 73d23c6f810c..000000000000 --- a/awx/ui/client/src/templates/prompt/steps/survey/prompt-survey.partial.html +++ /dev/null @@ -1,69 +0,0 @@ -
-
- - -
- -
-
- -
{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}
-
Please enter an answer between {{question.minlength}} to {{question.maxlength}} characters long.
-
-
- -
{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}
-
Please enter an answer between {{question.minlength}} to {{question.maxlength}} characters long.
-
-
-
- - - - - -
-
{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}
-
Please enter an answer between {{question.minlength}} to {{question.maxlength}} characters long.
-
-
- -
{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}
-
{{:: vm.strings.get('prompt.VALID_INTEGER') }}
-
Please enter an answer between {{question.minValue}} and {{question.maxValue}}.
-
-
- -
{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}
-
{{:: vm.strings.get('prompt.VALID_DECIMAL') }}
-
Please enter an answer between {{question.minValue}} and {{question.maxValue}}.
-
-
-
- - -
-
{{:: vm.strings.get('prompt.PLEASE_SELECT_VALUE') }}
-
-
- - -
{{:: vm.strings.get('prompt.PLEASE_SELECT_VALUE') }}
-
-
- diff --git a/awx/ui/client/src/templates/survey-maker/main.js b/awx/ui/client/src/templates/survey-maker/main.js deleted file mode 100644 index 1d41e63aef5e..000000000000 --- a/awx/ui/client/src/templates/survey-maker/main.js +++ /dev/null @@ -1,14 +0,0 @@ -import listGenerator from '../../shared/list-generator/main'; -import questions from './questions/main'; -import surveys from './surveys/main'; -import render from './render/main'; -import shared from './shared/main'; - -export default - angular.module('templates.surveyMaker', - [ listGenerator.name, - questions.name, - surveys.name, - render.name, - shared.name - ]); diff --git a/awx/ui/client/src/templates/survey-maker/questions/edit.factory.js b/awx/ui/client/src/templates/survey-maker/questions/edit.factory.js deleted file mode 100644 index 4aec1a5c6f18..000000000000 --- a/awx/ui/client/src/templates/survey-maker/questions/edit.factory.js +++ /dev/null @@ -1,100 +0,0 @@ -export default - function EditQuestion(GenerateForm, CreateSelect2, SurveyQuestionForm) { - return function(params) { - - var scope = params.scope, - index = params.index, - tmpVar, - i, - question = params.question, - form = SurveyQuestionForm; - - // Update the index so that we know which question is being edited. - scope.editQuestionIndex = index; - - scope.text_min = null; - scope.text_max = null; - scope.int_min = null; - scope.int_max = null; - scope.float_min = null; - scope.float_max = null; - scope.password_min = null; - scope.password_max = null; - scope.pwcheckbox = false; - - if (scope.removeFillQuestionForm) { - scope.removeFillQuestionForm(); - } - scope.removeFillQuestionForm = scope.$on('FillQuestionForm', function() { - for( var fld in form.fields){ - scope[fld] = question[fld]; - if(form.fields[fld].type === 'select'){ - for (i = 0; i < scope.answer_types.length; i++) { - if (question[fld] === scope.answer_types[i].type) { - scope[fld] = scope.answer_types[i]; - } - } - } - } - if( question.type === 'text'){ - scope.text_min = question.min; - scope.text_max = question.max; - scope.default_text = question.default; - } - if( question.type === 'textarea'){ - scope.textarea_min = question.min; - scope.textarea_max = question.max; - scope.default_textarea= question.default; - } - if(question.type === 'password'){ - scope.password_min = question.min; - scope.password_max = question.max; - scope.default_password = question.default; - } - if( question.type === 'integer'){ - scope.int_min = question.min; - scope.int_max = question.max; - scope.default_int = question.default; - } - else if( question.type === 'float' ) { - scope.float_min = question.min; - scope.float_max = question.max; - scope.default_float = question.default; - - } - else if ( question.type === 'multiselect'){ - scope.default_multiselect = question.default; - } - - // After we populate the form with data, need to call CreateSelect2 again - // to get the dropdown to show the selected item. - CreateSelect2({ - element:'#survey_question_type', - multiple: false - }); - - // Set the form to dirty. This lets the cancel button know that it should become enabled. - scope.survey_question_form.$setDirty(); - }); - - if (scope.removeGenerateForm) { - scope.removeGenerateForm(); - } - scope.removeGenerateForm = scope.$on('GenerateForm', function() { - tmpVar = scope.mode; - GenerateForm.inject(form, { id: 'survey_maker_question_form', mode: 'edit', related: false, scope:scope, noPanel: true }); - scope.mode = tmpVar; - scope.$emit('FillQuestionForm'); - }); - - - scope.$emit('GenerateForm'); - - }; - } - -EditQuestion.$inject = - [ 'GenerateForm', - 'CreateSelect2', - 'questionDefinitionForm' - ]; diff --git a/awx/ui/client/src/templates/survey-maker/questions/main.js b/awx/ui/client/src/templates/survey-maker/questions/main.js deleted file mode 100644 index 957c06638687..000000000000 --- a/awx/ui/client/src/templates/survey-maker/questions/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import questionScope from './question-scope.factory'; -import edit from './edit.factory'; - -export default - angular.module('jobTemplates.surveyMaker.questions', []) - .factory('questionScope', questionScope) - .factory('editQuestion', edit); diff --git a/awx/ui/client/src/templates/survey-maker/questions/question-scope.factory.js b/awx/ui/client/src/templates/survey-maker/questions/question-scope.factory.js deleted file mode 100644 index 31af0902a50a..000000000000 --- a/awx/ui/client/src/templates/survey-maker/questions/question-scope.factory.js +++ /dev/null @@ -1,25 +0,0 @@ -var typesSupportingIsolatedScope = - [ 'multiselect', - 'multiplechoice' - ]; - -function typeSupportsIsolatedScope(type) { - return _.include(typesSupportingIsolatedScope, type); -} - -function getIsolatedScope(question, oldScope) { - var newScope = oldScope.$new(); - newScope.question = question; - return newScope; -} - -export default - function() { - return function(question, oldScope) { - if (typeSupportsIsolatedScope(question.type)) { - return getIsolatedScope(question, oldScope); - } else { - return oldScope; - } - }; - } diff --git a/awx/ui/client/src/templates/survey-maker/render/main.js b/awx/ui/client/src/templates/survey-maker/render/main.js deleted file mode 100644 index 90390c74e1a4..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/main.js +++ /dev/null @@ -1,9 +0,0 @@ -import surveyQuestion from './survey-question.directive'; -import multipleChoice from './multiple-choice.directive'; -import multiSelect from './multiselect.directive'; - -export default - angular.module('jobTemplates.surveyMaker.render', []) - .directive('surveyQuestion', surveyQuestion) - .directive('multipleChoice', multipleChoice) - .directive('multiSelect', multiSelect); diff --git a/awx/ui/client/src/templates/survey-maker/render/multiple-choice.directive.js b/awx/ui/client/src/templates/survey-maker/render/multiple-choice.directive.js deleted file mode 100644 index c55231f24ebc..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/multiple-choice.directive.js +++ /dev/null @@ -1,47 +0,0 @@ -/* jshint unused: vars */ -import {templateUrl} from '../../../shared/template-url/template-url.factory'; - -function link($timeout, CreateSelect2, scope, element, attrs, ngModel) { - $timeout(function() { - - // select2-ify the dropdown. If the preview flag is passed here - // and it's true then we don't want to use a custom dropdown adapter. - // The reason for this is that the custom dropdown adapter breaks - // the draggability of this element. We're able to get away with this - // in preview mode (survey create/edit) because the element is disabled - // and we don't actually need the dropdown portion. Note that the custom - // dropdown adapter is used to get the dropdown contents to show up in - // a modal. - - CreateSelect2({ - element: element.find('select'), - multiple: scope.isMultipleSelect(), - minimumResultsForSearch: scope.isMultipleSelect() ? Infinity : 10, - customDropdownAdapter: scope.preview ? false : true - }); - }); - -} - -export default - [ '$timeout', 'CreateSelect2', - function($timeout, CreateSelect2) { - var directive = - { restrict: 'E', - require: 'ngModel', - scope: { - isMultipleSelect: '&multiSelect', - choices: '=', - question: '=', - isRequired: '=ngRequired', - selectedValue: '=ngModel', - isDisabled: '=ngDisabled', - preview: '=', - formElementName: '@' - }, - templateUrl: templateUrl('templates/survey-maker/render/multiple-choice'), - link: _.partial(link, $timeout, CreateSelect2) - }; - return directive; - } - ]; diff --git a/awx/ui/client/src/templates/survey-maker/render/multiple-choice.partial.html b/awx/ui/client/src/templates/survey-maker/render/multiple-choice.partial.html deleted file mode 100644 index a29362e7ecfc..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/multiple-choice.partial.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/awx/ui/client/src/templates/survey-maker/render/multiselect.directive.js b/awx/ui/client/src/templates/survey-maker/render/multiselect.directive.js deleted file mode 100644 index 82a39bbd547f..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/multiselect.directive.js +++ /dev/null @@ -1,49 +0,0 @@ -/* jshint unused: vars */ - -/** - * @ngdoc directive - * - * @name jobTemplates.surveyMaker.render.multiSelect - * @description - * Angular provides no method of binding to "multiple" for - * select lists. This is because under normal circumstances, - * the structure of `ng-model` changes based on whether `multiple` - * is true or false. We're not needing to "bind" to "multiple", - * but we do need to pass in the value dynamically. This allows - * us to do that. - */ - -var directive = - { require: 'ngModel', - controller: function($scope) { - $('select').on('select2:unselecting', (event) => { - if (_.has($scope.$parent, 'preview')) { - event.preventDefault(); - } - }); - }, - compile: function() { - return { - pre: function(scope, element, attrs, ngModel) { - if (_.isUndefined(scope.isMultipleSelect)) { - return; - } - - if (!scope.isMultipleSelect()) { - return; - } - - element.attr('multiple', true); - attrs.multiple = true; - - - } - }; - }, - priority: 1000 - }; - -export default - function() { - return directive; - } diff --git a/awx/ui/client/src/templates/survey-maker/render/survey-question.directive.js b/awx/ui/client/src/templates/survey-maker/render/survey-question.directive.js deleted file mode 100644 index ed613e745b7a..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/survey-question.directive.js +++ /dev/null @@ -1,128 +0,0 @@ -/* jshint unused: vars */ -import {templateUrl} from '../../../shared/template-url/template-url.factory'; - -/** - * @ngdoc directive - * @name jobTemplates.surveyMaker.render.surveyQuestion - * @description - * Directive that will eventually hold all logic - * for rendering different form controls based on - * the question type for a survey. - */ - -// Since we're generating HTML for the entire survey, and _then_ -// calling $compile, this directive never actually gets compiled -// with the question object we need. Therefore, we give it the index -// of the question as an attribute (not scope) and then look it up -// in the `survey_questions` by that index when it the directive gets -// compiled. -// -function findQuestionByIndex(questions, index) { - return _.find(questions, function(question) { - return question.index === index; - }); -} - -function link($sce, $filter, Empty, scope, element, attrs) { - - function serialize(expression) { - return $sce.getTrustedHtml(expression); - } - - function sanitizeDefault() { - - var defaultValue = "", - min, - max; - - if(scope.question.type === 'text'|| scope.question.type === "password" ){ - defaultValue = (scope.question.default) ? scope.question.default : ""; - defaultValue = $filter('sanitize')(defaultValue); - defaultValue = serialize(defaultValue); - } - - if(scope.question.type === "textarea"){ - defaultValue = (scope.question.default) ? scope.question.default : (scope.question.default_textarea) ? scope.question.default_textarea: "" ; - defaultValue = $filter('sanitize')(defaultValue); - defaultValue = serialize(defaultValue); - } - - if(scope.question.type === 'multiplechoice' || scope.question.type === "multiselect"){ - - scope.question.default = scope.question.default_multiselect || scope.question.default; - - if (scope.question.default) { - if (scope.question.type === 'multiselect' && typeof scope.question.default.split === 'function') { - defaultValue = scope.question.default.split('\n'); - } else if (scope.question.type !== 'multiselect') { - defaultValue = scope.question.default; - } - } else { - defaultValue = ''; - } - } - - if(scope.question.type === 'integer'){ - min = (!Empty(scope.question.min)) ? scope.question.min : ""; - max = (!Empty(scope.question.max)) ? scope.question.max : "" ; - defaultValue = (!Empty(scope.question.default)) ? scope.question.default : (!Empty(scope.question.default_int)) ? scope.question.default_int : "" ; - - } - if(scope.question.type === "float"){ - min = (!Empty(scope.question.min)) ? scope.question.min : ""; - max = (!Empty(scope.question.max)) ? scope.question.max : "" ; - defaultValue = (!Empty(scope.question.default)) ? scope.question.default : (!Empty(scope.question.default_float)) ? scope.question.default_float : "" ; - - } - - scope.defaultValue = defaultValue; - - } - - //for toggling the input on password inputs - scope.toggleInput = function(id) { - var buttonId = id + "_show_input_button", - inputId = id, - buttonInnerHTML = $(buttonId).html(); - if (buttonInnerHTML.indexOf("SHOW") > -1) { - $(buttonId).html("HIDE"); - $(inputId).attr("type", "text"); - } else { - $(buttonId).html("SHOW"); - $(inputId).attr("type", "password"); - } - }; - - if (!scope.question) { - scope.question = findQuestionByIndex(scope.surveyQuestions, Number(attrs.index)); - } - - // Split out choices to be consumed by the multiple-choice directive - if (!_.isUndefined(scope.question.choices)) { - scope.choices = scope.question.choices.split('\n'); - } - - sanitizeDefault(); - -} - -export default - [ - '$sce', '$filter', 'Empty', - function($sce, $filter, Empty) { - var directive = - { restrict: 'E', - scope: - { question: '=', - surveyQuestions: '=', - isRequired: '@ngRequired', - isDisabled: '@ngDisabled', - preview: '=' - }, - templateUrl: templateUrl('templates/survey-maker/render/survey-question'), - link: _.partial(link, $sce, $filter, Empty) - }; - - return directive; - } - ]; diff --git a/awx/ui/client/src/templates/survey-maker/render/survey-question.partial.html b/awx/ui/client/src/templates/survey-maker/render/survey-question.partial.html deleted file mode 100644 index 0be50a89b2ef..000000000000 --- a/awx/ui/client/src/templates/survey-maker/render/survey-question.partial.html +++ /dev/null @@ -1,30 +0,0 @@ -
- -
-
- -
-
- - -
-
- - - - -
- -
- -
-
- -
diff --git a/awx/ui/client/src/templates/survey-maker/shared/main.js b/awx/ui/client/src/templates/survey-maker/shared/main.js deleted file mode 100644 index 4b92e376b6c9..000000000000 --- a/awx/ui/client/src/templates/survey-maker/shared/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import form from './question-definition.form'; - -export default - angular.module('jobTemplates.surveyMaker.shared', []) - .factory('questionDefinitionForm', form); diff --git a/awx/ui/client/src/templates/survey-maker/shared/question-definition.form.js b/awx/ui/client/src/templates/survey-maker/shared/question-definition.form.js deleted file mode 100644 index 30613f21d5af..000000000000 --- a/awx/ui/client/src/templates/survey-maker/shared/question-definition.form.js +++ /dev/null @@ -1,312 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Questions - * @description This form is for adding a question -*/ - -export default ['i18n', function(i18n){ - return { - - addTitle: i18n._('ADD SURVEY PROMPT'), - editTitle: i18n._('EDIT SURVEY PROMPT'), - titleClass: 'Form-secondaryTitle', - base: 'survey_question', - name: 'survey_question', - well: true, - cancelButton: false, - - fields: { - question_name: { - realName: 'question_text', - label: i18n._('Prompt'), - type: 'text', - required: true, - column: 1, - awSurveyQuestion: true, - class: 'Form-formGroup--singleColumn' - }, - question_description: { - realName: 'question_description', - label: i18n._('Description'), - type: 'text', - column: 1, - class: 'Form-formGroup--singleColumn' - }, - variable: { - realName: 'variable', - type: 'custom', - label: i18n._('Answer Variable Name'), - control: - '
'+ - '
Please enter an answer variable name.
'+ - '
Please remove the illegal character from the survey question variable name.
'+ - '
This question variable is already in use. Please enter a different variable name.
' + - '
'+ - '
', - awPopOver: i18n._("The suggested format for variable names is lowercase and underscore-separated (for example, foo_bar, user_id, host_name, etc.). Variable names with spaces are not allowed."), - dataTitle: i18n._('Answer Variable Name'), - dataPlacement: 'right', - dataContainer: "body", - required: true, - column: 1, - class: 'Form-formGroup--singleColumn' - }, - type: { - realName: 'answer_type', - label: i18n._('Answer Type'), - type: 'select', - defaultText: i18n._('Choose an answer type'), - ngOptions: 'answer_types.name for answer_types in answer_types track by answer_types.type', - required: true, - awPopOver: i18n._('Choose an answer type or format you want as the prompt for the user. Refer to the Ansible Tower Documentation for more additional information about each option.'), - dataTitle: i18n._('Answer Type'), - dataPlacement: 'right', - dataContainer: "body", - column: 2, - ngChange: 'typeChange()', - class: 'Form-formGroup--singleColumn' - }, - choices: { - realName: 'answer_options', - label: i18n._('Multiple Choice Options'), - type: 'textarea', - rows: 3, - required: true, - - ngRequired: "type.type=== 'multiselect' || type.type=== 'multiplechoice' " , - ngShow: 'type.type=== "multiselect" || type.type=== "multiplechoice" ', - column: 2, - class: 'Form-formGroup--singleColumn' - }, - text_options: { - realName: 'answer_options', - type: 'custom', - control:'
'+ - '
'+ - ''+ - '
The minimum length you entered is not a valid number. Please enter a whole number.
'+ - '
The minimium length is too high. Please enter a lower number.
'+ - '
The minimum length is too low. Please enter a positive number.
'+ - '
'+ - '
'+ - ''+ - '
The maximum length you entered is not a valid number. Please enter a whole nnumber.
'+ - '
The maximum length is too low. Please enter a number larger than the minimum length you set.
'+ - '
'+ - '
', - ngShow: 'type.type==="text" ', - required: true, - column: 2, - class: 'Form-formGroup--singleColumn' - }, - textarea_options: { - realName: 'answer_options', - type: 'custom', - control:'
'+ - '
'+ - ''+ - '
The minimum length you entered is not a valid number. Please enter a whole number.
'+ - '
The minimium length is too high. Please enter a lower number.
'+ - '
The minimum length is too low. Please enter a positive number.
'+ - '
'+ - '
'+ - ''+ - '
The maximum length you entered is not a valid number. Please enter a whole number.
'+ - '
The maximum length is too low. Please enter a number larger than the minimum length you set.
'+ - '
'+ - '
', - ngShow: 'type.type==="textarea" ', - required: true, - column: 2, - class: 'Form-formGroup--singleColumn' - }, - password_options: { - realName: 'answer_options', - type: 'custom', - control:'
'+ - '
'+ - ''+ - '
The minimum length you entered is not a valid number. Please enter a whole number.
'+ - '
The minimium length is too high. Please enter a lower number.
'+ - '
The minimum length is too low. Please enter a positive number.
'+ - '
'+ - '
'+ - ''+ - '
The maximum length you entered is not a valid number. Please enter a whole number.
'+ - '
The maximum length is too low. Please enter a number larger than the minimum length you set.
'+ - '
'+ - '
', - ngShow: 'type.type==="password" ', - required: true, - - column: 2, - class: 'Form-formGroup--singleColumn' - }, - int_options: { - realName: 'answer_options', - type: 'custom', - control:'
'+ - '
'+ - ''+ - '
Please enter a valid integer.
'+ - '
Please enter a smaller integer.
'+ - '
'+ - '
'+ - ''+ - '
Please enter a valid integer.
'+ - '
Please enter a larger integer.
'+ - '
'+ - '
', - ngShow: 'type.type==="integer" ', - required: true, - column: 2, - class: 'Form-formGroup--singleColumn' - }, - float_options: { - realName: 'answer_options', - type: 'custom', - control: '
'+ - '
'+ - ''+ - '
Please enter a valid float.
'+ - '
Please enter a smaller float.
'+ - '
'+ - '
'+ - ''+ - '
Please enter a valid float.
'+ - '
Please enter a larger float.
'+ - - '
'+ - '
', - ngShow: 'type.type==="float" ', - required: true, - column: 2, - class: 'Form-formGroup--singleColumn' - }, - default:{ - realName: 'default_answer', - type: 'custom' , - control: '
'+ - ''+ - '
'+ - ''+ - '
Please enter an answer from the choices listed.
' + - '
The answer is shorter than the minimium length. Please make the answer longer.
' + - '
The answer is longer than the maximum length. Please make the answer shorter.
' + - '
'+ - '
'+ - '
', - column: 2, - ngShow: 'type.type === "text" || type.type === "multiplechoice" ', - class: 'Form-formGroup--singleColumn' - }, - default_multiselect: { - realName: 'default_answer' , - type: 'custom', - control: '
'+ - ''+ - '
'+ - ''+ - '
Please enter an answer/answers from the choices listed.
' + - '
'+ - '
'+ - '
', - column: 2, - ngShow: 'type.type==="multiselect" ', - class: 'Form-formGroup--singleColumn' - }, - default_int: { - realName: 'default_answer', - type: 'custom', - control: '
'+ - ''+ - ''+ - '
Please enter a valid integer.
'+ - '
Please enter a minimum default of {{int_min}}.
'+ - '
Please enter a maximum default of {{int_max}}.
'+ - '
', - column: 2, - ngShow: 'type.type === "integer" ', - class: 'Form-formGroup--singleColumn' - }, - default_float: { - realName: 'default_answer', - type: 'custom', - control: '
'+ - ''+ - ''+ - '
Please enter a valid float.
'+ - '
Please enter a minimum default of {{float_min}}.
'+ - '
Please enter a maximum default of {{float_max}}.
'+ - '
', - column: 2, - ngShow: 'type.type=== "float" ', - class: 'Form-formGroup--singleColumn' - }, - default_textarea: { - realName: "default_answer" , - type: 'custom', - control: '
'+ - ''+ - '
'+ - ''+ - '
The answer is shorter than the minimium length. Please make the answer longer.
' + - '
The answer is longer than the maximum length. Please make the answer shorter.
' + - '
'+ - '
'+ - '
', - column : 2, - ngShow: 'type.type === "textarea" ', - class: 'Form-formGroup--singleColumn' - }, - default_password: { - realName: 'default_answer' , - type: 'custom' , - control: '
'+ - ''+ - '
'+ - '
'+ - ''+ - ''+ - ''+ - ''+ - '
'+ - '
The answer is shorter than the minimium length. Please make the answer longer.
' + - '
The answer is longer than the maximum length. Please make the answer shorter.
' + - '
'+ - '
'+ - '
', - column: 2, - ngShow: 'type.type === "password" ', - class: 'Form-formGroup--singleColumn' - }, - required: { - realName: 'required_answer', - label: i18n._('Required'), - type: 'checkbox', - column: 2, - class: 'Form-formGroup--singleColumn' - } - }, - buttons: { - question_cancel : { - label: i18n._('Clear'), - 'class' : 'btn btn-default Form-cancelButton', - ngClick: 'generateAddQuestionForm()', - ngDisabled: 'survey_question_form.$pristine' - }, - submit_question: { - ngClick: 'submitQuestion($event)', - ngDisabled: true, - 'class': 'btn btn-sm Form-saveButton', - label: '{{editQuestionIndex === null ? "+ ADD" : "UPDATE"}}' - } - } -}; -}]; diff --git a/awx/ui/client/src/templates/survey-maker/shared/survey-controls.block.less b/awx/ui/client/src/templates/survey-maker/shared/survey-controls.block.less deleted file mode 100644 index 74b3af496733..000000000000 --- a/awx/ui/client/src/templates/survey-maker/shared/survey-controls.block.less +++ /dev/null @@ -1,11 +0,0 @@ -/** @define SurveyControls */ - -.SurveyControls { - &-selectWrapper { - margin-left: 15px; - } - &--dropdown { - z-index: 10000; - opacity: 1; - } -} diff --git a/awx/ui/client/src/templates/survey-maker/survey-maker.block.less b/awx/ui/client/src/templates/survey-maker/survey-maker.block.less deleted file mode 100644 index 8f5e036be3bd..000000000000 --- a/awx/ui/client/src/templates/survey-maker/survey-maker.block.less +++ /dev/null @@ -1,258 +0,0 @@ -.position-center { - left: 0; - right: 0; - margin: auto; -} - -.SurveyMaker-dialog { - max-width: 1200px; - padding: 0px; - .position-center; - - .ui-dialog-buttonpane, .ui-dialog-titlebar { - display:none; - } -} -.SurveyMaker-header { - display: flex; -} -.SurveyMaker-title { - align-items: center; - flex: 1 0 auto; - display: flex; - word-wrap: break-word; - word-break: break-all; - max-width: 98%; -} -.SurveyMaker-titleText { - color: @list-title-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - max-width: 75%; -} -.SurveyMaker-titleLockup { - margin-left: 4px; - margin-right: 6px; - display: inline-block; - margin-top: 0px; - padding-bottom: 2px; - vertical-align: bottom; -} -.SurveyMaker-titleLockup:before { - content: "\007C"; - color: @default-icon-hov; - display: block; - font-size: 13px; -} -.SurveyMaker-close { - justify-content: flex-end; - display: flex; -} -.SurveyMaker-exit{ - cursor:pointer; - padding:0px; - border: none; - height:20px; - font-size: 20px; - background-color:@default-bg; - color:@d7grey; - transition: color 0.2s; - line-height:1; -} -.SurveyMaker-exit:hover{ - color:@default-icon; -} -.SurveyMaker-content { - display: flex; - margin-top: 25px; - min-height: 560px; - flex-flow: row nowrap; - justify-content: space-around; -} -.SurveyMaker-questionPanel, -.SurveyMaker-previewPanel { - display: flex; - flex: 0 0 90%; - max-width: 500px; -} -.SurveyMaker-separatorPanel { - display: flex; - flex: 0 0 51px; -} -.SurveyMaker-contentSeparator { - width: 1px; - background-color: @default-list-header-bg; - margin: 0px 25px; -} -.SurveyMaker-panelHeader { - color: @default-icon; - padding-bottom: 20px; - min-height: 40px; - flex: 0 0 auto; - text-transform: uppercase; - font-size: 14px; - font-weight: bold; - white-space: nowrap; -} -.SurveyMaker-panelBody { - flex: 1 0 auto; - padding-bottom: 20px; -} -.SurveyMaker-panelFooter { - flex: 0 0 auto; -} -.SurveyMaker-noQuestions { - color: @default-icon; -} -.SurveyMaker-deleteButton { - color: @default-bg; - background-color: @default-err; - text-transform: uppercase; - padding-left:15px; - padding-right: 15px; - margin-right: 20px; -} -.SurveyMaker-deleteButton:hover { - background-color: @default-err-hov; - color: @default-bg; -} -.SurveyMaker-previewLabel { - text-transform: uppercase; - color: @default-interface-txt; - font-weight: normal; - font-size: small; - width: 100%; - word-break: break-word; -} -.SurveyMaker-deleteOverlay { - height: 100%; - width: 100%; - position: absolute; - top: 0; - left: 0; - background: rgba(0,0,0,0.3); - z-index: 3; - display: flex; - align-items: center; - justify-content: center; - border-radius: 4px; - - .Modal-content { - position: fixed; - top: ~"calc(50% - 100px)"; - width: 600px; - .position-center; - } -} -.SurveyMaker-previewInputRow { - display: flex; - margin-bottom: 20px; -} -.SurveyMaker-previewInput { - width: 100%; -} -.SurveyMaker-previewActions { - display: flex; - align-items: center; - margin-left: 20px; -} -.SurveyMaker-previewActions--selected { - background-color: @default-link !important; - color: @default-bg; -} -.SurveyMaker-previewRows { - position: relative; - min-height: 42px; - padding-left: 0px; - margin-bottom: 0px; - padding-bottom: 10px; - - /* These classes are dynamically added via the angular-drag-and-drop-lists directive */ - .dndPlaceholder { - display: block; - background-color: @default-tertiary-bg; - border: 1px solid @d7grey; - padding: 10px 15px; - min-height: 42px; - margin-bottom: 20px; - border-radius: 4px; - color: @default-interface-txt; - } - - .dndDraggingSource { - display: none; - } -} -.SurveyMaker-previewRow { - position: relative; - display: block; - - /* Disable text selection if item is not draggable */ - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.SurveyMaker-reorderButton { - color: @default-icon; - margin-right: 10px; - display: flex; - align-items: center; - cursor: -moz-grab; - cursor: -webkit-grab; - cursor: grab; -} -.SurveyMaker-reorderButton:hover { - color: @default-interface-txt; -} -.SurveyMaker-previewPasswordButton { - padding: 7px 15px!important; -} -.SurveyMaker-previewInput { - .select2-container--disabled { - opacity: inherit!important; - } -} -.SurveyMaker-previewMultiSelect { - background-color: #EEEEEE!important; - cursor: not-allowed!important; -} -.SurveyMaker-previewDescription { - margin-bottom: 5px; -} - -.SurveyMaker-questionPanel { - #survey_question_default_password { - button { - height: 30px; /* show/hide button should match our input height */ - } - } -} - -@media screen and (max-width: 1200px) { - .SurveyMaker-content { - flex-wrap: wrap; - justify-content: center; - } - .SurveyMaker-separatorPanel { - flex: 0 0 90%; - .SurveyMaker-contentSeparator { - width: 100%; - margin: 25px 0; - height: 1px; - } - } -} - -@media screen and (max-width: 600px) { - .SurveyMaker-dialog { - max-width: 100vw; - - .Modal-content { - max-width: ~"calc(100vw - 50px)"; - } - } -} diff --git a/awx/ui/client/src/templates/survey-maker/surveys/add.factory.js b/awx/ui/client/src/templates/survey-maker/surveys/add.factory.js deleted file mode 100644 index eef26fa5d67d..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/add.factory.js +++ /dev/null @@ -1,27 +0,0 @@ -export default - function AddFactory(ShowSurveyModal, Wait) { - return function(params) { - var scope = params.scope; - - // This variable controls the survey on/off toggle beside the create survey - // modal title. We want this toggle to be on by default - scope.survey_enabled = true; - - scope.isEditSurvey = false; - - if (scope.removeDialogReady) { - scope.removeDialogReady(); - } - scope.removeDialogReady = scope.$on('DialogReady', function() { - $('#survey-modal-dialog').dialog('open'); - scope.generateAddQuestionForm(); - }); - Wait('start'); - ShowSurveyModal({ scope: scope, callback: 'DialogReady' }); - }; - } - -AddFactory.$inject = - [ 'showSurvey', - 'Wait' - ]; diff --git a/awx/ui/client/src/templates/survey-maker/surveys/delete.factory.js b/awx/ui/client/src/templates/survey-maker/surveys/delete.factory.js deleted file mode 100644 index a1ee5d36608e..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/delete.factory.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Delete a survey. Prompts user to confirm delete - * - * DeleteSurvey({ - * scope: $scope containing list of survey form fields - * id: id of job template that survey is attached to - * }) - * - */ -export default - function DeleteSurvey(GetBasePath, Rest, Wait, ProcessErrors) { - return function(params) { - - var scope = params.scope, - id = params.id, - templateType = params.templateType, - url; - - - if (scope.removeSurveyDeleted) { - scope.removeSurveyDeleted(); - } - scope.$on('SurveyDeleted', function(){ - scope.survey_name = ""; - scope.survey_description = ""; - scope.survey_questions = []; - scope.closeSurvey('survey-modal-dialog'); - Wait('stop'); - scope.survey_exists = false; - }); - - - Wait('start'); - - if(scope.mode==="add"){ - scope.$emit("SurveyDeleted"); - - } else { - let basePath = templateType === 'workflow_job_template' ? GetBasePath('workflow_job_templates') : GetBasePath('job_templates'); - url = basePath + id + '/survey_spec/'; - - Rest.setUrl(url); - Rest.destroy() - .then(() => { - scope.$emit("SurveyDeleted"); - - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, { hdr: 'Error!', - msg: 'Failed to delete survey. DELETE returned status: ' + status }); - }); - } - }; - } - -DeleteSurvey.$inject = - [ 'GetBasePath', - 'Rest', - 'Wait', - 'ProcessErrors' - ]; diff --git a/awx/ui/client/src/templates/survey-maker/surveys/edit.factory.js b/awx/ui/client/src/templates/survey-maker/surveys/edit.factory.js deleted file mode 100644 index 90d2c734cef5..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/edit.factory.js +++ /dev/null @@ -1,67 +0,0 @@ -export default - function EditFactory(ShowSurveyModal, Wait, Rest, ProcessErrors, GetBasePath, Empty, AddSurvey) { - return function(params) { - var scope = params.scope, - id = params.id, - templateType = params.templateType, - url; - - if(templateType === 'job_template'){ - url = GetBasePath('job_templates') + id + '/survey_spec/'; - } - else if(templateType === 'workflow_job_template') { - url = GetBasePath('workflow_job_templates') + id + '/survey_spec/'; - } - - if (scope.removeDialogReady) { - scope.removeDialogReady(); - } - scope.removeDialogReady = scope.$on('DialogReady', function() { - $('#survey-modal-dialog').dialog('open'); - scope.generateAddQuestionForm(); - }); - - Wait('start'); - //for adding a job template: - if(scope.mode === 'add'){ - ShowSurveyModal({ title: "Edit Survey", scope: scope, callback: 'DialogReady' }); - } - //editing an existing job template: - else{ - // Get the existing record - Rest.setUrl(url); - Rest.get() - .then(({data}) => { - if(!Empty(data)){ - ShowSurveyModal({ title: "Edit Survey", scope: scope, callback: 'DialogReady' }); - scope.survey_name = data.name; - scope.survey_description = data.description; - scope.survey_questions = data.spec; - scope.isEditSurvey = true; - Wait('stop'); - } else { - AddSurvey({ - scope: scope - }); - } - - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve survey. GET returned status: ' + status }); - }); - - } - }; - } - - -EditFactory.$inject = - [ 'showSurvey', - 'Wait', - 'Rest', - 'ProcessErrors', - 'GetBasePath', - 'Empty', - 'addSurvey' - ]; diff --git a/awx/ui/client/src/templates/survey-maker/surveys/init.factory.js b/awx/ui/client/src/templates/survey-maker/surveys/init.factory.js deleted file mode 100644 index f3f7d09e8485..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/init.factory.js +++ /dev/null @@ -1,533 +0,0 @@ -export default - function Init(DeleteSurvey, EditSurvey, AddSurvey, GenerateForm, SurveyQuestionForm, Wait, Alert, - GetBasePath, Rest, ProcessErrors, EditQuestion, CreateSelect2) { - return function(params) { - var scope = params.scope, - id = params.id, - form = SurveyQuestionForm, - sce = params.sce, - templateType = params.templateType; - scope.sce = sce; - scope.survey_questions = []; - scope.answer_types=[ - {name: 'Text' , type: 'text'}, - {name: 'Textarea', type: 'textarea'}, - {name: 'Password', type: 'password'}, - {name: 'Multiple Choice (single select)', type: 'multiplechoice'}, - {name: 'Multiple Choice (multiple select)', type: 'multiselect'}, - {name: 'Integer', type: 'integer'}, - {name: 'Float', type: 'float'} - ]; - - /* SURVEY RELATED FUNCTIONS */ - - // Called when a job template does not have a saved survey. This simply sets some - // default variables and fills the add question form via form generator. - scope.addSurvey = function() { - AddSurvey({ - scope: scope - }); - }; - - // Called when a job template (new or existing) already has a "saved" survey - // In the case where a job template has not yet been created but a survey has - // been the data is just pulled out of the scope rather than from the server. - // (this is dictated by scope.mode) - scope.editSurvey = function() { - // Goes out and fetches the existing survey and populates the preview - EditSurvey({ - scope: scope, - id: id, - templateType: templateType - }); - }; - - // This gets called after a user confirms survey deletion - scope.deleteSurvey = function() { - // Hide the delete overlay - scope.hideDeleteOverlay(); - // Show the loading spinner - Wait('start'); - // Call the delete survey factory which handles making the rest call - // and closing the modal after success - DeleteSurvey({ - scope: scope, - id: id, - templateType: templateType - }); - }; - - // Called when the user hits cancel/close on the survey modal. This function - // goes out and cleans up the survey_questions on scope before destroying - // the modal. - scope.closeSurvey = function(id) { - // Clear out the whole array, this data gets pulled in each time the modal is opened - scope.survey_questions = []; - - $('#' + id).dialog('destroy'); - }; - - scope.saveSurvey = function() { - Wait('start'); - - scope.survey_name = ""; - scope.survey_description = ""; - - var updateSurveyQuestions = function() { - if(templateType === 'job_template') { - Rest.setUrl(GetBasePath('job_templates') + id + '/survey_spec/'); - } - else if(templateType === 'workflow_job_template') { - Rest.setUrl(GetBasePath('workflow_job_templates') + id + '/survey_spec/'); - } - return Rest.post({name: scope.survey_name, description: scope.survey_description, spec: scope.survey_questions }) - .then(() => { - - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to add new survey. POST returned status: ' + status }); - }); - }; - - var updateSurveyEnabled = function() { - if(templateType === 'job_template') { - Rest.setUrl(GetBasePath('job_templates') + id+ '/'); - } - else if(templateType === 'workflow_job_template') { - Rest.setUrl(GetBasePath('workflow_job_templates') + id+ '/'); - } - return Rest.patch({"survey_enabled": scope.survey_enabled}) - .then(() => { - - }) - .catch(({data, status}) => { - ProcessErrors(scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to save survey_enabled: GET status: ' + status - }); - }); - }; - - if (!scope.survey_questions || scope.survey_questions.length === 0) { - scope.deleteSurvey(); - } else { - updateSurveyQuestions() - .then(function() { - return updateSurveyEnabled(); - }) - .then(function() { - scope.closeSurvey('survey-modal-dialog'); - scope.$emit('SurveySaved'); - }); - } - }; - - // Gets called when the user clicks the on/off toggle beside the survey modal title. - scope.toggleSurveyEnabled = function() { - scope.survey_enabled = !scope.survey_enabled; - }; - - /* END SURVEY RELATED FUNCTIONS */ - - /* QUESTION RELATED FUNCTIONS */ - - // This injects the Add Question form into survey_maker_question_form - scope.generateAddQuestionForm = function(){ - // This tmpMode logic is necessary because form generator seems to set scope.mode to match the mode that you pass it. - // So if a user is editing a job template (scope.mode='edit') but the JT doesn't have a survey then when we open the - // modal we need to make sure that scope.mode is still 'edit' after the Add Question form is injected. - // To avoid having to do this we'd need to track the job template mode in a variable other than scope.mode. - var tmpMode = scope.mode; - GenerateForm.inject(form, { id:'survey_maker_question_form', mode: 'add' , scope: scope, related: false, noPanel: true}); - scope.mode = tmpMode; - scope.clearQuestion(); - }; - - // This gets called when a users clicks the pencil icon beside a question preview in order to edit it. - scope.editQuestion = function(index){ - scope.duplicate = false; - // The edit question factory injects the edit form and fills the form with the question data from memory. - EditQuestion({ - index: index, - scope: scope, - question: scope.survey_questions[index] - }); - }; - - // Gets called when a user clicks the delete icon on a question in the survey preview - scope.showDeleteQuestion = function(deleteIndex) { - // Keep track of the question to be deleted on scope - scope.questionToBeDeleted = deleteIndex; - // Show the delete overlay with mode='question' - scope.showDeleteOverlay('question'); - }; - - // Called after a user confirms question deletion (hitting the DELETE button on the delete question overlay). - scope.deleteQuestion = function(index){ - // Move the edit question index down by one if this question came before the - // one being edited in the array. This makes sure that our pointer to the question - // currently being edited gets updated independently from a deleted question. - if(GenerateForm.mode === 'edit' && !isNaN(scope.editQuestionIndex)){ - if(scope.editQuestionIndex === index) { - // The user is deleting the question being edited - need to roll back to Add Question mode - scope.editQuestionIndex = null; - scope.generateAddQuestionForm(); - } - else if(scope.editQuestionIndex > index) { - scope.editQuestionIndex--; - } - } - // Remove the question from the array - scope.survey_questions.splice(index, 1); - // Hide the delete overlay - scope.hideDeleteOverlay(); - }; - - function clearTypeSpecificFields() { - scope.minTextError = false; - scope.maxTextError = false; - scope.default = ""; - scope.default_multiselect = ""; - scope.default_float = ""; - scope.default_int = ""; - scope.default_textarea = ""; - scope.default_password = "" ; - scope.choices = ""; - scope.text_min = 0; - scope.text_max = 1024 ; - scope.textarea_min = 0; - scope.textarea_max = 4096; - scope.password_min = 0; - scope.password_max = 32; - scope.int_min = 0; - scope.int_max = 100; - scope.float_min = 0.0; - scope.float_max = 100.0; - } - - // Sets all of our scope variables used for adding/editing a question back to a clean state - scope.clearQuestion = function(){ - clearTypeSpecificFields(); - scope.editQuestionIndex = null; - scope.question_name = null; - scope.question_description = null; - scope.variable = null; - scope.required = true; //set the required checkbox to true via the ngmodel attached to scope.required. - scope.duplicate = false; - scope.invalidChoice = false; - scope.type = ""; - - // Make sure that the select2 dropdown for question type is clean - CreateSelect2({ - element:'#survey_question_type', - multiple: false - }); - - // Set the whole form to pristine - scope.survey_question_form.$setPristine(); - }; - - // Gets called when the "type" dropdown value changes. In that case, we want to clear out - // all the "type" specific fields/errors and start fresh. - scope.typeChange = function() { - clearTypeSpecificFields(); - scope.survey_question_form.default.$setPristine(); - scope.survey_question_form.default_multiselect.$setPristine(); - scope.survey_question_form.default_float.$setPristine(); - scope.survey_question_form.default_int.$setPristine(); - scope.survey_question_form.default_textarea.$setPristine(); - scope.survey_question_form.default_password.$setPristine(); - scope.survey_question_form.choices.$setPristine(); - scope.survey_question_form.int_min.$setPristine(); - scope.survey_question_form.int_max.$setPristine(); - }; - - // Function that gets called when a user hits ADD/UPDATE on the survey question form. This - // function handles some validation as well as eventually adding the question to the - // scope.survey_questions array. - scope.submitQuestion = function(){ - var data = {}, - fld, i, - choiceArray, - answerArray; - scope.invalidChoice = false; - scope.duplicate = false; - scope.minTextError = false; - scope.maxTextError = false; - - if(scope.type.type==="text"){ - if(scope.default.trim() !== ""){ - if(scope.default.trim().length < scope.text_min && scope.text_min !== "" ){ - scope.minTextError = true; - } - if(scope.text_max < scope.default.trim().length && scope.text_max !== "" ){ - scope.maxTextError = true; - } - } - } - - if(scope.type.type==="textarea"){ - if(scope.default_textarea.trim() !== ""){ - if(scope.default_textarea.trim().length < scope.textarea_min && scope.textarea_min !== "" ){ - scope.minTextError = true; - } - if(scope.textarea_max < scope.default_textarea.trim().length && scope.textarea_max !== "" ){ - scope.maxTextError = true; - } - } - } - - if(scope.type.type==="password"){ - if(scope.default_password.trim() !== ""){ - if(scope.default_password.trim().length < scope.password_min && scope.password_min !== "" ){ - scope.minTextError = true; - } - if(scope.password_max < scope.default_password.trim().length && scope.password_max !== "" ){ - scope.maxTextError = true; - } - } - } - - if(scope.type.type==="multiselect" && scope.default_multiselect.trim() !== ""){ - choiceArray = scope.choices.split(/\n/); - answerArray = scope.default_multiselect.split(/\n/); - - if(answerArray.length>0){ - for(i=0; i i && dropIndex >= scope.editQuestionIndex) { - // An element that was ahead of the edit question is now behind it - scope.editQuestionIndex--; - } - } - } - - // Break out of the for loop - break; - } - - } - - // return true here signals that the drop is allowed, but that we've already taken care of inserting the element - return true; - }; - - // Gets called when a user is creating/editing a question that has a password - // field. The password field in the form has a SHOW/HIDE button that calls this. - scope.toggleInput = function(id) { - // Note that the id string passed into this function will have a "#" prepended - var buttonId = id + "_show_input_button", - inputId = id, - buttonInnerHTML = $(buttonId).html(); - if (buttonInnerHTML.indexOf("SHOW") > -1) { - $(buttonId).html("HIDE"); - $(inputId).attr("type", "text"); - } else { - $(buttonId).html("SHOW"); - $(inputId).attr("type", "password"); - } - }; - - /* END QUESTION RELATED FUNCTIONS */ - - /* DELETE OVERLAY RELATED FUNCTIONS */ - - // This handles setting the delete mode and flipping the boolean used to show the delete overlay - scope.showDeleteOverlay = function(mode) { - // Set the delete mode (question or survey) so that the overlay knows - // how to phrase the prompt - scope.deleteMode = mode; - // Flip the deleteOverlayVisible flag so that the overlay becomes visible via ng-show - scope.deleteOverlayVisible = true; - }; - - // Called by the cancel/close buttons on the delete overlay. Also called after deletion has been confirmed. - scope.hideDeleteOverlay = function() { - // Clear out the delete mode for next time - scope.deleteMode = null; - // Clear out the index variable for next time - scope.questionToBeDeleted = null; - // Hide the delete overlay - scope.deleteOverlayVisible = false; - }; - - /* END DELETE OVERLAY RELATED FUNCTIONS */ - - // Watcher that updates the survey enabled/disabled tooltip based on scope.survey_enabled - scope.$watch('survey_enabled', function(newVal) { - scope.surveyEnabledTooltip = (newVal) ? "Disable survey" : "Enable survey"; - }); - - }; - } - -Init.$inject = - [ 'deleteSurvey', - 'editSurvey', - 'addSurvey', - 'GenerateForm', - 'questionDefinitionForm', - 'Wait', - 'Alert', - 'GetBasePath', - 'Rest', - 'ProcessErrors', - 'editQuestion', - 'CreateSelect2' - ]; diff --git a/awx/ui/client/src/templates/survey-maker/surveys/main.js b/awx/ui/client/src/templates/survey-maker/surveys/main.js deleted file mode 100644 index a16c10073cdb..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/main.js +++ /dev/null @@ -1,13 +0,0 @@ -import add from './add.factory'; -import edit from './edit.factory'; -import _delete from './delete.factory'; -import init from './init.factory'; -import show from './show.factory'; - -export default - angular.module('jobTemplates.surveyMaker.surveys', []) - .factory('showSurvey', show) - .factory('addSurvey', add) - .factory('editSurvey', edit) - .factory('deleteSurvey', _delete) - .factory('initSurvey', init); diff --git a/awx/ui/client/src/templates/survey-maker/surveys/show.factory.js b/awx/ui/client/src/templates/survey-maker/surveys/show.factory.js deleted file mode 100644 index 12faa2f401fb..000000000000 --- a/awx/ui/client/src/templates/survey-maker/surveys/show.factory.js +++ /dev/null @@ -1,53 +0,0 @@ -export default - function ShowFactory(Wait, CreateDialog, $compile) { - return function(params) { - // Set modal dimensions based on viewport width - - let scope = params.scope, - callback = params.callback, - mode = (params.mode) ? params.mode : "survey-maker", - title = params.title, - element, - target = (mode==='survey-taker') ? 'password-modal' : "survey-modal-dialog", - width = params.scope.can_edit ? 'calc(100vw - 50px)' : 600; - - - CreateDialog({ - id: target, - title: title, - scope: scope, - width: width, - minWidth: 400, - draggable: false, - dialogClass: 'SurveyMaker-dialog', - onClose: function() { - $('#'+target).empty(); - }, - onOpen: function() { - Wait('stop'); - - // Let the modal height be variable based on the content - // and set a uniform padding - $('#'+target).css({'height': 'auto', 'padding': '20px'}); - - if(mode==="survey-taker"){ - $('#survey-save-button').attr('ng-disabled', "survey_taker_form.$invalid"); - element = angular.element(document.getElementById('survey-save-button')); - $compile(element)(scope); - - } - - }, - _allowInteraction: function(e) { - return !!$(e.target).is('.select2-input') || this._super(e); - }, - callback: callback - }); - }; - } - -ShowFactory.$inject = - [ 'Wait', - 'CreateDialog', - '$compile' - ]; diff --git a/awx/ui/client/src/templates/templates.list.js b/awx/ui/client/src/templates/templates.list.js deleted file mode 100644 index e45a1fa5ba95..000000000000 --- a/awx/ui/client/src/templates/templates.list.js +++ /dev/null @@ -1,124 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['i18n', function(i18n) { - return { - - name: 'templates', - iterator: 'template', - basePath: 'unified_job_templates', - selectTitle: i18n._('Template'), - editTitle: i18n._('TEMPLATES'), - listTitle: i18n._('TEMPLATES'), - selectInstructions: i18n.sprintf(i18n._("Click on a row to select it, and click Finished when done. Use the %s button to create a new job template."), " "), - index: false, - hover: true, - - fields: { - name: { - key: true, - label: i18n._('Name'), - columnClass: 'col-lg-2 col-md-2 col-sm-4 col-xs-9', - ngHref: '#/templates/{{template.type}}/{{template.id}}', - awToolTip: '{{template.description | sanitize}}', - dataPlacement: 'top' - }, - type: { - label: i18n._('Type'), - ngBind: 'template.type_label', - columnClass: 'col-lg-2 col-md-2 col-sm-4 hidden-xs' - }, - smart_status: { - label: i18n._('Activity'), - columnClass: 'List-tableCell col-lg-2 col-md-3 hidden-sm hidden-xs', - nosort: true, - ngInclude: "'/static/partials/job-template-smart-status.html'", - type: 'template' - }, - labels: { - label: i18n._('Labels'), - type: 'labels', - nosort: true, - showDelete: true, - columnClass: 'List-tableCell col-lg-2 col-md-3 hidden-sm hidden-xs' - } - }, - - actions: { - add: { - mode: 'all', // One of: edit, select, all - type: 'buttonDropdown', - basePaths: ['templates'], - awToolTip: i18n._('Create a new template'), - actionClass: 'at-Button--add', - actionId: 'button-add', - options: [ - { - optionContent: i18n._('Job Template'), - optionSref: 'templates.addJobTemplate', - ngShow: 'canAddJobTemplate' - }, - { - optionContent: i18n._('Workflow Template'), - optionSref: 'templates.addWorkflowJobTemplate', - ngShow: 'canAddWorkflowJobTemplate' - } - ], - ngShow: 'canAddJobTemplate || canAddWorkflowJobTemplate' - } - }, - - fieldActions: { - - columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-3', - - edit: { - label: i18n._('Edit'), - ngClick: "editJobTemplate(template)", - awToolTip: i18n._('Edit template'), - "class": 'btn-default btn-xs', - dataPlacement: 'top', - ngShow: 'template.summary_fields.user_capabilities.edit', - editStateParams: ['job_template_id', 'workflow_job_template_id'] - }, - submit: { - // The submit key lets the list generator know that we want to use the - // at-launch-template directive - }, - schedule: { - label: i18n._('Schedule'), - mode: 'all', - ngClick: 'scheduleJob(template)', - awToolTip: i18n._('Schedule job template runs'), - dataPlacement: 'top', - }, - copy: { - label: i18n._('Copy'), - ngClick: 'copyTemplate(template)', - "class": 'btn-danger btn-xs', - awToolTip: i18n._('Copy template'), - dataPlacement: 'top', - ngShow: 'template.summary_fields.user_capabilities.copy' - }, - view: { - label: i18n._('View'), - ngClick: "editJobTemplate(template)", - awToolTip: i18n._('View template'), - "class": 'btn-default btn-xs', - dataPlacement: 'top', - ngShow: '!template.summary_fields.user_capabilities.edit' - }, - "delete": { - label: i18n._('Delete'), - ngClick: "deleteJobTemplate(template)", - "class": 'btn-danger btn-xs', - awToolTip: i18n._('Delete template'), - dataPlacement: 'top', - ngShow: 'template.summary_fields.user_capabilities.delete' - } - } - };}]; diff --git a/awx/ui/client/src/templates/templates.service.js b/awx/ui/client/src/templates/templates.service.js deleted file mode 100644 index 1a63cb6553bb..000000000000 --- a/awx/ui/client/src/templates/templates.service.js +++ /dev/null @@ -1,295 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default ['Rest', 'GetBasePath', '$q', 'NextPage', function(Rest, GetBasePath, $q, NextPage){ - return { - deleteJobTemplate: function(id){ - var url = GetBasePath('job_templates'); - - url = url + id; - - Rest.setUrl(url); - return Rest.destroy(); - }, - deleteWorkflowJobTemplate: function(id) { - var url = GetBasePath('workflow_job_templates'); - - url = url + id; - - Rest.setUrl(url); - return Rest.destroy(); - }, - createJobTemplate: function(data){ - var url = GetBasePath('job_templates'); - - Rest.setUrl(url); - return Rest.post(data); - }, - createWorkflowJobTemplate: function(data) { - var url = GetBasePath('workflow_job_templates'); - - Rest.setUrl(url); - return Rest.post(data); - }, - getAllLabelOptions: function() { - Rest.setUrl(GetBasePath('labels') + '?page_size=200'); - return Rest.get() - .then(function(res) { - if (res.data.next) { - return NextPage({ - url: res.data.next, - arrayOfValues: res.data.results - }).then(function(labels) { - return labels; - }).catch(function(response){ - return $q.reject( response ); - }); - } - else { - return $q.resolve( res.data.results ); - } - }).catch(function(response){ - return $q.reject( response ); - }); - }, - getAllJobTemplateLabels: function(id) { - Rest.setUrl(GetBasePath('job_templates') + id + "/labels?page_size=20"); - return Rest.get() - .then(function(res) { - if (res.data.next) { - return NextPage({ - url: res.data.next, - arrayOfValues: res.data.results - }).then(function(labels) { - return labels; - }).catch(function(response){ - return $q.reject( response ); - }); - } - else { - return $q.resolve( res.data.results ); - } - }).catch(function(response){ - return $q.reject( response ); - }); - }, - - getAllWorkflowJobTemplateLabels: function(id) { - Rest.setUrl(GetBasePath('workflow_job_templates') + id + "/labels?page_size=200"); - return Rest.get() - .then(function(res) { - if (res.data.next) { - return NextPage({ - url: res.data.next, - arrayOfValues: res.data.results - }).then(function(labels) { - return labels; - }).catch(function(response){ - return $q.reject( response ); - }); - } - else { - return $q.resolve( res.data.results ); - } - }).catch(function(response){ - return $q.reject( response ); - }); - }, - getJobTemplate: function(id) { - var url = GetBasePath('job_templates'); - - url = url + id; - - Rest.setUrl(url); - return Rest.get(); - }, - addWorkflowNode: function(params) { - // params.url - // params.data - - Rest.setUrl(params.url); - return Rest.post(params.data); - }, - editWorkflowNode: function(params) { - // params.id - // params.data - - var url = GetBasePath('workflow_job_template_nodes') + params.id; - - Rest.setUrl(url); - return Rest.put(params.data); - }, - getJobTemplateLaunchInfo: function(id) { - var url = GetBasePath('job_templates'); - - url = url + id + '/launch'; - - Rest.setUrl(url); - return Rest.get(); - }, - getWorkflowJobTemplateNodes: function(id, page) { - var url = GetBasePath('workflow_job_templates'); - - url = url + id + '/workflow_nodes'; - - if(page) { - url += '/?page=' + page; - } - - Rest.setUrl(url); - return Rest.get(); - }, - updateWorkflowJobTemplate: function(params) { - // params.id - // params.data - - var url = GetBasePath('workflow_job_templates'); - - url = url + params.id; - - Rest.setUrl(url); - return Rest.put(params.data); - }, - getWorkflowJobTemplate: function(id) { - var url = GetBasePath('workflow_job_templates'); - - url = url + id; - - Rest.setUrl(url); - return Rest.get(); - }, - deleteWorkflowJobTemplateNode: function(id) { - var url = GetBasePath('workflow_job_template_nodes') + id; - - Rest.setUrl(url); - return Rest.destroy(); - }, - disassociateWorkflowNode: function(params) { - //params.parentId - //params.nodeId - //params.edge - - var url = GetBasePath('workflow_job_template_nodes') + params.parentId; - - if(params.edge === 'success') { - url = url + '/success_nodes'; - } - else if(params.edge === 'failure') { - url = url + '/failure_nodes'; - } - else if(params.edge === 'always') { - url = url + '/always_nodes'; - } - - Rest.setUrl(url); - return Rest.post({ - "id": params.nodeId, - "disassociate": true - }); - }, - associateWorkflowNode: function(params) { - //params.parentId - //params.nodeId - //params.edge - - var url = GetBasePath('workflow_job_template_nodes') + params.parentId; - - if(params.edge === 'success') { - url = url + '/success_nodes'; - } - else if(params.edge === 'failure') { - url = url + '/failure_nodes'; - } - else if(params.edge === 'always') { - url = url + '/always_nodes'; - } - - Rest.setUrl(url); - return Rest.post({ - id: params.nodeId - }); - }, - getUnifiedJobTemplate: function(id) { - var url = GetBasePath('unified_job_templates'); - - url = url + "?id=" + id; - - Rest.setUrl(url); - return Rest.get(); - }, - getCredential: function(id) { - var url = GetBasePath('credentials'); - - url = url + id; - - Rest.setUrl(url); - return Rest.get(); - }, - getInventory: function(id) { - var url = GetBasePath('inventory'); - - url = url + id; - - Rest.setUrl(url); - return Rest.get(); - }, - getWorkflowCopy: function(id) { - let url = GetBasePath('workflow_job_templates'); - - url = url + id + '/copy'; - - Rest.setUrl(url); - return Rest.get(); - }, - copyWorkflow: function(id) { - let url = GetBasePath('workflow_job_templates'); - - url = url + id + '/copy'; - - Rest.setUrl(url); - return Rest.post(); - }, - getWorkflowJobTemplateOptions: function() { - var deferred = $q.defer(); - - let url = GetBasePath('workflow_job_templates'); - - Rest.setUrl(url); - Rest.options() - .then(({data}) => { - deferred.resolve(data); - }).catch(({msg, code}) => { - deferred.reject(msg, code); - }); - - return deferred.promise; - }, - getJobTemplateOptions: function() { - var deferred = $q.defer(); - - let url = GetBasePath('job_templates'); - - Rest.setUrl(url); - Rest.options() - .then(({data}) => { - deferred.resolve(data); - }).catch(({msg, code}) => { - deferred.reject(msg, code); - }); - - return deferred.promise; - }, - postWorkflowNodeCredential: function(params) { - // params.id - // params.data - - var url = GetBasePath('workflow_job_template_nodes') + params.id + '/credentials'; - - Rest.setUrl(url); - return Rest.post(params.data); - } - }; -}]; diff --git a/awx/ui/client/src/templates/workflows.form.js b/awx/ui/client/src/templates/workflows.form.js deleted file mode 100644 index b484d33c7edd..000000000000 --- a/awx/ui/client/src/templates/workflows.form.js +++ /dev/null @@ -1,240 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name forms.function:Workflow - * @description This form is for adding/editing a Workflow -*/ - -export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) { - return function() { - var WorkflowFormObject = { - - addTitle: i18n._('NEW WORKFLOW JOB TEMPLATE'), - editTitle: '{{ name }}', - name: 'workflow_job_template', - breadcrumbName: i18n._('WORKFLOW'), - base: 'workflow', - basePath: 'workflow_job_templates', - // the top-most node of generated state tree - stateTree: 'templates', - activeEditState: 'templates.editWorkflowJobTemplate', - tabs: true, - detailsClick: "$state.go('templates.editWorkflowJobTemplate')", - include: ['/static/partials/survey-maker-modal.html'], - - headerFields: { - missingTemplates: { - type: 'html', - html: `
- ` + - i18n._("Missing Job Templates found in the Workflow Editor") + - `
` - } - }, - - fields: { - name: { - label: i18n._('Name'), - type: 'text', - required: true, - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)', - column: 1 - }, - description: { - label: i18n._('Description'), - type: 'text', - column: 1, - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - sourceModel: 'organization', - basePath: 'organizations', - list: 'OrganizationList', - sourceField: 'name', - dataTitle: i18n._('Organization'), - dataContainer: 'body', - dataPlacement: 'right', - awRequiredWhen: { - reqExpression: '!current_user.is_superuser' - }, - column: 1, - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate) || !canEditOrg', - awLookupWhen: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate) && canEditOrg' - }, - labels: { - label: i18n._('Labels'), - type: 'select', - ngOptions: 'label.label for label in labelOptions track by label.value', - multiSelect: true, - dataTitle: i18n._('Labels'), - dataPlacement: 'right', - awPopOver: "

" + i18n._("Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.") + "

", - dataContainer: 'body', - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' - }, - variables: { - label: i18n._('Extra Variables'), - type: 'textarea', - class: 'Form-textAreaLabel Form-formGroup--fullWidth', - rows: 6, - "default": "---", - column: 2, - awPopOver:i18n._('Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for example syntax.'), - dataTitle: i18n._('Extra Variables'), - dataPlacement: 'right', - dataContainer: "body", - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' // TODO: get working - }, - checkbox_group: { - label: i18n._('Options'), - type: 'checkbox_group', - fields: [{ - name: 'allow_simultaneous', - label: i18n._('Enable Concurrent Jobs'), - type: 'checkbox', - column: 2, - awPopOver: "

" + i18n._("If enabled, simultaneous runs of this workflow job template will be allowed.") + "

", - dataPlacement: 'right', - dataTitle: i18n._('Enable Concurrent Jobs'), - dataContainer: "body", - labelClass: 'stack-inline', - ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' - }] - } - }, - - buttons: { //for now always generates - - - - - - - -
-
-
{{ workflowJobTemplateObj.name }}
-
-
- -
-
-
-
-
-
- -
    -
  • -

    KEY

    -
  • -
  • -
    -

    On Success

    -
  • -
  • -
    -

    On Fail

    -
  • -
  • -
    -

    Always

    -
  • -
  • -
    P
    -

    Project Sync

    -
  • -
  • -
    I
    -

    Inventory Sync

    -
  • -
  • -
    !
    -

    Warning

    -
  • -
-
-
- TOTAL TEMPLATES - - -
- -
-
-
- -
-
-
{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited) ? ((nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "EDIT TEMPLATE") : "ADD A TEMPLATE"}}
-
-
-
-
JOBS
-
PROJECT SYNC
-
INVENTORY SYNC
-
-
-
-
-
-
-
-
- - {{:: strings.get('workflows.INVALID_JOB_TEMPLATE') }} -
-
-
- -
- -
-
-
- - - - -
-
-
-
-
- - -
- - diff --git a/awx/ui/client/src/templates/workflows/workflow.block.less b/awx/ui/client/src/templates/workflows/workflow.block.less deleted file mode 100644 index 66f3f76ec4b2..000000000000 --- a/awx/ui/client/src/templates/workflows/workflow.block.less +++ /dev/null @@ -1,13 +0,0 @@ -.Workflow-warning { - float: right; - margin-right: 20px; - color: @default-interface-txt; -} -.Workflow-warningIcon { - color: @default-warning; - margin-right: 5px; -} -.Workflow-warningLink { - color: @default-link; - cursor: pointer; -} diff --git a/awx/ui/client/src/templates/workflows/workflow.service.js b/awx/ui/client/src/templates/workflows/workflow.service.js deleted file mode 100644 index fe632a2e1d7f..000000000000 --- a/awx/ui/client/src/templates/workflows/workflow.service.js +++ /dev/null @@ -1,328 +0,0 @@ -export default ['$q', function($q){ - return { - searchTree: function(params) { - // params.element - // params.matchingId - // params.byNodeId - - let prospectiveId = params.byNodeId ? params.element.nodeId : params.element.id; - - if(prospectiveId === params.matchingId){ - return params.element; - }else if (params.element.children && params.element.children.length > 0){ - let result = null; - const thisService = this; - _.forEach(params.element.children, function(child) { - result = thisService.searchTree({ - element: child, - matchingId: params.matchingId, - byNodeId: params.byNodeId ? params.byNodeId : false - }); - if(result) { - return false; - } - }); - return result; - } - return null; - }, - removeNodeFromTree: function(params) { - // params.tree - // params.nodeToBeDeleted - - let parentNode = this.searchTree({ - element: params.tree, - matchingId: params.nodeToBeDeleted.parent.id - }); - let nodeToBeDeleted = this.searchTree({ - element: parentNode, - matchingId: params.nodeToBeDeleted.id - }); - - if(nodeToBeDeleted.children) { - _.forEach(nodeToBeDeleted.children, function(child) { - if(nodeToBeDeleted.isRoot) { - child.isRoot = true; - child.edgeType = "always"; - } - child.parent = parentNode; - parentNode.children.push(child); - }); - } - - _.forEach(parentNode.children, function(child, index) { - if(child.id === params.nodeToBeDeleted.id) { - parentNode.children.splice(index, 1); - return false; - } - }); - }, - addPlaceholderNode: function(params) { - // params.parent - // params.betweenTwoNodes - // params.tree - // params.id - - let placeholder = { - children: [], - c: "#D7D7D7", - id: params.id, - canDelete: true, - canEdit: false, - canAddTo: true, - placeholder: true, - isNew: true, - edited: false, - isRoot: (params.betweenTwoNodes) ? _.get(params, 'parent.source.isStartNode', false) : _.get(params, 'parent.isStartNode', false) - }; - - let parentNode = (params.betweenTwoNodes) ? this.searchTree({element: params.tree, matchingId: params.parent.source.id}) : this.searchTree({element: params.tree, matchingId: params.parent.id}); - let placeholderRef; - - if (params.betweenTwoNodes) { - _.forEach(parentNode.children, function(child, index) { - if (child.id === params.parent.target.id) { - child.isRoot = false; - placeholder.children.push(child); - parentNode.children[index] = placeholder; - placeholderRef = parentNode.children[index]; - child.parent = parentNode.children[index]; - return false; - } - }); - } else { - if (parentNode.children) { - parentNode.children.push(placeholder); - placeholderRef = parentNode.children[parentNode.children.length - 1]; - } else { - parentNode.children = [placeholder]; - placeholderRef = parentNode.children[0]; - } - } - - return placeholderRef; - }, - getSiblingConnectionTypes: function(params) { - // params.parentId - // params.childId - // params.tree - - let siblingConnectionTypes = {}; - - let parentNode = this.searchTree({ - element: params.tree, - matchingId: params.parentId - }); - - if(parentNode.children && parentNode.children.length > 0) { - // Loop across them and add the types as keys to siblingConnectionTypes - _.forEach(parentNode.children, function(child) { - if(child.id !== params.childId && !child.placeholder && child.edgeType) { - siblingConnectionTypes[child.edgeType] = true; - } - }); - } - - return Object.keys(siblingConnectionTypes); - }, - buildTree: function(params) { - //params.workflowNodes - - let deferred = $q.defer(); - - let _this = this; - - let treeData = { - data: { - id: 1, - canDelete: false, - canEdit: false, - canAddTo: true, - isStartNode: true, - unifiedJobTemplate: { - name: "Workflow Launch" - }, - children: [], - deletedNodes: [], - totalNodes: 0 - }, - nextIndex: 2 - }; - - let nodesArray = params.workflowNodes; - let nodesObj = {}; - let nonRootNodeIds = []; - let allNodeIds = []; - - // Determine which nodes are root nodes - _.forEach(nodesArray, function(node) { - nodesObj[node.id] = _.clone(node); - - allNodeIds.push(node.id); - - _.forEach(node.success_nodes, function(nodeId){ - nonRootNodeIds.push(nodeId); - }); - _.forEach(node.failure_nodes, function(nodeId){ - nonRootNodeIds.push(nodeId); - }); - _.forEach(node.always_nodes, function(nodeId){ - nonRootNodeIds.push(nodeId); - }); - }); - - let rootNodes = _.difference(allNodeIds, nonRootNodeIds); - - // Loop across the root nodes and re-build the tree - _.forEach(rootNodes, function(rootNodeId) { - let branch = _this.buildBranch({ - nodeId: rootNodeId, - edgeType: "always", - nodesObj: nodesObj, - isRoot: true, - treeData: treeData - }); - - treeData.data.children.push(branch); - }); - - deferred.resolve(treeData); - - return deferred.promise; - }, - buildBranch: function(params) { - // params.nodeId - // params.parentId - // params.edgeType - // params.nodesObj - // params.isRoot - // params.treeData - - let _this = this; - - let treeNode = { - children: [], - c: "#D7D7D7", - id: params.treeData.nextIndex, - nodeId: params.nodeId, - canDelete: true, - canEdit: true, - canAddTo: true, - placeholder: false, - edgeType: params.edgeType, - isNew: false, - edited: false, - originalEdge: params.edgeType, - originalNodeObj: _.clone(params.nodesObj[params.nodeId]), - promptValues: {}, - isRoot: params.isRoot ? params.isRoot : false - }; - - params.treeData.data.totalNodes++; - - params.treeData.nextIndex++; - - if(params.parentId) { - treeNode.originalParentId = params.parentId; - } - - if(params.nodesObj[params.nodeId].summary_fields) { - if(params.nodesObj[params.nodeId].summary_fields.job) { - treeNode.job = _.clone(params.nodesObj[params.nodeId].summary_fields.job); - } - - if(params.nodesObj[params.nodeId].summary_fields.unified_job_template) { - treeNode.unifiedJobTemplate = _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template); - } - } - - // Loop across the success nodes and add them recursively - _.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) { - treeNode.children.push(_this.buildBranch({ - nodeId: successNodeId, - parentId: params.nodeId, - edgeType: "success", - nodesObj: params.nodesObj, - treeData: params.treeData - })); - }); - - // failure nodes - _.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) { - treeNode.children.push(_this.buildBranch({ - nodeId: failureNodesId, - parentId: params.nodeId, - edgeType: "failure", - nodesObj: params.nodesObj, - treeData: params.treeData - })); - }); - - // always nodes - _.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) { - treeNode.children.push(_this.buildBranch({ - nodeId: alwaysNodesId, - parentId: params.nodeId, - edgeType: "always", - nodesObj: params.nodesObj, - treeData: params.treeData - })); - }); - - return treeNode; - }, - updateStatusOfNode: function(params) { - // params.treeData - // params.nodeId - // params.status - - let matchingNode = this.searchTree({ - element: params.treeData.data, - matchingId: params.nodeId, - byNodeId: true - }); - - if(matchingNode) { - matchingNode.job = { - status: params.status, - id: params.unified_job_id - }; - } - - }, - checkForEdgeConflicts: function(params) { - //params.treeData - //params.edgeFlags - - let hasAlways = false; - let hasSuccessFailure = false; - let _this = this; - - _.forEach(params.treeData.children, function(child) { - // Flip the flag to false for now - we'll set it to true later on - // if we detect a conflict - child.edgeConflict = false; - if(child.edgeType === 'always') { - hasAlways = true; - } - else if(child.edgeType === 'success' || child.edgeType === 'failure') { - hasSuccessFailure = true; - } - - _this.checkForEdgeConflicts({ - treeData: child, - edgeFlags: params.edgeFlags - }); - }); - - if(hasAlways && hasSuccessFailure) { - // We have a conflict - _.forEach(params.treeData.children, function(child) { - child.edgeConflict = true; - }); - - params.edgeFlags.conflict = true; - } - } - }; -}]; diff --git a/awx/ui/client/src/tooltip/tooltip.block.less b/awx/ui/client/src/tooltip/tooltip.block.less deleted file mode 100644 index bfc3cea87158..000000000000 --- a/awx/ui/client/src/tooltip/tooltip.block.less +++ /dev/null @@ -1,82 +0,0 @@ -/** @define Tooltip */ -.tooltip.bottom .tooltip-arrow { - border-bottom-color: @default-interface-txt; -} - -.tooltip.top .tooltip-arrow { - border-top-color: @default-interface-txt; -} - -.tooltip.left .tooltip-arrow { - border-left-color: @default-interface-txt; -} - -.tooltip.right .tooltip-arrow { - border-right-color: @default-interface-txt; -} - -.tooltip.Tooltip.fade.bottom.in { - opacity: 1; - padding-top: 4px; -} - -.tooltip.in { - opacity: 1; -} - -.tooltip-inner { - background-color: @default-interface-txt; -} - -.tooltip-inner--logOut { - margin-left: -15px !important; -} - -.tooltip { - z-index: 2050; - opacity: 1.0; -} - -.tooltip-inner { - padding: 10px; - text-align:left; - max-width: 150px; -} - -.Tooltip-inner { - white-space: pre-wrap; - word-break: break-word; -} -.Tooltip-wide { - max-width: 300px!important; -} - -.Tooltip-secondary { - .Tooltip-inner { - background-color: @default-icon; - } -} - -.Tooltip-secondary.top { - .Tooltip-arrow { - border-top-color: @default-icon; - } -} - -.Tooltip-secondary.bottom { - .Tooltip-arrow { - border-bottom-color: @default-icon; - } -} - -.Tooltip-secondary.left { - .Tooltip-arrow { - border-left-color: @default-icon; - } -} - -.Tooltip-secondary.right { - .Tooltip-arrow { - border-right-color: @default-icon; - } -} diff --git a/awx/ui/client/src/users/add/users-add.controller.js b/awx/ui/client/src/users/add/users-add.controller.js deleted file mode 100644 index c822b7bf9dee..000000000000 --- a/awx/ui/client/src/users/add/users-add.controller.js +++ /dev/null @@ -1,119 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import { N_ } from "../../i18n"; - -const user_type_options = [ - { type: 'normal', label: N_('Normal User') }, - { type: 'system_auditor', label: N_('System Auditor') }, - { type: 'system_administrator', label: N_('System Administrator') }, -]; - -export default ['$scope', '$rootScope', 'UserForm', 'GenerateForm', 'Rest', - 'Alert', 'ProcessErrors', 'ReturnToCaller', 'GetBasePath', - 'Wait', 'CreateSelect2', '$state', '$location', 'i18n', - function($scope, $rootScope, UserForm, GenerateForm, Rest, Alert, - ProcessErrors, ReturnToCaller, GetBasePath, Wait, CreateSelect2, - $state, $location, i18n) { - - var defaultUrl = GetBasePath('organizations'), - form = UserForm; - - init(); - - function init() { - // apply form definition's default field values - GenerateForm.applyDefaults(form, $scope); - - $scope.isAddForm = true; - $scope.ldap_user = false; - $scope.not_ldap_user = !$scope.ldap_user; - $scope.ldap_dn = null; - $scope.socialAuthUser = false; - $scope.external_account = null; - - Rest.setUrl(GetBasePath('users')); - Rest.options() - .then(({data}) => { - if (!data.actions.POST) { - $state.go("^"); - Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a user.'), 'alert-info'); - } - }); - - $scope.user_type_options = user_type_options; - $scope.user_type = user_type_options[0]; - $scope.$watch('user_type', user_type_sync($scope)); - CreateSelect2({ - element: '#user_user_type', - multiple: false - }); - } - - function user_type_sync($scope) { - return (type_option) => { - $scope.is_superuser = false; - $scope.is_system_auditor = false; - switch (type_option.type) { - case 'system_administrator': - $scope.is_superuser = true; - break; - case 'system_auditor': - $scope.is_system_auditor = true; - break; - } - }; - } - - // Save - $scope.formSave = function() { - var fld, data = {}; - if ($scope[form.name + '_form'].$valid) { - if ($scope.organization !== undefined && $scope.organization !== null && $scope.organization !== '') { - Rest.setUrl(defaultUrl + $scope.organization + '/users/'); - for (fld in form.fields) { - if (form.fields[fld].realName) { - data[form.fields[fld].realName] = $scope[fld]; - } else { - data[fld] = $scope[fld]; - } - } - data.is_superuser = $scope.is_superuser; - data.is_system_auditor = $scope.is_system_auditor; - Wait('start'); - Rest.post(data) - .then(({data}) => { - var base = $location.path().replace(/^\//, '').split('/')[0]; - if (base === 'users') { - $rootScope.flashMessage = i18n._('New user successfully created!'); - $rootScope.$broadcast("EditIndicatorChange", "users", data.id); - $state.go('users.edit', { user_id: data.id }, { reload: true }); - } else { - ReturnToCaller(1); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n._('Failed to add new user. POST returned status: ') + status }); - }); - } else { - $scope.organization_name_api_error = i18n._('A value is required'); - } - } - }; - - $scope.formCancel = function() { - $state.go('users'); - }; - - // Password change - $scope.clearPWConfirm = function() { - // If password value changes, make sure password_confirm must be re-entered - $scope.password_confirm = ''; - let passValidity = (!$scope.password || $scope.password === '') ? true : false; - $scope[form.name + '_form'].password_confirm.$setValidity('awpassmatch', passValidity); - }; - } -]; diff --git a/awx/ui/client/src/users/edit/users-edit.controller.js b/awx/ui/client/src/users/edit/users-edit.controller.js deleted file mode 100644 index f2294a17031b..000000000000 --- a/awx/ui/client/src/users/edit/users-edit.controller.js +++ /dev/null @@ -1,200 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import { N_ } from "../../i18n"; - -const user_type_options = [ - { type: 'normal', label: N_('Normal User') }, - { type: 'system_auditor', label: N_('System Auditor') }, - { type: 'system_administrator', label: N_('System Administrator') }, -]; - -export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'Rest', - 'ProcessErrors', 'GetBasePath', 'Wait', 'CreateSelect2', - '$state', 'i18n', 'resolvedModels', - function($scope, $rootScope, $stateParams, UserForm, Rest, ProcessErrors, - GetBasePath, Wait, CreateSelect2, $state, i18n, models) { - - for (var i = 0; i < user_type_options.length; i++) { - user_type_options[i].label = i18n._(user_type_options[i].label); - } - - const { me } = models; - var form = UserForm, - master = {}, - id = $stateParams.user_id, - defaultUrl = GetBasePath('users') + id; - - init(); - - function init() { - $scope.canEdit = me.get('summary_fields.user_capabilities.edit'); - $scope.isOrgAdmin = me.get('related.admin_of_organizations.count') > 0; - $scope.isCurrentlyLoggedInUser = (parseInt(id) === $rootScope.current_user.id); - $scope.hidePagination = false; - $scope.hideSmartSearch = false; - $scope.user_type_options = user_type_options; - $scope.user_type = user_type_options[0]; - $scope.$watch('user_type', user_type_sync($scope)); - $scope.$watch('is_superuser', hidePermissionsTabSmartSearchAndPaginationIfSuperUser($scope)); - Rest.setUrl(defaultUrl); - Wait('start'); - Rest.get(defaultUrl).then(({data}) => { - $scope.user_id = id; - $scope.ldap_user = (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') ? true : false; - $scope.not_ldap_user = !$scope.ldap_user; - master.ldap_user = $scope.ldap_user; - $scope.socialAuthUser = (data.auth.length > 0) ? true : false; - $scope.external_account = data.external_account; - - $scope.user_type = $scope.user_type_options[0]; - $scope.is_system_auditor = false; - $scope.is_superuser = false; - if (data.is_system_auditor) { - $scope.user_type = $scope.user_type_options[1]; - $scope.is_system_auditor = true; - } - if (data.is_superuser) { - $scope.user_type = $scope.user_type_options[2]; - $scope.is_superuser = true; - } - - $scope.user_obj = data; - $scope.name = data.username; - - CreateSelect2({ - element: '#user_user_type', - multiple: false - }); - - $scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) { - $scope.canAdd = (val === false) ? false : true; - }); - - setScopeFields(data); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status - }); - }); - } - - function user_type_sync($scope) { - return (type_option) => { - $scope.is_superuser = false; - $scope.is_system_auditor = false; - switch (type_option.type) { - case 'system_administrator': - $scope.is_superuser = true; - break; - case 'system_auditor': - $scope.is_system_auditor = true; - break; - } - }; - } - - // Organizations and Teams tab pagination is hidden through other mechanism - function hidePermissionsTabSmartSearchAndPaginationIfSuperUser(scope) { - return function(isSuperuserNewValue) { - let shouldHide = isSuperuserNewValue; - if (shouldHide === true) { - scope.hidePagination = true; - scope.hideSmartSearch = true; - } else if (shouldHide === false) { - scope.hidePagination = false; - scope.hideSmartSearch = false; - } - }; - } - - - function setScopeFields(data) { - _(data) - .pick(function(value, key) { - return form.fields.hasOwnProperty(key) === true; - }) - .forEach(function(value, key) { - $scope[key] = value; - }) - .value(); - return; - } - - $scope.redirectToResource = function(resource) { - let type = resource.summary_fields.resource_type.replace(/ /g , "_"); - var id = resource.related[type].split("/")[4]; - switch (type) { - case 'organization': - $state.go('organizations.edit', { "organization_id": id }, { reload: true }); - break; - case 'team': - $state.go('teams.edit', { "team_id": id }, { reload: true }); - break; - case 'credential': - $state.go('credentials.edit', { "credential_id": id }, { reload: true }); - break; - case 'project': - $state.go('projects.edit', { "project_id": id }, { reload: true }); - break; - case 'inventory': - $state.go('inventories.edit', { "inventory_id": id }, { reload: true }); - break; - case 'job_template': - $state.go('templates.editJobTemplate', { "job_template_id": id }, { reload: true }); - break; - case 'workflow_job_template': - $state.go('templates.editWorkflowJobTemplate', { "workflow_job_template_id": id }, { reload: true }); - break; - } - }; - - // prepares a data payload for a PUT request to the API - var processNewData = function(fields) { - var data = {}; - _.forEach(fields, function(value, key) { - if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) { - data[key] = $scope[key]; - } - }); - data.is_superuser = $scope.is_superuser; - data.is_system_auditor = $scope.is_system_auditor; - return data; - }; - - $scope.formCancel = function() { - $state.go('users', null, { reload: true }); - }; - - $scope.formSave = function() { - $rootScope.flashMessage = null; - if ($scope[form.name + '_form'].$valid) { - Rest.setUrl(defaultUrl + '/'); - var data = processNewData(form.fields); - Rest.put(data).then(() => { - $state.go($state.current, null, { reload: true }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status - }); - }); - } - }; - - $scope.clearPWConfirm = function() { - // If password value changes, make sure password_confirm must be re-entered - $scope.password_confirm = ''; - let passValidity = (!$scope.password || $scope.password === '') ? true : false; - $scope[form.name + '_form'].password_confirm.$setValidity('awpassmatch', passValidity); - $rootScope.flashMessage = null; - }; - } -]; diff --git a/awx/ui/client/src/users/list/users-list.controller.js b/awx/ui/client/src/users/list/users-list.controller.js deleted file mode 100644 index b684a5bbdbcc..000000000000 --- a/awx/ui/client/src/users/list/users-list.controller.js +++ /dev/null @@ -1,99 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import { N_ } from "../../i18n"; - -const user_type_options = [ - { type: 'normal', label: N_('Normal User') }, - { type: 'system_auditor', label: N_('System Auditor') }, - { type: 'system_administrator', label: N_('System Administrator') }, -]; - -export default ['$scope', '$rootScope', 'Rest', 'UserList', 'Prompt', - 'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', - 'rbacUiControlService', 'Dataset', 'i18n', 'resolvedModels', - function($scope, $rootScope, Rest, UserList, Prompt, - ProcessErrors, GetBasePath, Wait, $state, $filter, rbacUiControlService, - Dataset, i18n, models) { - - for (var i = 0; i < user_type_options.length; i++) { - user_type_options[i].label = i18n._(user_type_options[i].label); - } - - const { me } = models; - var list = UserList, - defaultUrl = GetBasePath('users'); - - init(); - - function init() { - $scope.canEdit = me.get('summary_fields.user_capabilities.edit'); - $scope.canAdd = false; - - rbacUiControlService.canAdd('users') - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - - $rootScope.flashMessage = null; - $scope.selected = []; - } - - $scope.addUser = function() { - $state.go('users.add'); - }; - - $scope.editUser = function(id) { - $state.go('users.edit', { user_id: id }); - }; - - $scope.deleteUser = function(id, name) { - - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() - .then(() => { - - let reloadListStateParams = null; - - if($scope.users.length === 1 && $state.params.user_search && !_.isEmpty($state.params.user_search.page) && $state.params.user_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.user_search.page = (parseInt(reloadListStateParams.user_search.page)-1).toString(); - } - - if (parseInt($state.params.user_id) === id) { - $state.go('^', null, { reload: true }); - } else { - $state.go('.', null, { reload: true }); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status - }); - }); - }; - - Prompt({ - hdr: i18n._('Delete'), - resourceName: $filter('sanitize')(name), - body: '
' + i18n._('Are you sure you want to delete this user?') + '
', - action: action, - actionText: i18n._('DELETE') - }); - }; - } -]; diff --git a/awx/ui/client/src/users/main.js b/awx/ui/client/src/users/main.js deleted file mode 100644 index 3701d4f626a3..000000000000 --- a/awx/ui/client/src/users/main.js +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import UsersList from './list/users-list.controller'; -import UsersAdd from './add/users-add.controller'; -import UsersEdit from './edit/users-edit.controller'; -import UserForm from './users.form'; -import UserList from './users.list'; - -import UserTokensListRoute from '../../features/users/tokens/users-tokens-list.route'; -import UserTokensAddRoute from '../../features/users/tokens/users-tokens-add.route'; -import UserTokensAddApplicationRoute from '../../features/users/tokens/users-tokens-add-application.route'; - -import { N_ } from '../i18n'; - -export default -angular.module('Users', []) - .controller('UsersList', UsersList) - .controller('UsersAdd', UsersAdd) - .controller('UsersEdit', UsersEdit) - .factory('UserForm', UserForm) - .factory('UserList', UserList) - .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', - function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { - let stateDefinitions = stateDefinitionsProvider.$get(); - let stateExtender = $stateExtenderProvider.$get(); - - function generateStateTree() { - let userTree = stateDefinitions.generateTree({ - parent: 'users', - modes: ['add', 'edit'], - list: 'UserList', - form: 'UserForm', - controllers: { - list: UsersList, - add: UsersAdd, - edit: UsersEdit - }, - data: { - activityStream: true, - activityStreamTarget: 'user' - }, - resolve: { - edit: { - resolvedModels: ['MeModel', '$q', function(Me, $q) { - const promises= { - me: new Me('get').then((me) => me.extend('get', 'admin_of_organizations')) - }; - - return $q.all(promises); - }] - }, - list: { - resolvedModels: ['MeModel', '$q', function(Me, $q) { - const promises= { - me: new Me('get') - }; - - return $q.all(promises); - }] - } - }, - ncyBreadcrumb: { - label: N_('USERS') - } - }); - - return Promise.all([ - userTree - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(UserTokensListRoute), - stateExtender.buildDefinition(UserTokensAddRoute), - stateExtender.buildDefinition(UserTokensAddApplicationRoute) - ]) - }; - }); - } - - $stateProvider.state({ - name: 'users.**', - url: '/users', - lazyLoad: () => generateStateTree() - }); - - } - ]); diff --git a/awx/ui/client/src/users/users.form.js b/awx/ui/client/src/users/users.form.js deleted file mode 100644 index 0ffc63151b89..000000000000 --- a/awx/ui/client/src/users/users.form.js +++ /dev/null @@ -1,241 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name forms.function:Users - * @description This form is for adding/editing users -*/ - -export default ['i18n', function(i18n) { - return { - - addTitle: i18n._('NEW USER'), - editTitle: '{{ username }}', - name: 'user', - // the top-most node of generated state tree - stateTree: 'users', - forceListeners: true, - tabs: true, - messageBar: { - ngShow: 'isOrgAdmin && !canEdit', - message: i18n._("Contact your System Administrator to grant you the appropriate permissions to add and edit Users and Teams.") - }, - fields: { - first_name: { - label: i18n._('First Name'), - type: 'text', - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: true - }, - last_name: { - label: i18n._('Last Name'), - type: 'text', - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - capitalize: true - }, - organization: { - label: i18n._('Organization'), - type: 'lookup', - list: 'OrganizationList', - basePath: 'organizations', - sourceModel: 'organization', - sourceField: 'name', - required: true, - excludeMode: 'edit', - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - email: { - label: i18n._('Email'), - type: 'email', - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)', - required: true, - autocomplete: false - }, - username: { - label: i18n._('Username'), - type: 'text', - awRequiredWhen: { - reqExpression: "not_ldap_user && external_account === null", - init: true - }, - autocomplete: false, - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - password: { - label: i18n._('Password'), - type: 'sensitive', - hasShowInputButton: true, - ngShow: 'ldap_user == false && socialAuthUser === false && external_account === null', - awRequiredWhen: { - reqExpression: "isAddForm", - init: false - }, - ngChange: "clearPWConfirm()", - autocomplete: false, - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - password_confirm: { - label: i18n._('Confirm Password'), - type: 'sensitive', - hasShowInputButton: true, - ngShow: 'ldap_user == false && socialAuthUser === false && external_account === null', - awRequiredWhen: { - reqExpression: "isAddForm", - init: false - }, - awPassMatch: true, - associated: 'password', - autocomplete: false, - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - user_type: { - label: i18n._('User Type'), - type: 'select', - ngOptions: 'item as item.label for item in user_type_options track by item.type', - disableChooseOption: true, - ngModel: 'user_type', - ngShow: 'current_user["is_superuser"]', - ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - }, - - buttons: { - cancel: { - ngClick: 'formCancel()', - ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - close: { - ngClick: 'formCancel()', - ngShow: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)' - }, - save: { - ngClick: 'formSave()', - ngDisabled: true, - ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)' - } - }, - - related: { - organizations: { - name: 'organizations', - awToolTip: i18n._('Please save before assigning to organizations.'), - basePath: 'api/v2/users/{{$stateParams.user_id}}/organizations', - emptyListText: i18n._('Please add user to an Organization.'), - search: { - page_size: '10' - }, - dataPlacement: 'top', - type: 'collection', - title: i18n._('Organizations'), - iterator: 'organization', - index: false, - open: false, - - actions: {}, - - fields: { - name: { - key: true, - label: i18n._('Name') - }, - description: { - label: i18n._('Description') - } - }, - //hideOnSuperuser: true // RBAC defunct - }, - teams: { - name: 'teams', - awToolTip: i18n._('Please save before assigning to teams.'), - basePath: 'api/v2/users/{{$stateParams.user_id}}/teams', - search: { - page_size: '10' - }, - dataPlacement: 'top', - type: 'collection', - title: i18n._('Teams'), - iterator: 'team', - open: false, - index: false, - actions: {}, - emptyListText: i18n._('This user is not a member of any teams'), - fields: { - name: { - key: true, - label: i18n._('Name') - }, - description: { - label: i18n._('Description') - } - }, - //hideOnSuperuser: true // RBAC defunct - }, - permissions: { - name: 'permissions', - basePath: 'api/v2/users/{{$stateParams.user_id}}/roles/', - search: { - page_size: '10', - order_by: 'id' - }, - awToolTip: i18n._('Please save before assigning to organizations.'), - dataPlacement: 'top', - hideSearchAndActions: true, - type: 'collection', - title: i18n._('Permissions'), - iterator: 'permission', - open: false, - index: false, - emptyListText: i18n._('No permissions have been granted'), - fields: { - name: { - label: i18n._('Name'), - ngBind: 'permission.summary_fields.resource_name', - ngClick: "redirectToResource(permission)", - nosort: true - }, - type: { - label: i18n._('Type'), - ngBind: 'permission.summary_fields.resource_type_display_name', - nosort: true - }, - role: { - label: i18n._('Role'), - ngBind: 'permission.name', - nosort: true - }, - }, - actions: { - add: { - ngClick: "$state.go('.add')", - label: 'Add', - awToolTip: i18n._('Grant Permission'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: '(!is_superuser && (user_obj.summary_fields.user_capabilities.edit || canAdd))' - } - }, - fieldActions: { - "delete": { - label: i18n._('Remove'), - ngClick: 'deletePermissionFromUser(user_id, username, permission.name, permission.summary_fields.resource_name, permission.related.users)', - iconClass: 'fa fa-times', - awToolTip: i18n._('Dissasociate permission from user'), - ngShow: 'permission.summary_fields.user_capabilities.unattach' - } - }, - //hideOnSuperuser: true // RBAC defunct - }, - tokens: { - ngIf: 'isCurrentlyLoggedInUser', - title: i18n._('Tokens'), - skipGenerator: true, - } - } - - };}]; diff --git a/awx/ui/client/src/users/users.list.js b/awx/ui/client/src/users/users.list.js deleted file mode 100644 index 4bedeb44b820..000000000000 --- a/awx/ui/client/src/users/users.list.js +++ /dev/null @@ -1,88 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - -export default ['i18n', function(i18n) { - return { - - name: 'users', - stateTree: 'users', - search: { - order_by: 'username' - }, - iterator: 'user', - selectTitle: i18n._('Add Users'), - editTitle: i18n._('USERS'), - listTitle: i18n._('USERS'), - selectInstructions: '

Select existing users by clicking each user or checking the related checkbox. When finished, click the blue ' + - 'Select button, located bottom right.

When available, a brand new user can be created by clicking the ' + - ' button.

', - index: false, - hover: true, - - fields: { - username: { - key: true, - label: i18n._('Username'), - columnClass: 'col-md-3 col-sm-3 col-xs-9' - }, - first_name: { - label: i18n._('First Name'), - columnClass: 'col-md-3 col-sm-3 hidden-xs' - }, - last_name: { - label: i18n._('Last Name'), - columnClass: 'col-md-3 col-sm-3 hidden-xs' - } - }, - - actions: { - add: { - label: i18n._('Create New'), - mode: 'all', // One of: edit, select, all - ngClick: 'addUser()', - basePaths: ['organizations', 'users'], // base path must be in list, or action not available - awToolTip: i18n._('Create a new user'), - actionClass: 'at-Button--add', - actionId: 'button-add', - ngShow: 'canAdd && canEdit' - } - }, - - fieldActions: { - - columnClass: 'col-md-3 col-sm-3 col-xs-3', - - edit: { - label: i18n._('Edit'), - ngClick: "editUser(user.id)", - icon: 'icon-edit', - "class": 'btn-xs btn-default', - awToolTip: i18n._('Edit user'), - dataPlacement: 'top', - ngShow: 'user.summary_fields.user_capabilities.edit' - }, - - view: { - label: i18n._('View'), - ngClick: "editUser(user.id)", - "class": 'btn-xs btn-default', - awToolTip: i18n._('View user'), - dataPlacement: 'top', - ngShow: '!user.summary_fields.user_capabilities.edit' - }, - - "delete": { - label: i18n._('Delete'), - ngClick: "deleteUser(user.id, user.username)", - icon: 'icon-trash', - "class": 'btn-xs btn-danger', - awToolTip: i18n._('Delete user'), - dataPlacement: 'top', - ngShow: 'user.summary_fields.user_capabilities.delete' - } - } - };}]; diff --git a/awx/ui/client/src/vendor.js b/awx/ui/client/src/vendor.js deleted file mode 100644 index c4263249f165..000000000000 --- a/awx/ui/client/src/vendor.js +++ /dev/null @@ -1,73 +0,0 @@ -// Theme -require('~assets/custom-theme/jquery-ui-1.10.3.custom.min.css'); -require('~assets/ansible-bootstrap.min.css'); -require('~assets/fontcustom/fontcustom.css'); -require('~node_modules/components-font-awesome/css/font-awesome.min.css'); -require('~node_modules/select2/dist/css/select2.css'); -require('~node_modules/codemirror/lib/codemirror.css'); -require('~node_modules/codemirror/theme/elegant.css'); -require('~node_modules/codemirror/addon/lint/lint.css'); -require('~node_modules/nvd3/build/nv.d3.css'); -require('~node_modules/ng-toast/dist/ngToast.min.css'); - -// jQuery + extensions -global.jQuery = require('jquery'); - -global.jquery = global.jQuery; -global.$ = global.jQuery; - -require('jquery-resize'); -require('jquery-ui'); -require('jquery-ui/ui/widgets/button'); -require('jquery-ui/ui/widgets/dialog'); -require('jquery-ui/ui/widgets/slider'); -require('jquery-ui/ui/widgets/spinner'); -require('bootstrap'); -require('bootstrap-datepicker'); - -// jquery-ui and bootstrap both define $.fn.button -// the code below resolves that namespace clash -const btn = $.fn.button.noConflict(); -$.fn.btn = btn; - -require('select2'); - -// Standalone libs -global._ = require('lodash'); -require('moment'); -require('rrule'); -require('sprintf-js'); -require('reconnectingwebsocket'); - -// D3 + extensions -require('d3'); -require('nvd3'); - -// Angular -require('angular'); -require('angular-cookies'); -require('angular-sanitize'); -require('angular-breadcrumb'); -require('angular-codemirror'); -require('angular-drag-and-drop-lists'); -require('angular-duration-format'); -require('angular-gettext'); -require('angular-md5'); -require('angular-moment'); -require('angular-scheduler'); -require('angular-tz-extensions'); -require('@uirouter/angularjs'); -require('ng-toast-provider'); -require('ng-toast-directives'); -require('ng-toast'); -require('lr-infinite-scroll'); -require('codemirror/mode/yaml/yaml'); -require('codemirror/mode/javascript/javascript'); - -// Network Visualization -require('angular-mousewheel'); -require('angular-xeditable'); -require('hamsterjs'); -require('titlecase'); -require('inherits'); -require('mathjs'); diff --git a/awx/ui/client/src/workflow-results/main.js b/awx/ui/client/src/workflow-results/main.js deleted file mode 100644 index f01c60ccafc1..000000000000 --- a/awx/ui/client/src/workflow-results/main.js +++ /dev/null @@ -1,18 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import workflowStatusBar from './workflow-status-bar/main'; -import route from './workflow-results.route.js'; -import workflowResultsService from './workflow-results.service'; -import controller from './workflow-results.controller'; - -export default - angular.module('workflowResults', [workflowStatusBar.name]) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route); - }]) - .controller('workflowResultsController', controller) - .service('workflowResultsService', workflowResultsService); diff --git a/awx/ui/client/src/workflow-results/standard-out.block.less b/awx/ui/client/src/workflow-results/standard-out.block.less deleted file mode 100644 index c5fad72826b1..000000000000 --- a/awx/ui/client/src/workflow-results/standard-out.block.less +++ /dev/null @@ -1,46 +0,0 @@ -/** @define StandardOut */ - -@breakpoint-md: 1180px; - -.StandardOut-panelHeader { - .OnePlusOne-panelHeader -} - -.StandardOut-panelHeaderText { - align-items: center; - flex: 1 0 auto; - display: flex; -} - -.StandardOut-panelHeaderActions { - justify-content: flex-end; - margin-left: 10px; - font-size: 12px; -} - -.StandardOut-actionButton { - font-size: 16px; - height: 20px; - min-width: 30px; - color: @list-action-icon; - background-color: inherit; - border: none; -} - -.StandardOut-actionButton:hover { - background-color: @list-actn-bg-hov; - color: @list-actn-icn-hov; -} - -.StandardOut-actionButton--active { - background-color: @list-actn-bg-hov; - color: @list-actn-icn-hov; - - &:hover { - background-color: @default-link-hov; - } -} - -.StandardOut-actionButton + a { - margin-left: 15px; -} diff --git a/awx/ui/client/src/workflow-results/workflow-results.block.less b/awx/ui/client/src/workflow-results/workflow-results.block.less deleted file mode 100644 index 53a98f4db51e..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-results.block.less +++ /dev/null @@ -1,142 +0,0 @@ -@breakpoint-md: 1200px; -@breakpoint-sm: 700px; - -.WorkflowResults { - .OnePlusTwo-container(100%, @breakpoint-md); - - &.fullscreen { - .WorkflowResults-rightSide { - max-width: 100%; - } - } -} - -.WorkflowResults-leftSide { - .OnePlusTwo-left--panel(100%, @breakpoint-md); - height: ~"calc(100vh - 177px)"; - min-height: 350px; - - .Panel { - overflow: scroll; - } -} - -.WorkflowResults-rightSide { - .OnePlusTwo-right--panel(100%, @breakpoint-md); - height: ~"calc(100vh - 177px)"; - min-height: 350px; - - @media (max-width: @breakpoint-md - 1px) { - padding-right: 15px; - } -} - -@media (max-width: @breakpoint-md) { - .WorkflowResults-rightSide { - height: inherit; - } -} - -.WorkflowResults-stdoutActionButton--active { - display: none; - visibility: hidden; - flex:none; - width:0px; - padding-right: 0px; -} - -.WorkflowResults-panelHeader { - display: flex; - height: 30px; -} - -.WorkflowResults-panelHeaderText { - color: @default-interface-txt; - flex: 1 0 auto; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - text-transform: uppercase; -} - -.WorkflowResults-resultRow { - width: 100%; - display: flex; - padding-bottom: 10px; - flex-wrap: wrap; -} - -.WorkflowResults-resultRow--variables { - flex-direction: column; -} - -.WorkflowResults-resultRowLabel { - text-transform: uppercase; - color: @default-interface-txt; - font-size: 14px; - font-weight: normal!important; - width: 30%; - margin-right: 20px; - - @media screen and (max-width: @breakpoint-md) { - flex: 2.5 0 auto; - } -} - -.WorkflowResults-resultRowLabel--fullWidth { - width: 100%; - margin-right: 0px; -} - -.WorkflowResults-resultRowText { - width: ~"calc(70% - 20px)"; - flex: 1 0 auto; - text-transform: none; - word-wrap: break-word; -} - -.WorkflowResults-resultRowText--fullWidth { - width: 100%; -} - -.WorkflowResults-statusResultIcon { - padding-left: 0px; - padding-right: 10px; -} - -.WorkflowResults-panelRightTitle{ - flex-wrap: wrap; -} - -.WorkflowResults-panelRightTitleText{ - word-wrap: break-word; - word-break: break-all; - max-width: 100%; -} - -.WorkflowResults-badgeAndActionRow{ - display:flex; - flex: 1 0 auto; - justify-content: flex-end; - flex-wrap: wrap; - max-width: 100%; -} - -.WorkflowResults-badgeRow { - display: flex; - align-items: center; - margin-right: 5px; -} - -.WorkflowResults-badgeTitle{ - color: @default-interface-txt; - font-size: 14px; - margin-right: 10px; - font-weight: normal; - text-transform: uppercase; - margin-left: 20px; -} - -.WorkflowResults-extraVarsLabel { - font-size:14px!important; -} diff --git a/awx/ui/client/src/workflow-results/workflow-results.controller.js b/awx/ui/client/src/workflow-results/workflow-results.controller.js deleted file mode 100644 index 23e2fe726987..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-results.controller.js +++ /dev/null @@ -1,232 +0,0 @@ -export default ['workflowData', 'workflowResultsService', 'workflowDataOptions', - 'jobLabels', 'workflowNodes', '$scope', 'ParseTypeChange', - 'ParseVariableString', 'WorkflowService', 'count', '$state', 'i18n', - 'moment', function(workflowData, workflowResultsService, - workflowDataOptions, jobLabels, workflowNodes, $scope, ParseTypeChange, - ParseVariableString, WorkflowService, count, $state, i18n, moment) { - var runTimeElapsedTimer = null; - - var getLinks = function() { - var getLink = function(key) { - if(key === 'schedule') { - if($scope.workflow.related.schedule) { - return '/#/templates/workflow_job_template/' + $scope.workflow.workflow_job_template + '/schedules' + $scope.workflow.related.schedule.split(/api\/v\d+\/schedules/)[1]; - } - else { - return null; - } - } - else { - if ($scope.workflow.related[key]) { - return '/#/' + $scope.workflow.related[key] - .split(/api\/v\d+\//)[1]; - } else { - return null; - } - } - }; - - $scope.workflow_template_link = '/#/templates/workflow_job_template/'+$scope.workflow.workflow_job_template; - $scope.created_by_link = getLink('created_by'); - $scope.scheduled_by_link = getLink('schedule'); - $scope.cloud_credential_link = getLink('cloud_credential'); - $scope.network_credential_link = getLink('network_credential'); - }; - - var getLabels = function() { - var getLabel = function(key) { - if ($scope.workflowOptions && $scope.workflowOptions[key]) { - return $scope.workflowOptions[key].choices - .filter(val => val[0] === $scope.workflow[key]) - .map(val => val[1])[0]; - } else { - return null; - } - }; - - $scope.status_label = getLabel('status'); - $scope.type_label = getLabel('job_type'); - $scope.verbosity_label = getLabel('verbosity'); - }; - - var updateWorkflowJobElapsedTimer = function(time) { - $scope.workflow.elapsed = time; - }; - - function init() { - // put initially resolved request data on scope - $scope.workflow = workflowData; - $scope.workflow_nodes = workflowNodes; - $scope.workflowOptions = workflowDataOptions.actions.GET; - $scope.labels = jobLabels; - $scope.count = count.val; - $scope.showManualControls = false; - - // Start elapsed time updater for job known to be running - if ($scope.workflow.started !== null && $scope.workflow.status === 'running') { - runTimeElapsedTimer = workflowResultsService.createOneSecondTimer($scope.workflow.started, updateWorkflowJobElapsedTimer); - } - - if(workflowData.summary_fields && workflowData.summary_fields.workflow_job_template && - workflowData.summary_fields.workflow_job_template.id){ - $scope.workflow_job_template_link = `/#/templates/workflow_job_template/${$scope.workflow.summary_fields.workflow_job_template.id}`; - } - - // stdout full screen toggle tooltip text - $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output"); - - // turn related api browser routes into front end routes - getLinks(); - - // use options labels to manipulate display of details - getLabels(); - - // set up a read only code mirror for extra vars - $scope.variables = ParseVariableString($scope.workflow.extra_vars); - $scope.parseType = 'yaml'; - $scope.varsTooltip= i18n._('Read only view of extra variables added to the workflow.'); - $scope.varsLabel = i18n._('Extra Variables'); - - - // Click binding for the expand/collapse button on the standard out log - $scope.stdoutFullScreen = false; - - WorkflowService.buildTree({ - workflowNodes: workflowNodes - }).then(function(data){ - $scope.treeData = data; - - // TODO: I think that the workflow chart directive (and eventually d3) is meddling with - // this treeData object and removing the children object for some reason (?) - // This happens on occasion and I think is a race condition (?) - if(!$scope.treeData.data.children) { - $scope.treeData.data.children = []; - } - - $scope.canAddWorkflowJobTemplate = false; - }); - - } - - $scope.toggleStdoutFullscreen = function() { - - $scope.$broadcast('workflowDetailsResized'); - - $scope.stdoutFullScreen = !$scope.stdoutFullScreen; - - if ($scope.stdoutFullScreen === true) { - $scope.toggleStdoutFullscreenTooltip = i18n._("Collapse Output"); - } else if ($scope.stdoutFullScreen === false) { - $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output"); - } - }; - - $scope.deleteJob = function() { - workflowResultsService.deleteJob($scope.workflow); - }; - - $scope.cancelJob = function() { - workflowResultsService.cancelJob($scope.workflow); - }; - - $scope.relaunchJob = function() { - workflowResultsService.relaunchJob($scope); - }; - - $scope.toggleManualControls = function() { - $scope.showManualControls = !$scope.showManualControls; - }; - - $scope.lessLabels = false; - $scope.toggleLessLabels = function() { - if (!$scope.lessLabels) { - $('#workflow-results-labels').slideUp(200); - $scope.lessLabels = true; - } - else { - $('#workflow-results-labels').slideDown(200); - $scope.lessLabels = false; - } - }; - - $scope.panChart = function(direction) { - $scope.$broadcast('panWorkflowChart', { - direction: direction - }); - }; - - $scope.zoomChart = function(zoom) { - $scope.$broadcast('zoomWorkflowChart', { - zoom: zoom - }); - }; - - $scope.resetChart = function() { - $scope.$broadcast('resetWorkflowChart'); - }; - - $scope.zoomToFitChart = function() { - $scope.$broadcast('zoomToFitChart'); - }; - - $scope.workflowZoomed = function(zoom) { - $scope.$broadcast('workflowZoomed', { - zoom: zoom - }); - }; - - init(); - - // Processing of job-status messages from the websocket - $scope.$on(`ws-jobs`, function(e, data) { - // Update the workflow job's unified job: - if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) { - $scope.workflow.status = data.status; - // start internval counter for job that transitioned to running - if ($scope.workflow.status === 'running') { - runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer); - } - - if(data.status === "successful" || data.status === "failed" || data.status === "error"){ - $state.go('.', null, { reload: true }); - } - } - // Update the jobs spawned by the workflow: - if(data.hasOwnProperty('workflow_job_id') && - parseInt(data.workflow_job_id, 10) === parseInt($scope.workflow.id,10)){ - - // This check ensures that the workflow status icon doesn't get stuck in - // the waiting state due to the UI missing the initial socket message. This - // can happen if the GET request on the workflow job returns "waiting" and - // the sockets aren't established yet so we miss the event that indicates - // the workflow job has moved into a running state. - if (!_.includes(['running', 'successful', 'failed', 'error'], $scope.workflow.status)){ - $scope.workflow.status = 'running'; - runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer); - } - - WorkflowService.updateStatusOfNode({ - treeData: $scope.treeData, - nodeId: data.workflow_node_id, - status: data.status, - unified_job_id: data.unified_job_id - }); - - $scope.workflow_nodes.forEach(node => { - if(parseInt(node.id) === parseInt(data.workflow_node_id)){ - node.summary_fields.job = { - status: data.status - }; - } - }); - - $scope.count = workflowResultsService - .getCounts($scope.workflow_nodes); - $scope.$broadcast("refreshWorkflowChart"); - } - }); - - $scope.$on('$destroy', function() { - workflowResultsService.destroyTimer(runTimeElapsedTimer); - }); -}]; diff --git a/awx/ui/client/src/workflow-results/workflow-results.partial.html b/awx/ui/client/src/workflow-results/workflow-results.partial.html deleted file mode 100644 index dd8def828367..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-results.partial.html +++ /dev/null @@ -1,289 +0,0 @@ -
-
-
- - -
-
- - -
-
- DETAILS -
- - -
- - - - - - - - - -
-
- - -
- - -
- -
- - {{ status_label }} -
-
- - -
- -
- {{ workflow.started | longDate }} -
-
- - -
- -
- {{ (workflow.finished | - longDate) || "Not Finished" }} -
-
- - - - - - - - - - - - - - - -
- -
-
-
-
- {{ label }} -
-
-
-
-
- - -
- -
-
- - -
-
- - -
-
- - - {{ workflow.name }} -
-
- -
- -
- Total Jobs -
- - {{ workflow_nodes.length || 0}} - - - -
- Elapsed -
- - {{ workflow.elapsed * 1000 | duration: "hh:mm:ss"}} - -
- - -
- - - - -
-
-
- -
-
-
KEY:
-
-
-
On Success
-
-
-
-
On Fail
-
-
-
-
Always
-
-
-
P
-
Project Sync
-
-
-
I
-
Inventory Sync
-
-
-
- -
- -
-
-
- -
- -
-
-
diff --git a/awx/ui/client/src/workflow-results/workflow-results.route.js b/awx/ui/client/src/workflow-results/workflow-results.route.js deleted file mode 100644 index 84562c47836d..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-results.route.js +++ /dev/null @@ -1,145 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../shared/template-url/template-url.factory'; - -import workflowResultsController from './workflow-results.controller'; - -export default { - name: 'workflowResults', - url: '/workflows/:id', - ncyBreadcrumb: { - parent: 'jobs', - label: '{{ workflow.id }} - {{ workflow.name }}' - }, - data: { - socket: { - "groups":{ - "jobs": ["status_changed"] - } - } - }, - templateUrl: templateUrl('workflow-results/workflow-results'), - controller: workflowResultsController, - resolve: { - // the GET for the particular workflow - workflowData: ['Rest', 'GetBasePath', '$stateParams', '$q', '$state', 'Alert', function(Rest, GetBasePath, $stateParams, $q, $state, Alert) { - Rest.setUrl(GetBasePath('workflow_jobs') + $stateParams.id); - var defer = $q.defer(); - Rest.get() - .then(function(data) { - defer.resolve(data.data); - }, function(data) { - defer.reject(data); - - if (data.status === 404) { - Alert('Job Not Found', 'Cannot find job.', 'alert-info'); - } else if (data.status === 403) { - Alert('Insufficient Permissions', 'You do not have permission to view this job.', 'alert-info'); - } - - $state.go('jobs'); - }); - return defer.promise; - }], - // after the GET for the job, this helps us keep the status bar from - // flashing as rest data comes in. Provides the list of workflow nodes - workflowNodes: ['workflowData', 'Rest', '$q', function(workflowData, Rest, $q) { - var defer = $q.defer(); - Rest.setUrl(workflowData.related.workflow_nodes + '?order_by=id'); - Rest.get() - .then(({data}) => { - if(data.next) { - let allNodes = data.results; - let getNodes = function(nextUrl){ - // Get the workflow nodes - Rest.setUrl(nextUrl); - Rest.get() - .then(function(nextData) { - for(var i=0; i { - // TODO: handle this - //defer.resolve(data); - }); - return defer.promise; - }], - // after the GET for the workflow & it's nodes, this helps us keep the - // status bar from flashing as rest data comes in. If the workflow - // is finished and there's a playbook_on_stats event, go ahead and - // resolve the count so you don't get that flashing! - count: ['workflowData', 'workflowNodes', 'workflowResultsService', 'Rest', '$q', function(workflowData, workflowNodes, workflowResultsService, Rest, $q) { - var defer = $q.defer(); - defer.resolve({ - val: workflowResultsService - .getCounts(workflowNodes), - countFinished: true}); - return defer.promise; - }], - // GET for the particular jobs labels to be displayed in the - // left-hand pane - jobLabels: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) { - var getNext = function(data, arr, resolve) { - Rest.setUrl(data.next); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, arr.concat(data.results), resolve); - } else { - resolve.resolve(arr.concat(data.results) - .map(val => val.name)); - } - }); - }; - - var seeMoreResolve = $q.defer(); - - Rest.setUrl(GetBasePath('workflow_jobs') + $stateParams.id + '/labels/'); - Rest.get() - .then(({data}) => { - if (data.next) { - getNext(data, data.results, seeMoreResolve); - } else { - seeMoreResolve.resolve(data.results - .map(val => val.name)); - } - }); - - return seeMoreResolve.promise; - }], - // OPTIONS request for the workflow. Used to make things like the - // verbosity data in the left-hand pane prettier than just an - // integer - workflowDataOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('workflow_jobs') + $stateParams.id); - var defer = $q.defer(); - Rest.options() - .then(function(data) { - defer.resolve(data.data); - }, function(data) { - defer.reject(data); - }); - return defer.promise; - }] - } - -}; diff --git a/awx/ui/client/src/workflow-results/workflow-results.service.js b/awx/ui/client/src/workflow-results/workflow-results.service.js deleted file mode 100644 index 41bc41064735..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-results.service.js +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************* -* Copyright (c) 2016 Ansible, Inc. -* -* All Rights Reserved -*************************************************/ - - -export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'WorkflowJobModel', '$interval', 'moment', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, WorkflowJob, $interval, moment) { - var val = { - getCounts: function(workflowNodes){ - var nodeArr = []; - workflowNodes.forEach(node => { - if(node && node.summary_fields && node.summary_fields.job && node.summary_fields.job.status){ - nodeArr.push(node.summary_fields.job.status); - } - }); - // use the workflow nodes data populate above to get the count - var count = { - successful : _.filter(nodeArr, function(o){ - return o === "successful"; - }), - failed : _.filter(nodeArr, function(o){ - return o === "failed" || o === "error" || o === "canceled"; - }) - }; - - // turn the count into an actual count, rather than a list of - // statuses - Object.keys(count).forEach(key => { - count[key] = count[key].length; - }); - - return count; - }, - deleteJob: function(workflow) { - Prompt({ - hdr: 'Delete Job', - resourceName: `#${workflow.id} ` + $filter('sanitize')(workflow.name), - body: `
- Are you sure you want to delete this workflow? -
`, - action: function() { - Wait('start'); - Rest.setUrl(workflow.url); - Rest.destroy() - .then(() => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - $state.go('jobs'); - }) - .catch(({obj, status}) => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - ProcessErrors(null, obj, status, null, { - hdr: 'Error!', - msg: `Could not delete job. - Returned status: ${status}` - }); - }); - }, - actionText: 'DELETE' - }); - }, - cancelJob: function(workflow) { - var doCancel = function() { - Rest.setUrl(workflow.url + 'cancel'); - Rest.post({}) - .then(() => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - }) - .catch(({obj, status}) => { - Wait('stop'); - $('#prompt-modal').modal('hide'); - ProcessErrors(null, obj, status, null, { - hdr: 'Error!', - msg: `Could not cancel workflow. - Returned status: ${status}` - }); - }); - }; - - Prompt({ - hdr: 'Cancel Workflow', - resourceName: `#${workflow.id} ${$filter('sanitize')(workflow.name)}`, - body: `
- Are you sure you want to cancel this workflow job? -
`, - action: function() { - Wait('start'); - Rest.setUrl(workflow.url + 'cancel'); - Rest.get() - .then(({data}) => { - if (data.can_cancel === true) { - doCancel(); - } else { - $('#prompt-modal').modal('hide'); - ProcessErrors(null, data, null, null, { - hdr: 'Error!', - msg: `Job has completed, - unabled to be canceled.` - }); - } - }); - }, - actionText: 'PROCEED' - }); - }, - relaunchJob: function(scope) { - const workflowJob = new WorkflowJob(); - - workflowJob.postRelaunch({ - id: scope.workflow.id - }).then((launchRes) => { - $state.go('workflowResults', { id: launchRes.data.id }, { reload: true }); - }); - }, - createOneSecondTimer: function(startTime, fn) { - return $interval(function(){ - fn(moment().diff(moment(startTime), 'seconds')); - }, 1000); - }, - destroyTimer: function(timer) { - if (timer !== null) { - $interval.cancel(timer); - timer = null; - return true; - } - return false; - }, - }; - return val; -}]; diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/main.js b/awx/ui/client/src/workflow-results/workflow-status-bar/main.js deleted file mode 100644 index 251258fc70f7..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-status-bar/main.js +++ /dev/null @@ -1,11 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import workflowStatusBar from './workflow-status-bar.directive'; - -export default - angular.module('workflowStatusBarDirective', []) - .directive('workflowStatusBar', workflowStatusBar); diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less deleted file mode 100644 index b5a14a8605db..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less +++ /dev/null @@ -1,58 +0,0 @@ -.WorkflowStatusBar { - display: flex; - flex: 0 0 auto; - width: 100%; - margin-top: 10px; - margin-bottom: 15px; -} - -.WorkflowStatusBar-successful, -.WorkflowStatusBar-failed, -.WorkflowStatusBar-pending, -.WorkflowStatusBar-noData { - height: 15px; - border-top: 5px solid @default-bg; - border-bottom: 5px solid @default-bg; -} - -.WorkflowStatusBar-successful { - background-color: @default-succ; - display: flex; - flex: 0 0 auto; -} - -.WorkflowStatusBar-failed { - background-color: @default-err; - flex: 0 0 auto; -} - -.WorkflowStatusBar-pending { - background-color: @b7grey; - flex: 0 0 auto; -} - -.WorkflowStatusBar-noData { - background-color: @default-icon-hov; - flex: 1 0 auto; -} - -.WorkflowStatusBar-tooltipLabel { - text-transform: uppercase; - margin-right: 15px; -} - -.WorkflowStatusBar-tooltipBadge { - border-radius: 5px; -} - -.WorkflowStatusBar-tooltipBadge--successful { - background-color: @default-succ; -} - -.WorkflowStatusBar-tooltipBadge--failed { - background-color: @default-err; -} - -.WorkflowStatusBar-tooltipBadge--pending { - background-color: @b7grey; -} diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js deleted file mode 100644 index c53fc2dcba2b..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -export default [ 'templateUrl', - function(templateUrl) { - return { - scope: true, - templateUrl: templateUrl('workflow-results/workflow-status-bar/workflow-status-bar'), - restrict: 'E', - link: function(scope) { - // as count is changed by jobs coming in, - // update the workflow status bar - scope.$watch('count', function(val) { - if (val) { - Object.keys(val).forEach(key => { - // reposition the workflow status bar by setting - // the various flex values to the count of - // those jobs - $(`.WorkflowStatusBar-${key}`) - .css('flex', `${val[key]} 0 auto`); - - // set the tooltip to give how many jobs of - // each type - if (val[key] > 0) { - scope[`${key}CountTip`] = `${key}${val[key]}`; - } - }); - - // if there are any hosts that have finished, don't - // show default grey bar - scope.hostsFinished = (Object - .keys(val) - .filter(key => (val[key] > 0)).length > 0); - } - }); - } - }; -}]; diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html deleted file mode 100644 index c2bc7d87a5b7..000000000000 --- a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
-
-
-
diff --git a/awx/ui/conf.py b/awx/ui/conf.py index 61a5a44d61c4..3148aec6ee7f 100644 --- a/awx/ui/conf.py +++ b/awx/ui/conf.py @@ -6,7 +6,7 @@ # Tower from awx.conf import register, fields -from awx.ui.fields import * # noqa +from awx.ui.fields import PendoTrackingStateField, CustomLogoField # noqa register( @@ -17,8 +17,8 @@ ('anonymous', _('Anonymous')), ('detailed', _('Detailed')), ], - label=_('Analytics Tracking State'), - help_text=_('Enable or Disable Analytics Tracking.'), + label=_('User Analytics Tracking State'), + help_text=_('Enable or Disable User Analytics Tracking.'), category=_('UI'), category_slug='ui', ) @@ -31,11 +31,10 @@ label=_('Custom Login Info'), help_text=_('If needed, you can add specific information (such as a legal ' 'notice or a disclaimer) to a text box in the login modal using ' - 'this setting. Any content added must be in plain text, as ' - 'custom HTML or other markup languages are not supported.'), + 'this setting. Any content added must be in plain text or an ' + 'HTML fragment, as other markup languages are not supported.'), category=_('UI'), category_slug='ui', - feature_required='rebranding', ) register( @@ -50,7 +49,6 @@ placeholder='data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=', category=_('UI'), category_slug='ui', - feature_required='rebranding', ) register( @@ -73,3 +71,4 @@ category=_('UI'), category_slug='ui', ) + diff --git a/awx/ui/context_processors.py b/awx/ui/context_processors.py index d9c0d133ba8c..87c071c2850a 100644 --- a/awx/ui/context_processors.py +++ b/awx/ui/context_processors.py @@ -1,20 +1,8 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. +import base64 +import os -# Django -from django.conf import settings as django_settings -# Ansible Tower -from awx.main.utils import get_awx_version - -def settings(request): - return { - 'settings': django_settings, - } - -def version(request): +def csp(request): return { - 'version': get_awx_version(), - 'tower_version': get_awx_version(), - 'short_tower_version': get_awx_version().split('-')[0], + 'csp_nonce': base64.encodebytes(os.urandom(32)).decode().rstrip(), } diff --git a/awx/ui/fields.py b/awx/ui/fields.py index 20bddb39f194..4d96165d4d8b 100644 --- a/awx/ui/fields.py +++ b/awx/ui/fields.py @@ -3,6 +3,7 @@ # Python import base64 +import binascii import re # Django @@ -38,6 +39,7 @@ def to_internal_value(self, data): b64data = match.group(1) try: base64.b64decode(b64data) - except TypeError: + except (TypeError, binascii.Error): self.fail('invalid_data') return data + diff --git a/awx/ui/grunt-tasks/jshint.js b/awx/ui/grunt-tasks/jshint.js deleted file mode 100644 index 0ed7193e6eab..000000000000 --- a/awx/ui/grunt-tasks/jshint.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - source: { - src: ['client/src/**/*.js', '*conf.js', '*.config.js', 'Gruntfile.js'], - options: { - reporter: require('jshint-stylish'), - jshintrc: true - } - }, - -}; diff --git a/awx/ui/grunt-tasks/nggettext_compile.js b/awx/ui/grunt-tasks/nggettext_compile.js deleted file mode 100644 index 1fb250a6d438..000000000000 --- a/awx/ui/grunt-tasks/nggettext_compile.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - all: { - options: { - format: 'json' - }, - files: [{ - expand: true, - dot: true, - dest: 'client/languages', - cwd: 'po', - ext: '.json', - src: ['*.po'] - }] - } -}; - diff --git a/awx/ui/grunt-tasks/nggettext_extract.js b/awx/ui/grunt-tasks/nggettext_extract.js deleted file mode 100644 index 437e82dd47c6..000000000000 --- a/awx/ui/grunt-tasks/nggettext_extract.js +++ /dev/null @@ -1,22 +0,0 @@ -let source = [ - 'client/features/**/*.js', - 'client/features/**/*.html', - 'client/lib/**/*.js', - 'client/lib/**/*.html', - 'client/src/**/*.js', - 'client/src/**/*.html' -]; - -module.exports = { - all: { - options: { - markerNames: ['_', 'N_'], - moduleName: 't', - moduleMethodString: 's', - moduleMethodPlural: 'p' - }, - files: { - 'po/ansible-tower-ui.pot': source - } - } -}; diff --git a/awx/ui/models.py b/awx/ui/models.py deleted file mode 100644 index 33cc349cf4aa..000000000000 --- a/awx/ui/models.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Empty models file. diff --git a/awx/ui/package.json b/awx/ui/package.json deleted file mode 100644 index 24a42aa20737..000000000000 --- a/awx/ui/package.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "name": "awx", - "version": "1.0.0", - "repository": { - "type": "git", - "url": "https://github.com/ansible/awx" - }, - "config": { - "django_port": "8043", - "django_host": "localhost" - }, - "engines": { - "node": "^6.11.3", - "npm": "^3.10.10" - }, - "scripts": { - "ui-docker-machine": "ip=$(docker-machine ip $DOCKER_MACHINE_NAME); npm set ansible-tower:django_host ${ip}; grunt dev;", - "ui-docker": "npm run watch;", - "build-devel": "npm run dev", - "pot": "grunt nggettext_extract", - "languages": "grunt nggettext_compile", - "build-release": "npm run production", - "pretest": "", - "test": "karma start test/spec/karma.spec.js", - "jshint": "grunt jshint:source --no-color", - "test:ci": "npm run test -- --single-run --reporter junit,dots --browsers=PhantomJS", - "e2e": "./test/e2e/runner.js --config ./test/e2e/nightwatch.conf.js --suiteRetries=2", - "unit": "karma start test/unit/karma.unit.js", - "lint": "eslint .", - "dev": "webpack --config build/webpack.development.js --progress", - "watch": "webpack-dev-server --config build/webpack.watch.js --progress", - "production": "webpack --config build/webpack.production.js" - }, - "devDependencies": { - "angular-mocks": "~1.6.6", - "archiver": "^2.1.1", - "axios": "^0.16.2", - "babel-core": "^6.26.0", - "babel-istanbul": "^0.12.2", - "babel-loader": "^7.1.2", - "babel-plugin-istanbul": "^4.1.5", - "babel-preset-env": "^1.6.0", - "chromedriver": "^2.35.0", - "clean-webpack-plugin": "^0.1.16", - "copy-webpack-plugin": "^4.0.1", - "css-loader": "^0.28.5", - "eslint": "^4.6.1", - "eslint-config-airbnb-base": "^12.0.0", - "eslint-import-resolver-webpack": "^0.8.3", - "eslint-loader": "^1.9.0", - "eslint-plugin-disable": "^0.3.0", - "eslint-plugin-import": "^2.7.0", - "extract-text-webpack-plugin": "^3.0.0", - "grunt": "^1.0.1", - "grunt-angular-gettext": "^2.2.3", - "grunt-cli": "^1.2.0", - "grunt-concurrent": "^2.3.0", - "grunt-contrib-jshint": "^1.0.0", - "grunt-newer": "^1.2.0", - "hard-source-webpack-plugin": "^0.4.9", - "html-loader": "^0.5.1", - "html-webpack-harddisk-plugin": "^0.1.0", - "html-webpack-plugin": "^2.30.1", - "istanbul-instrumenter-loader": "^3.0.0", - "jasmine-core": "^2.5.2", - "jshint": "^2.9.4", - "jshint-stylish": "^2.2.0", - "json-loader": "^0.5.4", - "karma": "^1.4.1", - "karma-chrome-launcher": "^2.2.0", - "karma-coverage": "^1.1.1", - "karma-firefox-launcher": "^1.0.0", - "karma-html2js-preprocessor": "^1.0.0", - "karma-jasmine": "^1.1.0", - "karma-junit-reporter": "^1.2.0", - "karma-phantomjs-launcher": "^1.0.2", - "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^2.0.4", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "less-plugin-autoprefix": "^1.4.2", - "load-grunt-configs": "^1.0.0", - "load-grunt-tasks": "^3.5.0", - "ngtemplate-loader": "^2.0.1", - "nightwatch": "^0.9.19", - "node-object-hash": "^1.3.0", - "nunjucks": "^3.1.2", - "phantomjs-prebuilt": "^2.1.12", - "time-grunt": "^1.4.0", - "uglifyjs-webpack-plugin": "^0.4.6", - "uuid": "^3.1.0", - "webpack": "^3.0.0", - "webpack-dev-server": "^2.7.1", - "webpack-merge": "^4.1.0" - }, - "dependencies": { - "@uirouter/angularjs": "^1.0.7", - "angular": "~1.6.6", - "angular-breadcrumb": "git+https://git@github.com/ansible/angular-breadcrumb#0.4.1", - "angular-codemirror": "git+https://git@github.com/ansible/angular-codemirror#v1.1.2", - "angular-cookies": "~1.6.6", - "angular-drag-and-drop-lists": "git+https://git@github.com/ansible/angular-drag-and-drop-lists#v1.4.1", - "angular-duration-format": "^1.0.1", - "angular-gettext": "^2.3.5", - "angular-md5": "^0.1.8", - "angular-moment": "^0.10.1", - "angular-sanitize": "~1.6.6", - "angular-scheduler": "git+https://git@github.com/ansible/angular-scheduler#v0.3.2", - "angular-tz-extensions": "git+https://git@github.com/ansible/angular-tz-extensions#v0.5.2", - "ansi-to-html": "^0.6.3", - "babel-polyfill": "^6.26.0", - "bootstrap": "^3.3.7", - "bootstrap-datepicker": "^1.7.1", - "codemirror": "^5.17.0", - "components-font-awesome": "^4.6.1", - "d3": "~3.3.13", - "html-entities": "^1.2.1", - "javascript-detect-element-resize": "^0.5.3", - "jquery": "~2.2.4", - "jquery-ui": "^1.12.1", - "js-yaml": "^3.2.7", - "legacy-loader": "0.0.2", - "lodash": "~3.8.0", - "lr-infinite-scroll": "git+https://git@github.com/lorenzofox3/lrInfiniteScroll", - "moment": "^2.19.4", - "ng-toast": "git+https://git@github.com/ansible/ngToast#v2.1.1", - "nvd3": "git+https://git@github.com/ansible/nvd3#awx", - "reconnectingwebsocket": "^1.0.0", - "rrule": "git+https://git@github.com/jkbrzt/rrule#4ff63b2f8524fd6d5ba6e80db770953b5cd08a0c", - "select2": "^4.0.2", - "sprintf-js": "^1.0.3", - "mathjs": "^3.15.0", - "hamsterjs": "^1.1.2", - "titlecase": "^1.1.2", - "inherits": "^1.0.2", - "angular-mousewheel": "^1.0.5", - "angular-xeditable": "~0.8.0" - } -} diff --git a/awx/ui/po/ansible-tower-ui.pot b/awx/ui/po/ansible-tower-ui.pot deleted file mode 100644 index ee20fdbbf5c9..000000000000 --- a/awx/ui/po/ansible-tower-ui.pot +++ /dev/null @@ -1,5586 +0,0 @@ -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Project-Id-Version: \n" - -#: client/src/projects/add/projects-add.controller.js:161 -#: client/src/projects/edit/projects-edit.controller.js:295 -msgid "%sNote:%s Mercurial does not support password authentication for SSH. Do not put the username and key in the URL. If using Bitbucket and SSH, do not supply your Bitbucket username." -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:140 -#: client/src/projects/edit/projects-edit.controller.js:274 -msgid "%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using SSH. GIT read only protocol (git://) does not use username or password information." -msgstr "" - -#: client/src/credentials/credentials.form.js:287 -msgid "(defaults to %s)" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -msgid "(seconds)" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:66 -msgid "100" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:60 -msgid "20" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:63 -msgid "50" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:17 -msgid "" -"

\n" -" Enter inventory variables using either JSON or YAML\n" -" syntax. Use the radio button to toggle between the two.\n" -"

\n" -" JSON:\n" -"
\n" -"
\n" -" {\n" -"
\"somevar\": \"somevalue\",\n" -"
\"password\": \"magic\"\n" -"
\n" -" }\n" -"
\n" -" YAML:\n" -"
\n" -"
\n" -" ---\n" -"
somevar: somevalue\n" -"
password: magic\n" -"
\n" -"
\n" -"

\n" -" View JSON examples at\n" -" www.json.org\n" -"

\n" -"

\n" -" View YAML examples at\n" -" \n" -" docs.ansible.com\n" -"

" -msgstr "" - -#: client/features/templates/templates.strings.js:54 -msgid "

Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON.

JSON:
{
"somevar": "somevalue",
"password": "magic"
}
YAML:
---
somevar: somevalue
password: magic
" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:33 -msgid "A schedule name is required." -msgstr "" - -#: client/src/users/add/users-add.controller.js:102 -msgid "A value is required" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:167 -msgid "A value is required." -msgstr "" - -#: client/src/about/about.route.js:10 -msgid "ABOUT" -msgstr "" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 -msgid "ACTION" -msgstr "" - -#: client/src/activity-stream/activity-detail.form.js:23 -msgid "ACTIVITY DETAIL" -msgstr "" - -#: client/src/activity-stream/activitystream.route.js:28 -#: client/src/activity-stream/streams.list.js:14 -#: client/src/activity-stream/streams.list.js:15 -msgid "ACTIVITY STREAM" -msgstr "" - -#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 -msgid "ADD" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:16 -msgid "ADD SURVEY PROMPT" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:51 -msgid "ADDITIONAL INFORMATION" -msgstr "" - -#: client/src/organizations/linkout/organizations-linkout.route.js:258 -#: client/src/organizations/list/organizations-list.controller.js:85 -msgid "ADMINS" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:4 -msgid "ALL ACTIVITY" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:239 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "ANY" -msgstr "" - -#: client/src/credentials/credentials.form.js:198 -msgid "API Key" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:243 -msgid "API Service/Integration Key" -msgstr "" - -#: client/src/notifications/shared/type-change.service.js:60 -msgid "API Token" -msgstr "" - -#: client/features/applications/applications.strings.js:8 -#: client/src/activity-stream/get-target-title.factory.js:47 -msgid "APPLICATIONS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js:19 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js:19 -msgid "ASSOCIATED GROUPS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js:19 -msgid "ASSOCIATED HOSTS" -msgstr "" - -#: client/lib/components/components.strings.js:78 -msgid "About" -msgstr "" - -#: client/lib/components/components.strings.js:82 -msgid "Access" -msgstr "" - -#: client/src/credentials/credentials.form.js:91 -msgid "Access Key" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:221 -msgid "Account SID" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:180 -msgid "Account Token" -msgstr "" - -#: client/src/activity-stream/activity-detail.form.js:36 -msgid "Action" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/inventories-hosts/hosts/hosts.partial.html:47 -#: client/src/shared/list-generator/list-generator.factory.js:582 -msgid "Actions" -msgstr "" - -#: client/features/templates/templates.strings.js:15 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:17 -#: client/src/templates/templates.list.js:36 -msgid "Activity" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:88 -msgid "Activity Stream" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:113 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:115 -#: client/src/organizations/organizations.form.js:93 -#: client/src/teams/teams.form.js:85 -#: client/src/templates/workflows.form.js:148 -msgid "Add" -msgstr "" - -#: client/src/credentials/credentials.list.js:14 -msgid "Add Credentials" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:13 -msgid "Add Inventories" -msgstr "" - -#: client/src/shared/stateDefinitions.factory.js:288 -msgid "Add Permissions" -msgstr "" - -#: client/src/projects/projects.list.js:13 -msgid "Add Project" -msgstr "" - -#: client/src/shared/form-generator.js:1720 -#: client/src/templates/job_templates/job-template.form.js:458 -#: client/src/templates/workflows.form.js:196 -msgid "Add Survey" -msgstr "" - -#: client/src/teams/teams.list.js:13 -msgid "Add Team" -msgstr "" - -#: client/src/teams/teams.form.js:86 -msgid "Add User" -msgstr "" - -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/shared/stateDefinitions.factory.js:578 -#: client/src/users/users.list.js:17 -msgid "Add Users" -msgstr "" - -#: client/src/organizations/organizations.form.js:94 -msgid "Add Users to this organization." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:69 -msgid "Add a group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:118 -msgid "Add a host" -msgstr "" - -#: client/src/scheduler/schedules.list.js:74 -msgid "Add a new schedule" -msgstr "" - -#: client/features/credentials/legacy.credentials.js:71 -#: client/src/credentials/credentials.form.js:448 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:115 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:117 -#: client/src/projects/projects.form.js:255 -#: client/src/templates/job_templates/job-template.form.js:406 -#: client/src/templates/workflows.form.js:149 -msgid "Add a permission" -msgstr "" - -#: client/src/shared/form-generator.js:1455 -msgid "Admin" -msgstr "" - -#: client/lib/components/components.strings.js:83 -msgid "Administration" -msgstr "" - -#: client/src/organizations/linkout/organizations-linkout.route.js:281 -msgid "Admins" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:367 -msgid "After every project update where the SCM revision changes, refresh the inventory from the selected source before executing job tasks. This is intended for static content, like the Ansible inventory .ini file format." -msgstr "" - -#: client/lib/components/components.strings.js:90 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:37 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:43 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:65 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:74 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "All" -msgstr "" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 -msgid "All Activity" -msgstr "" - -#: client/src/portal-mode/portal-mode-layout.partial.html:22 -msgid "All Jobs" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:285 -#: client/src/templates/job_templates/job-template.form.js:292 -msgid "Allow Provisioning Callbacks" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:301 -msgid "An SCM update does not appear to be running for project: %s. Click the %sRefresh%s button to view the latest status." -msgstr "" - -#: client/src/organizations/organizations.form.js:47 -#: client/src/organizations/organizations.form.js:52 -#: client/src/projects/projects.form.js:207 -#: client/src/projects/projects.form.js:212 -#: client/src/templates/job_templates/job-template.form.js:235 -#: client/src/templates/job_templates/job-template.form.js:240 -msgid "Ansible Environment" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:62 -#: client/src/templates/survey-maker/shared/question-definition.form.js:68 -msgid "Answer Type" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:44 -#: client/src/templates/survey-maker/shared/question-definition.form.js:53 -msgid "Answer Variable Name" -msgstr "" - -#: client/lib/components/components.strings.js:76 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 -msgid "Applications" -msgstr "" - -#: client/src/notifications/notification-templates-list/list.controller.js:219 -msgid "Are you sure you want to delete this notification template?" -msgstr "" - -#: client/src/teams/list/teams-list.controller.js:80 -msgid "Are you sure you want to delete this team?" -msgstr "" - -#: client/src/users/list/users-list.controller.js:93 -msgid "Are you sure you want to delete this user?" -msgstr "" - -#: client/lib/services/base-string.service.js:78 -msgid "Are you sure you want to delete this {{ resourceType }}?" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:13 -msgid "Are you sure you want to delete this {{deleteMode}}?" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:25 -msgid "Are you sure you want to disassociate the group below from" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:23 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:26 -msgid "Are you sure you want to disassociate the host below from" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:47 -msgid "Are you sure you want to permanently delete the group below from the inventory?" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js:106 -msgid "Are you sure you want to permanently delete the host below from the inventory?" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:69 -msgid "Are you sure you want to permanently delete the inventory source below from the inventory?" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:251 -msgid "Are you sure you want to remove the %s below from %s?" -msgstr "" - -#: client/lib/services/base-string.service.js:83 -msgid "Are you sure you want to submit the request to cancel this job?" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:39 -msgid "Arguments" -msgstr "" - -#: client/src/credentials/credentials.form.js:232 -#: client/src/credentials/credentials.form.js:271 -#: client/src/credentials/credentials.form.js:311 -#: client/src/credentials/credentials.form.js:397 -msgid "Ask at runtime?" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:24 -msgid "Associate an existing Instance" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:69 -msgid "Associate an existing group" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:51 -msgid "Associate this host with a new group" -msgstr "" - -#: client/src/shared/form-generator.js:1457 -msgid "Auditor" -msgstr "" - -#: client/src/configuration/configuration.partial.html:15 -msgid "Authentication" -msgstr "" - -#: client/src/credentials/credentials.form.js:72 -msgid "Authentication for network device access. This can include SSH keys, usernames, passwords, and authorize information. Network credentials are used when submitting jobs to run playbooks against network devices." -msgstr "" - -#: client/src/credentials/credentials.form.js:68 -msgid "Authentication for remote machine access. This can include SSH keys, usernames, passwords, and sudo information. Machine credentials are used when submitting jobs to run playbooks against remote hosts." -msgstr "" - -#: client/src/credentials/credentials.form.js:343 -msgid "Authorize" -msgstr "" - -#: client/src/credentials/credentials.form.js:351 -msgid "Authorize Password" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:226 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:239 -msgid "Availability Zone:" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:125 -msgid "Azure AD" -msgstr "" - -#: client/src/shared/directives.js:91 -msgid "BROWSE" -msgstr "" - -#: client/src/projects/projects.form.js:81 -msgid "Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. Together the base path and selected playbook directory provide the full path used to locate playbooks." -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:129 -msgid "Become Privilege Escalation" -msgstr "" - -#: client/src/license/license.partial.html:107 -msgid "Browse" -msgstr "" - -#: client/src/license/license.partial.html:129 -msgid "" -"By default, Tower collects and transmits analytics data on Tower usage to Red Hat. This data is used to enhance future releases of the Tower Software and help streamline customer experience and success. For more information, see\n" -"\t\t\t\t\t\t\t\t\t\t\n" -"\t\t\t\t\t\t\t\t\t\t\t\tthis Tower documentation page\n" -"\t\t\t\t\t\t\t\t\t\t. Uncheck this box to disable this feature." -msgstr "" - -#: client/lib/services/base-string.service.js:60 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:28 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:73 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:16 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:16 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:16 -#: client/src/job-submission/job-submission.partial.html:370 -#: client/src/partials/survey-maker-modal.html:17 -#: client/src/partials/survey-maker-modal.html:85 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:17 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:78 -msgid "CANCEL" -msgstr "" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:28 -msgid "CHANGES" -msgstr "" - -#: client/lib/components/components.strings.js:20 -msgid "CHOOSE A FILE" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:30 -msgid "CLEAR ALL" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:86 -msgid "CLOSE" -msgstr "" - -#: client/features/jobs/routes/templateCompletedJobs.route.js:21 -msgid "COMPLETED JOBS" -msgstr "" - -#: client/src/configuration/configuration.partial.html:10 -msgid "CONFIGURE {{ BRAND_NAME }}" -msgstr "" - -#: client/features/templates/templates.strings.js:30 -msgid "CONFIRM" -msgstr "" - -#: client/lib/services/base-string.service.js:71 -msgid "COPY" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:25 -msgid "COULD NOT CREATE TOKEN" -msgstr "" - -#: client/src/shared/stateDefinitions.factory.js:157 -msgid "CREATE %s" -msgstr "" - -#: client/features/applications/applications.strings.js:9 -msgid "CREATE APPLICATION" -msgstr "" - -#: client/features/credentials/credentials.strings.js:8 -#: client/src/credentials/credentials.form.js:16 -msgid "CREATE CREDENTIAL" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:16 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:16 -msgid "CREATE GROUP" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:17 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:17 -#: client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:17 -msgid "CREATE HOST" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:8 -msgid "CREATE INSTANCE GROUP" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js:8 -msgid "CREATE INVENTORY SOURCE" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js:8 -#: client/src/scheduler/main.js:109 -#: client/src/scheduler/main.js:200 -#: client/src/scheduler/main.js:284 -msgid "CREATE SCHEDULE" -msgstr "" - -#: client/src/management-jobs/scheduler/main.js:81 -msgid "CREATE SCHEDULED JOB" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:32 -msgid "CREATE SOURCE" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:18 -#: client/features/users/tokens/tokens.strings.js:9 -#: client/features/users/tokens/users-tokens-add.route.js:25 -msgid "CREATE TOKEN" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:351 -#: client/src/partials/job-template-details.html:2 -msgid "CREDENTIAL" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:21 -msgid "CREDENTIAL TYPE" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:92 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:70 -msgid "CREDENTIAL TYPE:" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:11 -#: client/src/credential-types/credential-types.list.js:12 -#: client/src/credential-types/main.js:44 -msgid "CREDENTIAL TYPES" -msgstr "" - -#: client/features/credentials/legacy.credentials.js:11 -#: client/src/activity-stream/get-target-title.factory.js:17 -#: client/src/credentials/credentials.list.js:15 -#: client/src/credentials/credentials.list.js:16 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:5 -msgid "CREDENTIALS" -msgstr "" - -#: client/features/credentials/credentials.strings.js:30 -msgid "CREDENTIALS PERMISSIONS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:390 -#: client/src/projects/projects.form.js:200 -msgid "Cache Timeout" -msgstr "" - -#: client/src/projects/projects.form.js:189 -msgid "Cache Timeout%s (seconds)%s" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:214 -#: client/src/users/list/users-list.controller.js:85 -msgid "Call to %s failed. DELETE returned status:" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:281 -#: client/src/projects/list/projects-list.controller.js:298 -msgid "Call to %s failed. GET status:" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:245 -msgid "Call to %s failed. POST returned status:" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:260 -msgid "Call to %s failed. POST status:" -msgstr "" - -#: client/src/management-jobs/card/card.controller.js:29 -msgid "Call to %s failed. Return status: %d" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:307 -msgid "Call to get project failed. GET status:" -msgstr "" - -#: client/lib/services/base-string.service.js:90 -msgid "Call to {{ path }} failed. {{ action }} returned status: {{ status }}." -msgstr "" - -#: client/features/output/details.partial.html:17 -#: client/lib/services/base-string.service.js:82 -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:105 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:188 -#: client/src/configuration/configuration.controller.js:594 -#: client/src/shared/form-generator.js:1708 -#: client/src/workflow-results/workflow-results.partial.html:42 -msgid "Cancel" -msgstr "" - -#: client/lib/services/base-string.service.js:84 -msgid "Cancel Job" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:276 -msgid "Cancel Not Allowed" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:100 -msgid "Cancel sync process" -msgstr "" - -#: client/src/projects/projects.list.js:131 -msgid "Cancel the SCM update" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:81 -msgid "Canceled. Click for details" -msgstr "" - -#: client/src/shared/smart-search/smart-search.controller.js:106 -msgid "Cannot search running job" -msgstr "" - -#: client/src/instance-groups/instance-groups.list.js:22 -msgid "Capacity" -msgstr "" - -#: client/src/projects/projects.form.js:83 -msgid "Change %s under \"Configure {{BRAND_NAME}}\" to change this location." -msgstr "" - -#: client/src/activity-stream/activity-detail.form.js:41 -msgid "Changes" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:355 -msgid "Channel" -msgstr "" - -#: client/features/templates/templates.strings.js:60 -msgid "Check" -msgstr "" - -#: client/src/shared/form-generator.js:1080 -msgid "Choose a %s" -msgstr "" - -#: client/features/templates/templates.strings.js:51 -msgid "Choose a job type" -msgstr "" - -#: client/features/templates/templates.strings.js:52 -msgid "Choose a verbosity" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:64 -msgid "Choose an answer type" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:67 -msgid "Choose an answer type or format you want as the prompt for the user. Refer to the Ansible Tower Documentation for more additional information about each option." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:112 -msgid "Choose an inventory file" -msgstr "" - -#: client/src/shared/directives.js:92 -msgid "Choose file" -msgstr "" - -#: client/src/license/license.partial.html:97 -msgid "Choose your license file, agree to the End User License Agreement, and click submit." -msgstr "" - -#: client/src/projects/projects.form.js:157 -msgid "Clean" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:299 -msgid "Clear" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:64 -msgid "Click for details" -msgstr "" - -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:261 -msgid "Click here to open the workflow graph editor." -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:16 -msgid "Click on a row to select it, and click Finished when done. Click the %s button to create a new inventory." -msgstr "" - -#: client/src/teams/teams.list.js:16 -msgid "Click on a row to select it, and click Finished when done. Click the %s button to create a new team." -msgstr "" - -#: client/src/templates/templates.list.js:17 -msgid "Click on a row to select it, and click Finished when done. Use the %s button to create a new job template." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:138 -msgid "Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, or choose" -msgstr "" - -#: client/src/credentials/credentials.form.js:321 -msgid "Client ID" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:254 -msgid "Client Identifier" -msgstr "" - -#: client/src/credentials/credentials.form.js:330 -msgid "Client Secret" -msgstr "" - -#: client/src/shared/form-generator.js:1712 -msgid "Close" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:26 -msgid "Cloud source not configured." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "Cloud source not configured. Click" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:80 -#: client/src/credentials/factories/kind-change.factory.js:137 -msgid "CloudForms URL" -msgstr "" - -#: client/features/output/jobs.strings.js:29 -#: client/src/workflow-results/workflow-results.controller.js:118 -msgid "Collapse Output" -msgstr "" - -#: client/src/network-ui/network-nav/network.nav.strings.js:13 -msgid "Collapse Panel" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:155 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:172 -#: client/src/templates/job_templates/job-template.form.js:438 -msgid "Completed Jobs" -msgstr "" - -#: client/src/management-jobs/card/card.partial.html:34 -msgid "Configure Notifications" -msgstr "" - -#: client/src/users/users.form.js:84 -msgid "Confirm Password" -msgstr "" - -#: client/src/configuration/configuration.controller.js:601 -msgid "Confirm Reset" -msgstr "" - -#: client/src/configuration/configuration.controller.js:610 -msgid "Confirm factory reset" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "Confirm the removal of the" -msgstr "" - -#: client/src/teams/teams.form.js:24 -#: client/src/users/users.form.js:25 -msgid "Contact your System Administrator to grant you the appropriate permissions to add and edit Users and Teams." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:18 -msgid "Contains 0 hosts." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:179 -msgid "Control the level of output ansible will produce as the playbook executes." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:313 -msgid "Control the level of output ansible will produce for inventory source update jobs." -msgstr "" - -#: client/lib/components/components.strings.js:52 -msgid "Copied to clipboard." -msgstr "" - -#: client/src/credentials/credentials.list.js:73 -#: client/src/inventories-hosts/inventories/inventory.list.js:111 -#: client/src/inventory-scripts/inventory-scripts.list.js:61 -#: client/src/notifications/notificationTemplates.list.js:82 -#: client/src/projects/projects.list.js:109 -#: client/src/templates/templates.list.js:100 -msgid "Copy" -msgstr "" - -#: client/features/templates/templates.strings.js:76 -msgid "Copy Workflow" -msgstr "" - -#: client/src/credentials/credentials.list.js:76 -msgid "Copy credential" -msgstr "" - -#: client/lib/components/components.strings.js:51 -msgid "Copy full revision to clipboard." -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:114 -msgid "Copy inventory" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.list.js:64 -msgid "Copy inventory script" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:85 -msgid "Copy notification" -msgstr "" - -#: client/src/projects/projects.list.js:112 -msgid "Copy project" -msgstr "" - -#: client/src/templates/templates.list.js:103 -msgid "Copy template" -msgstr "" - -#: client/src/about/about.partial.html:27 -msgid "" -"Copyright © 2018 Red Hat, Inc.
\n" -" Visit Ansible.com for more information.
" -msgstr "" - -#: client/lib/components/components.strings.js:79 -msgid "Copyright © 2018 Red Hat, Inc." -msgstr "" - -#: client/src/users/users.list.js:44 -msgid "Create New" -msgstr "" - -#: client/features/applications/applications.strings.js:20 -msgid "Create a new Application" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:23 -msgid "Create a new Instance Group" -msgstr "" - -#: client/src/credentials/credentials.list.js:52 -msgid "Create a new credential" -msgstr "" - -#: client/src/credential-types/credential-types.list.js:42 -msgid "Create a new credential type" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.list.js:40 -msgid "Create a new custom inventory" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:69 -msgid "Create a new group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:123 -msgid "Create a new host" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:75 -msgid "Create a new inventory" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:52 -msgid "Create a new notification template" -msgstr "" - -#: client/src/organizations/list/organizations-list.partial.html:21 -msgid "Create a new organization" -msgstr "" - -#: client/src/projects/projects.list.js:76 -msgid "Create a new project" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:68 -msgid "Create a new source" -msgstr "" - -#: client/src/teams/teams.list.js:43 -msgid "Create a new team" -msgstr "" - -#: client/src/templates/templates.list.js:56 -msgid "Create a new template" -msgstr "" - -#: client/src/users/users.list.js:48 -msgid "Create a new user" -msgstr "" - -#: client/features/templates/templates.strings.js:25 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:73 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:74 -#: client/src/job-submission/job-submission.partial.html:18 -#: client/src/templates/job_templates/job-template.form.js:121 -msgid "Credential" -msgstr "" - -#: client/features/templates/templates.strings.js:35 -msgid "Credential Type" -msgstr "" - -#: client/lib/components/components.strings.js:65 -#: client/lib/models/models.strings.js:12 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:33 -msgid "Credential Types" -msgstr "" - -#: client/features/jobs/jobs.strings.js:15 -#: client/features/templates/templates.strings.js:18 -#: client/lib/components/components.strings.js:64 -#: client/lib/models/models.strings.js:8 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:129 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:58 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 -#: client/src/templates/job_templates/job-template.form.js:133 -msgid "Credentials" -msgstr "" - -#: client/features/templates/templates.strings.js:36 -msgid "Credentials that require passwords on launch are not permitted for template schedules and workflow nodes. The following credentials must be removed or replaced to proceed:" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:17 -msgid "Critical" -msgstr "" - -#: client/src/shared/directives.js:93 -msgid "Current Image:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:171 -msgid "Custom Inventory Script" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.form.js:50 -#: client/src/inventory-scripts/inventory-scripts.form.js:60 -msgid "Custom Script" -msgstr "" - -#: client/src/home/home.route.js:21 -msgid "DASHBOARD" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:28 -#: client/lib/services/base-string.service.js:70 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:52 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:74 -#: client/src/notifications/notification-templates-list/list.controller.js:221 -#: client/src/organizations/list/organizations-list.controller.js:196 -#: client/src/partials/survey-maker-modal.html:18 -#: client/src/projects/edit/projects-edit.controller.js:253 -#: client/src/projects/list/projects-list.controller.js:244 -#: client/src/users/list/users-list.controller.js:95 -msgid "DELETE" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:84 -msgid "DELETE SURVEY" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:35 -msgid "DESCRIPTION" -msgstr "" - -#: client/features/output/details.partial.html:3 -#: client/src/instance-groups/instance-groups.strings.js:17 -msgid "DETAILS" -msgstr "" - -#: client/src/network-ui/network-details/details.partial.html:2 -msgid "DETAILS | {{item.name}}" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:31 -msgid "DISASSOCIATE" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:5 -msgid "DYNAMIC HOSTS" -msgstr "" - -#: client/lib/components/components.strings.js:59 -msgid "Dashboard" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:137 -msgid "Default" -msgstr "" - -#: client/features/output/details.partial.html:34 -#: client/lib/services/base-string.service.js:75 -#: client/src/credential-types/credential-types.list.js:73 -#: client/src/credential-types/list/list.controller.js:106 -#: client/src/credentials/credentials.list.js:92 -#: client/src/credentials/list/credentials-list.controller.js:164 -#: client/src/inventories-hosts/inventories/inventory.list.js:126 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:139 -#: client/src/inventory-scripts/inventory-scripts.list.js:79 -#: client/src/inventory-scripts/list/list.controller.js:114 -#: client/src/notifications/notification-templates-list/list.controller.js:217 -#: client/src/notifications/notificationTemplates.list.js:100 -#: client/src/organizations/list/organizations-list.controller.js:192 -#: client/src/projects/edit/projects-edit.controller.js:250 -#: client/src/projects/list/projects-list.controller.js:240 -#: client/src/scheduler/schedules.list.js:98 -#: client/src/teams/teams.list.js:72 -#: client/src/templates/templates.list.js:116 -#: client/src/users/list/users-list.controller.js:91 -#: client/src/users/users.list.js:79 -#: client/src/workflow-results/workflow-results.partial.html:54 -msgid "Delete" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:6 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:6 -msgid "Delete Group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:195 -msgid "Delete Source" -msgstr "" - -#: client/src/credentials/credentials.list.js:94 -msgid "Delete credential" -msgstr "" - -#: client/src/credential-types/credential-types.list.js:75 -msgid "Delete credential type" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:101 -#: client/src/inventories-hosts/inventory-hosts.strings.js:19 -msgid "Delete group" -msgid_plural "Delete groups" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:48 -msgid "Delete groups" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:37 -msgid "Delete groups and hosts" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:100 -#: client/src/inventories-hosts/inventory-hosts.strings.js:21 -msgid "Delete host" -msgid_plural "Delete hosts" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:59 -msgid "Delete hosts" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:128 -msgid "Delete inventory" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.list.js:81 -msgid "Delete inventory script" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:102 -msgid "Delete notification" -msgstr "" - -#: client/src/projects/projects.form.js:167 -msgid "Delete on Update" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:27 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:27 -msgid "Delete or promote the group's children?" -msgstr "" - -#: client/src/scheduler/schedules.list.js:101 -msgid "Delete schedule" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:125 -msgid "Delete source" -msgstr "" - -#: client/src/teams/teams.list.js:76 -msgid "Delete team" -msgstr "" - -#: client/src/templates/templates.list.js:119 -msgid "Delete template" -msgstr "" - -#: client/src/projects/projects.form.js:169 -msgid "Delete the local repository in its entirety prior to performing an update." -msgstr "" - -#: client/src/projects/projects.list.js:125 -msgid "Delete the project" -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:81 -msgid "Delete the schedule" -msgstr "" - -#: client/src/users/users.list.js:83 -msgid "Delete user" -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:14 -msgid "Delete {{ group }} and {{ host }}" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:23 -msgid "Deleting group" -msgstr "" - -#: client/lib/services/base-string.service.js:77 -msgid "Deleting this {{ resourceType }} will make the following resources unavailable." -msgstr "" - -#: client/src/projects/projects.form.js:169 -msgid "Depending on the size of the repository this may significantly increase the amount of time required to complete an update." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:246 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "Describe Instances documentation" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:34 -#: client/src/credentials/credentials.form.js:39 -#: client/src/inventories-hosts/hosts/host.form.js:63 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:39 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:62 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:62 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:58 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:28 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:36 -#: client/src/inventory-scripts/inventory-scripts.form.js:35 -#: client/src/network-ui/network-details/details.partial.html:26 -#: client/src/notifications/notificationTemplates.form.js:39 -#: client/src/organizations/organizations.form.js:33 -#: client/src/projects/projects.form.js:37 -#: client/src/teams/teams.form.js:35 -#: client/src/templates/job_templates/job-template.form.js:41 -#: client/src/templates/survey-maker/shared/question-definition.form.js:36 -#: client/src/templates/workflows.form.js:49 -#: client/src/users/users.form.js:148 -#: client/src/users/users.form.js:174 -msgid "Description" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:136 -#: client/src/notifications/notificationTemplates.form.js:140 -#: client/src/notifications/notificationTemplates.form.js:152 -#: client/src/notifications/notificationTemplates.form.js:156 -msgid "Destination Channels" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:430 -#: client/src/notifications/notificationTemplates.form.js:434 -msgid "Destination Channels or Users" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:205 -#: client/src/notifications/notificationTemplates.form.js:206 -msgid "Destination SMS Number" -msgstr "" - -#: client/features/applications/applications.strings.js:15 -#: client/features/credentials/credentials.strings.js:13 -#: client/features/users/tokens/tokens.strings.js:14 -#: client/src/license/license.partial.html:5 -#: client/src/shared/form-generator.js:1490 -msgid "Details" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:263 -msgid "Diff Mode" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:369 -#: client/src/notifications/notificationTemplates.form.js:401 -msgid "Disable SSL Verification" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Group From Group" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:6 -msgid "Disassociate Host" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:6 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Host From Group" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:65 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:110 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:98 -msgid "Disassociate group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:87 -msgid "Disassociate host" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:93 -#: client/src/configuration/configuration.controller.js:231 -#: client/src/configuration/configuration.controller.js:311 -#: client/src/configuration/system-form/configuration-system.controller.js:57 -msgid "Discard changes" -msgstr "" - -#: client/src/teams/teams.form.js:149 -msgid "Dissasociate permission from team" -msgstr "" - -#: client/src/users/users.form.js:228 -msgid "Dissasociate permission from user" -msgstr "" - -#: client/src/credentials/credentials.form.js:384 -#: client/src/credentials/factories/become-method-change.factory.js:54 -#: client/src/credentials/factories/kind-change.factory.js:111 -msgid "Domain Name" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.form.js:59 -msgid "Drag and drop your custom inventory script file here or create one in the field to import your custom inventory. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/partials/survey-maker-modal.html:77 -msgid "Drop question here to reorder" -msgstr "" - -#: client/features/applications/applications.strings.js:10 -msgid "EDIT APPLICATION" -msgstr "" - -#: client/src/configuration/configuration.route.js:28 -msgid "EDIT CONFIGURATION" -msgstr "" - -#: client/features/credentials/credentials.strings.js:9 -msgid "EDIT CREDENTIAL" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:9 -msgid "EDIT INSTANCE GROUP" -msgstr "" - -#: client/src/management-jobs/scheduler/main.js:95 -msgid "EDIT SCHEDULED JOB" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:17 -msgid "EDIT SURVEY PROMPT" -msgstr "" - -#: client/lib/components/components.strings.js:9 -msgid "ENCRYPTED" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:39 -msgid "EXAMPLES:" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:15 -msgid "EXECUTE COMMAND" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:10 -msgid "EXPAND" -msgstr "" - -#: client/features/applications/applications.strings.js:28 -#: client/features/users/tokens/tokens.strings.js:36 -msgid "EXPIRATION" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:24 -msgid "EXPIRES" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:48 -#: client/lib/components/code-mirror/code-mirror.strings.js:8 -msgid "EXTRA VARIABLES" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:355 -msgid "Each time a job runs using this inventory, refresh the inventory from the selected source before executing job tasks." -msgstr "" - -#: client/src/projects/projects.form.js:180 -msgid "Each time a job runs using this project, update the revision of the project prior to starting the job." -msgstr "" - -#: client/src/credential-types/credential-types.list.js:56 -#: client/src/credentials/credentials.list.js:66 -#: client/src/inventories-hosts/inventories/inventory.list.js:97 -#: client/src/inventory-scripts/inventory-scripts.list.js:54 -#: client/src/notifications/notificationTemplates.list.js:66 -#: client/src/notifications/notificationTemplates.list.js:75 -#: client/src/scheduler/schedules.list.js:83 -#: client/src/teams/teams.list.js:55 -#: client/src/templates/templates.list.js:80 -#: client/src/users/users.list.js:60 -msgid "Edit" -msgstr "" - -#: client/src/shared/form-generator.js:1724 -#: client/src/templates/job_templates/job-template.form.js:465 -#: client/src/templates/workflows.form.js:203 -msgid "Edit Survey" -msgstr "" - -#: client/src/credential-types/credential-types.list.js:58 -msgid "Edit credenital type" -msgstr "" - -#: client/src/credentials/credentials.list.js:68 -msgid "Edit credential" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:85 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:96 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:84 -msgid "Edit group" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.list.js:83 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:73 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:79 -msgid "Edit host" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:99 -msgid "Edit inventory" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.list.js:56 -msgid "Edit inventory script" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:68 -msgid "Edit notification" -msgstr "" - -#: client/src/scheduler/schedules.list.js:86 -msgid "Edit schedule" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:83 -msgid "Edit source" -msgstr "" - -#: client/src/teams/teams.list.js:59 -msgid "Edit team" -msgstr "" - -#: client/src/templates/templates.list.js:82 -msgid "Edit template" -msgstr "" - -#: client/src/workflow-results/workflow-results.partial.html:124 -msgid "Edit the User" -msgstr "" - -#: client/src/projects/projects.list.js:88 -msgid "Edit the project" -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:67 -msgid "Edit the schedule" -msgstr "" - -#: client/src/users/users.list.js:64 -msgid "Edit user" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:276 -msgid "Either you do not have access or the SCM update process completed. Click the %sRefresh%s button to view the latest status." -msgstr "" - -#: client/src/credentials/credentials.form.js:191 -#: client/src/users/users.form.js:54 -msgid "Email" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:298 -#: client/src/templates/job_templates/job-template.form.js:303 -#: client/src/templates/workflows.form.js:101 -#: client/src/templates/workflows.form.js:106 -msgid "Enable Concurrent Jobs" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:124 -#: client/src/templates/job_templates/job-template.form.js:274 -#: client/src/templates/job_templates/job-template.form.js:279 -msgid "Enable Privilege Escalation" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:289 -msgid "Enables creation of a provisioning callback URL. Using the URL a host can contact {{BRAND_NAME}} and request a configuration update using this job template." -msgstr "" - -#: client/src/credentials/factories/credential-form-save.factory.js:73 -msgid "Encrypted credentials are not supported." -msgstr "" - -#: client/src/license/license.partial.html:113 -msgid "End User License Agreement" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:73 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:72 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:68 -msgid "Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two." -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:76 -msgid "Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:155 -msgid "Enter one HipChat channel per line. The pound symbol (#) is not required." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:433 -msgid "Enter one IRC channel or username per line. The pound symbol (#) for channels, and the at (@) symbol for users, are not required." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:139 -msgid "Enter one Slack channel per line. The pound symbol (#) is not required." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:97 -msgid "Enter one email address per line to create a recipient list for this type of notification." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:209 -msgid "Enter one phone number per line to specify where to route SMS messages." -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:81 -#: client/src/credentials/factories/kind-change.factory.js:138 -msgid "Enter the URL for the virtual machine which %scorresponds to your CloudForm instance. %sFor example, %s" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:71 -#: client/src/credentials/factories/kind-change.factory.js:128 -msgid "Enter the URL which corresponds to your %sRed Hat Satellite 6 server. %sFor example, %s" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:49 -#: client/src/credentials/factories/kind-change.factory.js:106 -msgid "Enter the hostname or IP address which corresponds to your VMware vCenter." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:195 -msgid "Enter the number associated with the \"Messaging Service\" in Twilio in the format +18005550199." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:197 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:221 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:245 -msgid "Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:187 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:194 -msgid "Environment Variables" -msgstr "" - -#: client/src/configuration/configuration.controller.js:141 -msgid "Error" -msgstr "" - -#: client/lib/services/base-string.service.js:89 -#: client/src/configuration/configuration.controller.js:402 -#: client/src/configuration/configuration.controller.js:502 -#: client/src/configuration/configuration.controller.js:536 -#: client/src/configuration/configuration.controller.js:583 -#: client/src/configuration/system-form/configuration-system.controller.js:231 -#: client/src/credentials/factories/credential-form-save.factory.js:77 -#: client/src/credentials/factories/credential-form-save.factory.js:93 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:131 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:141 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:168 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:198 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:217 -#: client/src/management-jobs/card/card.controller.js:102 -#: client/src/management-jobs/card/card.controller.js:28 -#: client/src/projects/add/projects-add.controller.js:116 -#: client/src/projects/edit/projects-edit.controller.js:163 -#: client/src/projects/edit/projects-edit.controller.js:229 -#: client/src/projects/edit/projects-edit.controller.js:245 -#: client/src/projects/list/projects-list.controller.js:186 -#: client/src/projects/list/projects-list.controller.js:213 -#: client/src/projects/list/projects-list.controller.js:260 -#: client/src/projects/list/projects-list.controller.js:281 -#: client/src/projects/list/projects-list.controller.js:297 -#: client/src/projects/list/projects-list.controller.js:306 -#: client/src/users/add/users-add.controller.js:99 -#: client/src/users/edit/users-edit.controller.js:185 -#: client/src/users/edit/users-edit.controller.js:82 -#: client/src/users/list/users-list.controller.js:84 -msgid "Error!" -msgstr "" - -#: client/src/activity-stream/streams.list.js:40 -msgid "Event" -msgstr "" - -#: client/src/activity-stream/factories/build-description.factory.js:120 -msgid "Event summary not available" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:137 -#: client/src/projects/edit/projects-edit.controller.js:272 -msgid "Example URLs for GIT SCM include:" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:158 -#: client/src/projects/edit/projects-edit.controller.js:292 -msgid "Example URLs for Mercurial SCM include:" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:149 -#: client/src/projects/edit/projects-edit.controller.js:283 -msgid "Example URLs for Subversion SCM include:" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:47 -msgid "Example: ansible_facts.ansible_distribution:\"RedHat\"" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:76 -msgid "Existing Group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:125 -msgid "Existing Host" -msgstr "" - -#: client/features/output/jobs.strings.js:28 -#: client/src/workflow-results/workflow-results.controller.js:120 -#: client/src/workflow-results/workflow-results.controller.js:76 -msgid "Expand Output" -msgstr "" - -#: client/src/network-ui/network-nav/network.nav.strings.js:12 -msgid "Expand Panel" -msgstr "" - -#: client/src/license/license.partial.html:39 -msgid "Expires On" -msgstr "" - -#: client/features/templates/templates.strings.js:53 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:133 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:145 -#: client/src/job-submission/job-submission.partial.html:165 -#: client/src/partials/logviewer.html:8 -#: client/src/templates/job_templates/job-template.form.js:352 -#: client/src/templates/job_templates/job-template.form.js:359 -#: client/src/templates/workflows.form.js:84 -#: client/src/templates/workflows.form.js:91 -msgid "Extra Variables" -msgstr "" - -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html:4 -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js:7 -msgid "FACTS" -msgstr "" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:64 -msgid "FAILED" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:45 -msgid "FIELDS:" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:107 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:106 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:107 -msgid "Facts" -msgstr "" - -#: client/lib/components/components.strings.js:91 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:80 -msgid "Failed" -msgstr "" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:44 -msgid "Failed Hosts" -msgstr "" - -#: client/src/users/add/users-add.controller.js:99 -msgid "Failed to add new user. POST returned status:" -msgstr "" - -#: client/src/credentials/factories/credential-form-save.factory.js:78 -msgid "Failed to create new Credential. POST status:" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:117 -msgid "Failed to create new project. POST returned status:" -msgstr "" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:218 -msgid "Failed to retrieve job template extra variables." -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:164 -msgid "Failed to retrieve project: %s. GET status:" -msgstr "" - -#: client/src/users/edit/users-edit.controller.js:186 -#: client/src/users/edit/users-edit.controller.js:83 -msgid "Failed to retrieve user: %s. GET status:" -msgstr "" - -#: client/src/configuration/configuration.controller.js:503 -msgid "Failed to save settings. Returned status:" -msgstr "" - -#: client/src/configuration/configuration.controller.js:537 -msgid "Failed to save toggle settings. Returned status:" -msgstr "" - -#: client/src/credentials/factories/credential-form-save.factory.js:94 -msgid "Failed to update Credential. PUT status:" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:229 -msgid "Failed to update project: %s. PUT status:" -msgstr "" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:199 -#: client/src/management-jobs/card/card.controller.js:103 -msgid "Failed updating job %s with variables. POST returned: %d" -msgstr "" - -#: client/src/notifications/notifications.list.js:49 -msgid "Failure" -msgstr "" - -#: client/src/scheduler/schedules.list.js:56 -msgid "Final Run" -msgstr "" - -#: client/features/jobs/jobs.strings.js:9 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:54 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:44 -msgid "Finished" -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:21 -#: client/src/users/users.form.js:29 -#: client/src/users/users.list.js:33 -msgid "First Name" -msgstr "" - -#: client/src/scheduler/schedules.list.js:46 -msgid "First Run" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:52 -msgid "For additional information on advanced search search syntax please see the Ansible Tower" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:63 -#: client/src/credentials/factories/kind-change.factory.js:120 -msgid "For example, %s" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:36 -#: client/src/inventories-hosts/hosts/host.list.js:36 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:35 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:32 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:35 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:31 -msgid "For hosts that are part of an external inventory, this flag cannot be changed. It will be set by the inventory sync process." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:54 -msgid "For job templates, select run to execute the playbook. Select check to only check playbook syntax, test environment setup, and report problems without executing the playbook." -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:110 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:97 -#: client/src/templates/job_templates/job-template.form.js:143 -#: client/src/templates/job_templates/job-template.form.js:153 -msgid "Forks" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:172 -msgid "Frequency Details" -msgstr "" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js:45 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js:46 -msgid "GROUPS" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:135 -#: client/src/projects/list/projects-list.controller.js:76 -msgid "Get latest SCM revision" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:126 -msgid "GitHub" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:127 -msgid "GitHub Org" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:128 -msgid "GitHub Team" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:129 -msgid "Google OAuth2" -msgstr "" - -#: client/src/teams/teams.form.js:158 -#: client/src/users/users.form.js:217 -msgid "Grant Permission" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Gray" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Green" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:52 -msgid "Group Variables" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:115 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:31 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:89 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:88 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:115 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:150 -msgid "Groups" -msgstr "" - -#: client/lib/components/components.strings.js:12 -#: client/lib/services/base-string.service.js:65 -msgid "HIDE" -msgstr "" - -#: client/lib/components/components.strings.js:43 -msgid "HINT: Drag and drop an SSH private key file on the field below." -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:41 -#: client/src/inventories-hosts/hosts/hosts.partial.html:9 -#: client/src/inventories-hosts/hosts/main.js:80 -#: client/src/inventories-hosts/inventories/inventories.partial.html:14 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.route.js:18 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js:17 -msgid "HOSTS" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:320 -#: client/src/notifications/notificationTemplates.form.js:321 -msgid "HTTP Headers" -msgstr "" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "Hide Activity Stream" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:23 -msgid "High" -msgstr "" - -#: client/src/credentials/credentials.form.js:139 -#: client/src/notifications/notificationTemplates.form.js:83 -msgid "Host" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:52 -#: client/src/credentials/factories/kind-change.factory.js:109 -msgid "Host (Authentication URL)" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:334 -#: client/src/templates/job_templates/job-template.form.js:343 -msgid "Host Config Key" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:39 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:39 -msgid "Host Enabled" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:46 -#: client/src/inventories-hosts/hosts/host.form.js:57 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:45 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:56 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:45 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:56 -#: client/src/network-ui/network-details/details.partial.html:16 -msgid "Host Name" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:80 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:79 -msgid "Host Variables" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is available" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is available. Click to toggle." -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is not available" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is not available. Click to toggle." -msgstr "" - -#: client/features/output/jobs.strings.js:13 -msgid "Host status information for this job is unavailable." -msgstr "" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:39 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:98 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:57 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:56 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:149 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:159 -msgid "Hosts" -msgstr "" - -#: client/src/license/license.partial.html:52 -msgid "Hosts Available" -msgstr "" - -#: client/src/license/license.partial.html:64 -msgid "Hosts Remaining" -msgstr "" - -#: client/src/license/license.partial.html:58 -msgid "Hosts Used" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:239 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "Hosts are imported to" -msgstr "" - -#: client/src/license/license.partial.html:121 -msgid "I agree to the End User License Agreement" -msgstr "" - -#: client/src/partials/job-template-details.html:2 -msgid "INFO" -msgstr "" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 -msgid "INITIATED BY" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.route.js:7 -msgid "INSIGHTS" -msgstr "" - -#: client/src/instance-groups/instance-groups.list.js:6 -#: client/src/instance-groups/instance-groups.list.js:7 -#: client/src/instance-groups/instance-groups.strings.js:13 -msgid "INSTANCE GROUPS" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:18 -msgid "INSTANCES" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:14 -#: client/src/inventories-hosts/hosts/hosts.partial.html:8 -#: client/src/inventories-hosts/inventories/inventories.partial.html:13 -#: client/src/inventories-hosts/inventories/inventories.route.js:8 -#: client/src/inventories-hosts/inventories/inventory.list.js:14 -#: client/src/inventories-hosts/inventories/inventory.list.js:15 -#: client/src/network-ui/network-nav/network.nav.strings.js:8 -#: client/src/organizations/linkout/organizations-linkout.route.js:144 -#: client/src/organizations/list/organizations-list.controller.js:67 -msgid "INVENTORIES" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:346 -#: client/src/partials/job-template-details.html:2 -msgid "INVENTORY" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.form.js:23 -msgid "INVENTORY SCRIPT" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:35 -#: client/src/inventory-scripts/inventory-scripts.list.js:12 -#: client/src/inventory-scripts/main.js:65 -msgid "INVENTORY SCRIPTS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js:8 -msgid "INVENTORY SOURCES" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:419 -msgid "IRC Nick" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:408 -msgid "IRC Server Address" -msgstr "" - -#: client/src/notifications/shared/type-change.service.js:66 -msgid "IRC Server Password" -msgstr "" - -#: client/src/notifications/shared/type-change.service.js:65 -msgid "IRC Server Port" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:79 -msgid "ISSUE: {{report.rule.description}}" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:43 -msgid "ITEMS" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:362 -#: client/src/notifications/notificationTemplates.form.js:394 -msgid "Icon URL" -msgstr "" - -#: client/src/login/authenticationServices/timer.factory.js:157 -msgid "Idle Session" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:236 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:249 -msgid "If blank, all groups above are created except" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:343 -msgid "If checked, all variables for child groups and hosts will be removed and replaced by those found on the external source." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:331 -msgid "If checked, any hosts and groups that were previously present on the external source but are now removed will be removed from the Tower inventory. Hosts and groups that were not managed by the inventory source will be promoted to the next manually created group or if there is no manually created group to promote them into, they will be left in the \"all\" default group for the inventory." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:277 -msgid "If enabled, run this playbook as an administrator." -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:121 -msgid "If enabled, show the changes made by Ansible tasks, where supported. This is equivalent to Ansible’s --diff mode." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:262 -msgid "If enabled, show the changes made by Ansible tasks, where supported. This is equivalent to Ansible’s --diff mode." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:301 -msgid "If enabled, simultaneous runs of this job template will be allowed." -msgstr "" - -#: client/src/templates/workflows.form.js:104 -msgid "If enabled, simultaneous runs of this workflow job template will be allowed." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:312 -msgid "If enabled, use cached facts if available and store discovered facts in the cache." -msgstr "" - -#: client/src/credentials/credentials.form.js:52 -msgid "If no organization is given, the credential can only be used by the user that creates the credential. Organization admins and system administrators can assign an organization so that roles for the credential can be assigned to users and teams in that organization." -msgstr "" - -#: client/src/license/license.partial.html:70 -msgid "If you are ready to upgrade, please contact us by clicking the button below" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:227 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:240 -msgid "Image ID:" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:34 -#: client/src/inventories-hosts/hosts/host.list.js:34 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:33 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:30 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:33 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:29 -msgid "Indicates if a host is available and should be included in running jobs." -msgstr "" - -#: client/src/activity-stream/activity-detail.form.js:31 -#: client/src/activity-stream/streams.list.js:33 -msgid "Initiated by" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:53 -#: client/src/credential-types/credential-types.form.js:61 -msgid "Injector Configuration" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:39 -#: client/src/credential-types/credential-types.form.js:47 -msgid "Input Configuration" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:123 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:122 -msgid "Insights" -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:52 -msgid "Insights Credential" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:145 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:148 -msgid "Instance Filters" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:47 -msgid "Instance Group parameter is missing." -msgstr "" - -#: client/lib/components/components.strings.js:75 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:54 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:57 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:61 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:64 -#: client/src/organizations/organizations.form.js:38 -#: client/src/organizations/organizations.form.js:41 -#: client/src/templates/job_templates/job-template.form.js:247 -#: client/src/templates/job_templates/job-template.form.js:250 -msgid "Instance Groups" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:236 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:249 -msgid "Instance ID" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:228 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:241 -msgid "Instance ID:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:229 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:242 -msgid "Instance Type:" -msgstr "" - -#: client/lib/components/components.strings.js:74 -msgid "Instances" -msgstr "" - -#: client/src/license/license.partial.html:11 -msgid "Invalid License" -msgstr "" - -#: client/src/license/license.controller.js:86 -#: client/src/license/license.controller.js:94 -msgid "Invalid file format. Please upload valid JSON." -msgstr "" - -#: client/lib/components/components.strings.js:16 -msgid "Invalid input for this type." -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:34 -msgid "Invalid username and/or password. Please try again." -msgstr "" - -#: client/lib/components/components.strings.js:66 -#: client/lib/models/models.strings.js:16 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:122 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:52 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:50 -#: client/src/organizations/linkout/organizations-linkout.route.js:156 -msgid "Inventories" -msgstr "" - -#: client/features/jobs/jobs.strings.js:13 -#: client/features/templates/templates.strings.js:16 -#: client/features/templates/templates.strings.js:24 -#: client/src/inventories-hosts/hosts/host.list.js:69 -#: client/src/inventories-hosts/inventories/inventory.list.js:80 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:71 -#: client/src/job-submission/job-submission.partial.html:17 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/templates/job_templates/job-template.form.js:66 -#: client/src/templates/job_templates/job-template.form.js:80 -msgid "Inventory" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:110 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:124 -msgid "Inventory File" -msgstr "" - -#: client/lib/components/components.strings.js:71 -#: client/lib/models/models.strings.js:20 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 -msgid "Inventory Scripts" -msgstr "" - -#: client/lib/models/models.strings.js:25 -msgid "Inventory Sources" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:46 -msgid "Inventory Sync" -msgstr "" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:55 -msgid "Inventory Sync Failures" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:75 -msgid "Inventory Variables" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:68 -msgid "Inventory contains 0 hosts." -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:4 -msgid "JOB STATUS" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:22 -msgid "JOB TEMPLATE" -msgstr "" - -#: client/features/templates/routes/organizationsTemplatesList.route.js:20 -#: client/features/templates/routes/projectsTemplatesList.route.js:18 -#: client/src/organizations/list/organizations-list.controller.js:79 -#: client/src/portal-mode/portal-job-templates.list.js:13 -#: client/src/portal-mode/portal-job-templates.list.js:14 -msgid "JOB TEMPLATES" -msgstr "" - -#: client/features/jobs/index.view.html:6 -#: client/features/jobs/routes/instanceGroupJobs.route.js:13 -#: client/features/jobs/routes/instanceJobs.route.js:13 -#: client/features/jobs/routes/inventoryCompletedJobs.route.js:22 -#: client/features/jobs/routes/jobs.route.js:12 -#: client/src/activity-stream/get-target-title.factory.js:32 -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:118 -#: client/src/instance-groups/instance-groups.strings.js:19 -#: client/src/portal-mode/portal-mode-layout.partial.html:10 -msgid "JOBS" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:12 -#: client/lib/services/base-string.service.js:69 -#: client/src/job-submission/job-submission.partial.html:173 -msgid "JSON" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:198 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:222 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:246 -msgid "JSON:" -msgstr "" - -#: client/features/templates/templates.strings.js:47 -#: client/src/job-submission/job-submission.partial.html:228 -#: client/src/templates/job_templates/job-template.form.js:190 -#: client/src/templates/job_templates/job-template.form.js:197 -msgid "Job Tags" -msgstr "" - -#: client/features/jobs/jobs.strings.js:12 -#: client/features/templates/templates.strings.js:13 -#: client/src/templates/templates.list.js:61 -msgid "Job Template" -msgstr "" - -#: client/lib/models/models.strings.js:30 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:36 -#: client/src/projects/projects.form.js:297 -msgid "Job Templates" -msgstr "" - -#: client/features/templates/templates.strings.js:49 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:32 -#: client/src/job-submission/job-submission.partial.html:202 -#: client/src/templates/job_templates/job-template.form.js:47 -#: client/src/templates/job_templates/job-template.form.js:55 -msgid "Job Type" -msgstr "" - -#: client/lib/components/components.strings.js:60 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 -#: client/src/configuration/configuration.partial.html:22 -#: client/src/instance-groups/instance-groups.strings.js:37 -msgid "Jobs" -msgstr "" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:61 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:154 -#: client/src/shared/smart-search/smart-search.partial.html:14 -msgid "Key" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:230 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:243 -msgid "Key Name:" -msgstr "" - -#: client/src/credential-types/credential-types.list.js:31 -#: client/src/credentials/credentials.list.js:33 -msgid "Kind" -msgstr "" - -#: client/features/applications/applications.strings.js:30 -msgid "LAST MODIFIED" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:37 -msgid "LAST USED" -msgstr "" - -#: client/features/templates/templates.strings.js:29 -msgid "LAUNCH" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:6 -msgid "LAUNCH JOB" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:130 -msgid "LDAP" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:138 -msgid "LDAP 1 (Optional)" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:139 -msgid "LDAP 2 (Optional)" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:140 -msgid "LDAP 3 (Optional)" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:141 -msgid "LDAP 4 (Optional)" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:142 -msgid "LDAP 5 (Optional)" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:17 -msgid "LDAP Server" -msgstr "" - -#: client/src/configuration/license.route.js:18 -#: client/src/license/license.route.js:18 -msgid "LICENSE" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:224 -#: client/src/templates/job_templates/job-template.form.js:228 -#: client/src/templates/templates.list.js:43 -#: client/src/templates/workflows.form.js:72 -#: client/src/templates/workflows.form.js:77 -msgid "Labels" -msgstr "" - -#: client/features/templates/templates.strings.js:19 -msgid "Last Modified" -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:25 -#: client/src/users/users.form.js:36 -#: client/src/users/users.list.js:37 -msgid "Last Name" -msgstr "" - -#: client/features/templates/templates.strings.js:20 -msgid "Last Ran" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:56 -msgid "Last Sync" -msgstr "" - -#: client/src/projects/projects.list.js:56 -msgid "Last Updated" -msgstr "" - -#: client/src/shared/form-generator.js:1716 -msgid "Launch" -msgstr "" - -#: client/src/management-jobs/card/card.partial.html:23 -msgid "Launch Management Job" -msgstr "" - -#: client/features/jobs/jobs.strings.js:11 -msgid "Launched By" -msgstr "" - -#: client/features/templates/templates.strings.js:37 -#: client/src/job-submission/job-submission.partial.html:99 -msgid "Launching this job requires the passwords listed below. Enter and confirm each password before continuing." -msgstr "" - -#: client/features/credentials/legacy.credentials.js:350 -msgid "Legacy state configuration for does not exist" -msgstr "" - -#: client/src/configuration/configuration.partial.html:43 -#: client/src/license/license.controller.js:44 -#: client/src/license/license.partial.html:8 -msgid "License" -msgstr "" - -#: client/src/license/license.partial.html:104 -msgid "License File" -msgstr "" - -#: client/src/license/license.partial.html:33 -msgid "License Key" -msgstr "" - -#: client/src/license/license.controller.js:46 -msgid "License Management" -msgstr "" - -#: client/src/license/license.partial.html:21 -msgid "License Type" -msgstr "" - -#: client/features/templates/templates.strings.js:48 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:55 -#: client/src/job-submission/job-submission.partial.html:220 -#: client/src/templates/job_templates/job-template.form.js:159 -#: client/src/templates/job_templates/job-template.form.js:163 -msgid "Limit" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:240 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:254 -msgid "Limit to hosts having a tag:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:242 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:256 -msgid "Limit to hosts using either key pair:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:244 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "Limit to hosts where the Name tag begins with" -msgstr "" - -#: client/src/shared/socket/socket.service.js:203 -msgid "Live events: attempting to connect to the server." -msgstr "" - -#: client/src/shared/socket/socket.service.js:207 -msgid "Live events: connected. Pages containing job status information will automatically update in real-time." -msgstr "" - -#: client/src/shared/socket/socket.service.js:211 -msgid "Live events: error connecting to the server." -msgstr "" - -#: client/src/shared/form-generator.js:1994 -msgid "Loading..." -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:133 -msgid "Local Time Zone" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:225 -msgid "Log aggregator test failed.
Detail:" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:218 -msgid "Log aggregator test successful." -msgstr "" - -#: client/lib/components/components.strings.js:56 -msgid "Logged in as" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:89 -msgid "Logging" -msgstr "" - -#: client/lib/components/components.strings.js:58 -msgid "Logout" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:35 -msgid "Low" -msgstr "" - -#: client/src/management-jobs/card/card.partial.html:6 -#: client/src/management-jobs/card/card.route.js:20 -msgid "MANAGEMENT JOBS" -msgstr "" - -#: client/src/portal-mode/portal-mode.route.js:12 -msgid "MY VIEW" -msgstr "" - -#: client/src/credentials/credentials.form.js:67 -#: client/src/job-submission/job-submission.partial.html:356 -msgid "Machine" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:60 -msgid "Machine Credential" -msgstr "" - -#: client/lib/components/components.strings.js:73 -msgid "Management Jobs" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:91 -msgid "Manual projects do not require a schedule" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:142 -#: client/src/projects/list/projects-list.controller.js:90 -msgid "Manual projects do not require an SCM update" -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:28 -msgid "Maximum per-user sessions reached. Please sign in." -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:29 -msgid "Medium" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:90 -msgid "Misc. System" -msgstr "" - -#: client/src/templates/workflows.form.js:35 -msgid "Missing Job Templates found in the Workflow Editor" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:22 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:30 -msgid "Module" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:25 -msgid "Most recent job failed. Click to view jobs." -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:29 -msgid "Most recent job successful. Click to view jobs." -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:77 -msgid "Multiple Choice Options" -msgstr "" - -#: client/src/portal-mode/portal-mode-layout.partial.html:16 -msgid "My Jobs" -msgstr "" - -#: client/features/applications/applications.strings.js:24 -msgid "NEW APPLICATION" -msgstr "" - -#: client/features/credentials/credentials.strings.js:26 -msgid "NEW CREDENTIAL" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:16 -msgid "NEW CREDENTIAL TYPE" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.form.js:16 -msgid "NEW CUSTOM INVENTORY" -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:17 -msgid "NEW INVENTORY" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:19 -msgid "NEW JOB TEMPLATE" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:16 -msgid "NEW NOTIFICATION TEMPLATE" -msgstr "" - -#: client/src/organizations/organizations.form.js:18 -msgid "NEW ORGANIZATION" -msgstr "" - -#: client/src/projects/projects.form.js:17 -msgid "NEW PROJECT" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:10 -msgid "NEW SMART INVENTORY" -msgstr "" - -#: client/src/teams/teams.form.js:16 -msgid "NEW TEAM" -msgstr "" - -#: client/src/users/users.form.js:16 -msgid "NEW USER" -msgstr "" - -#: client/src/templates/workflows.form.js:17 -msgid "NEW WORKFLOW JOB TEMPLATE" -msgstr "" - -#: client/lib/services/base-string.service.js:63 -msgid "NEXT" -msgstr "" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:38 -msgid "NO HOSTS HAVE BEEN CREATED" -msgstr "" - -#: client/lib/components/components.strings.js:39 -msgid "NO OPTIONS AVAILABLE" -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:89 -msgid "NOTICE" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:21 -msgid "NOTIFICATION TEMPLATE" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:26 -#: client/src/notifications/notificationTemplates.list.js:14 -msgid "NOTIFICATION TEMPLATES" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js:9 -#: client/src/management-jobs/notifications/notification.route.js:46 -#: client/src/notifications/main.js:42 -#: client/src/notifications/main.js:89 -msgid "NOTIFICATIONS" -msgstr "" - -#: client/src/credential-types/credential-types.form.js:27 -#: client/src/credential-types/credential-types.list.js:24 -#: client/src/credentials/credentials.form.js:32 -#: client/src/credentials/credentials.list.js:26 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:14 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:13 -#: client/src/instance-groups/instance-groups.list.js:15 -#: client/src/inventories-hosts/hosts/host.list.js:61 -#: client/src/inventories-hosts/inventories/inventory.list.js:47 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:55 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:33 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:51 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:21 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:28 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:45 -#: client/src/inventory-scripts/inventory-scripts.form.js:28 -#: client/src/inventory-scripts/inventory-scripts.list.js:20 -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 -#: client/src/notifications/notificationTemplates.form.js:32 -#: client/src/notifications/notificationTemplates.list.js:32 -#: client/src/notifications/notifications.list.js:27 -#: client/src/organizations/organizations.form.js:26 -#: client/src/portal-mode/portal-job-templates.list.js:23 -#: client/src/projects/projects.form.js:30 -#: client/src/projects/projects.list.js:37 -#: client/src/scheduler/scheduled-jobs.list.js:31 -#: client/src/scheduler/schedules.list.js:41 -#: client/src/teams/teams.form.js:127 -#: client/src/teams/teams.form.js:28 -#: client/src/teams/teams.list.js:23 -#: client/src/templates/job_templates/job-template.form.js:34 -#: client/src/templates/templates.list.js:24 -#: client/src/templates/workflows.form.js:42 -#: client/src/users/users.form.js:145 -#: client/src/users/users.form.js:171 -#: client/src/users/users.form.js:197 -msgid "Name" -msgstr "" - -#: client/src/credentials/credentials.form.js:71 -msgid "Network" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:104 -#: client/src/inventories-hosts/inventories/inventory.list.js:106 -msgid "Network Visualization" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:81 -msgid "New Group" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:130 -msgid "New Host" -msgstr "" - -#: client/src/users/add/users-add.controller.js:91 -msgid "New user successfully created!" -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:51 -#: client/src/scheduler/schedules.list.js:51 -msgid "Next Run" -msgstr "" - -#: client/src/credentials/credentials.list.js:21 -msgid "No Credentials Have Been Created" -msgstr "" - -#: client/features/templates/templates.strings.js:61 -#: client/src/job-submission/lists/credential/job-sub-cred-list.controller.js:44 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:15 -msgid "No Credentials Matching This Type Have Been Created" -msgstr "" - -#: client/features/output/host-event/host-event-codemirror.partial.html:3 -msgid "No JSON data returned by the module" -msgstr "" - -#: client/src/projects/projects.list.js:20 -msgid "No Projects Have Been Created" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:50 -msgid "No Remediation Playbook Available" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:176 -msgid "No SCM Configuration" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:9 -msgid "No SCM updates have run for this project" -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:17 -msgid "No Teams exist" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:152 -msgid "No Updates Available" -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:18 -msgid "No Users exist" -msgstr "" - -#: client/features/templates/templates.strings.js:32 -msgid "No credentials selected" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:63 -msgid "No data is available. There are no issues to report." -msgstr "" - -#: client/src/license/license.controller.js:41 -msgid "No file selected." -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:64 -msgid "No hosts with failures. Click for details." -msgstr "" - -#: client/features/templates/templates.strings.js:33 -msgid "No inventory selected" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:49 -msgid "No inventory sync failures. Click for details." -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:16 -msgid "No job data" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:75 -msgid "No job data available." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:22 -msgid "No job failures" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:54 -msgid "No job templates were recently used." -msgstr "" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:44 -msgid "No jobs were recently run." -msgstr "" - -#: client/src/teams/teams.form.js:124 -#: client/src/users/users.form.js:194 -msgid "No permissions have been granted" -msgstr "" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:17 -msgid "No recent job data available for this host." -msgstr "" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:75 -msgid "No recent job data available for this inventory." -msgstr "" - -#: client/src/notifications/notification-templates-list/list.controller.js:86 -msgid "No recent notifications." -msgstr "" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:36 -#: client/src/shared/form-generator.js:1888 -#: client/src/shared/list-generator/list-generator.factory.js:240 -msgid "No records matched your search." -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:16 -msgid "No schedules exist" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:348 -#: client/src/job-submission/job-submission.partial.html:353 -msgid "None selected" -msgstr "" - -#: client/src/users/add/users-add.controller.js:10 -#: client/src/users/edit/users-edit.controller.js:10 -#: client/src/users/list/users-list.controller.js:10 -msgid "Normal User" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:93 -msgid "Not configured for SCM" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:54 -msgid "Not configured for inventory sync." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -msgid "Note that only hosts directly in this group can be disassociated. Hosts in sub-groups must be disassociated directly from the sub-group level that they belong." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:288 -#: client/src/notifications/notificationTemplates.form.js:289 -#: client/src/notifications/notificationTemplates.form.js:472 -#: client/src/notifications/notificationTemplates.form.js:473 -msgid "Notification Color" -msgstr "" - -#: client/src/notifications/notification-templates-list/list.controller.js:131 -msgid "Notification Failed." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:277 -msgid "Notification Label" -msgstr "" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:30 -msgid "Notification Templates" -msgstr "" - -#: client/lib/components/components.strings.js:72 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:20 -#: client/src/management-jobs/notifications/notification.route.js:21 -#: client/src/notifications/notifications.list.js:17 -msgid "Notifications" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:302 -msgid "Notify Channel" -msgstr "" - -#: client/lib/services/base-string.service.js:67 -#: client/src/inventories-hosts/hosts/hosts.partial.html:55 -#: client/src/job-submission/job-submission.partial.html:269 -#: client/src/partials/survey-maker-modal.html:27 -#: client/src/shared/form-generator.js:547 -#: client/src/shared/form-generator.js:782 -#: client/src/shared/generator-helpers.js:554 -msgid "OFF" -msgstr "" - -#: client/lib/services/base-string.service.js:62 -#: client/src/network-ui/network-nav/network.nav.view.html:93 -msgid "OK" -msgstr "" - -#: client/lib/services/base-string.service.js:66 -#: client/src/inventories-hosts/hosts/hosts.partial.html:54 -#: client/src/job-submission/job-submission.partial.html:267 -#: client/src/partials/survey-maker-modal.html:26 -#: client/src/shared/form-generator.js:543 -#: client/src/shared/form-generator.js:780 -#: client/src/shared/generator-helpers.js:550 -msgid "ON" -msgstr "" - -#: client/lib/components/components.strings.js:10 -msgid "OPTIONS" -msgstr "" - -#: client/features/applications/applications.strings.js:29 -msgid "ORG" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:29 -#: client/src/organizations/list/organizations-list.partial.html:6 -#: client/src/organizations/main.js:51 -msgid "ORGANIZATIONS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:157 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:162 -msgid "Only Group By" -msgstr "" - -#: client/src/credentials/credentials.form.js:379 -msgid "OpenStack domains define administrative boundaries. It is only needed for Keystone v3 authentication URLs. Common scenarios include:" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:230 -#: client/src/templates/workflows.form.js:79 -msgid "Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:453 -#: client/src/partials/logviewer.html:7 -#: client/src/templates/job_templates/job-template.form.js:270 -#: client/src/templates/workflows.form.js:97 -msgid "Options" -msgstr "" - -#: client/src/credentials/credentials.form.js:46 -#: client/src/credentials/credentials.form.js:53 -#: client/src/inventories-hosts/inventories/inventory.list.js:60 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:33 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:41 -#: client/src/inventory-scripts/inventory-scripts.form.js:40 -#: client/src/inventory-scripts/inventory-scripts.list.js:27 -#: client/src/notifications/notificationTemplates.form.js:44 -#: client/src/projects/projects.form.js:42 -#: client/src/projects/projects.form.js:48 -#: client/src/teams/teams.form.js:40 -#: client/src/teams/teams.list.js:30 -#: client/src/templates/workflows.form.js:55 -#: client/src/templates/workflows.form.js:61 -#: client/src/users/users.form.js:43 -msgid "Organization" -msgstr "" - -#: client/lib/components/components.strings.js:68 -#: client/lib/models/models.strings.js:35 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:136 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:64 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:31 -#: client/src/users/users.form.js:135 -msgid "Organizations" -msgstr "" - -#: client/features/templates/templates.strings.js:26 -#: client/src/job-submission/job-submission.partial.html:19 -msgid "Other Prompts" -msgstr "" - -#: client/src/credentials/credentials.form.js:79 -msgid "Others (Cloud Providers)" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:283 -msgid "" -"Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:218 -msgid "Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:300 -msgid "" -"Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:266 -msgid "" -"Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration\n" -" \n" -" view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:242 -msgid "Override variables found in vmware.ini and used by the inventory update script. For a detailed description of these variables" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:328 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:333 -msgid "Overwrite" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:340 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:345 -msgid "Overwrite Variables" -msgstr "" - -#: client/src/credentials/credentials.list.js:40 -msgid "Owners" -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:68 -msgid "PASSWORD" -msgstr "" - -#: client/features/credentials/legacy.credentials.js:117 -msgid "PERMISSIONS" -msgstr "" - -#: client/src/partials/job-template-details.html:2 -msgid "PLAYBOOK" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:45 -msgid "PLEASE ADD A SURVEY PROMPT." -msgstr "" - -#: client/src/organizations/list/organizations-list.partial.html:46 -#: client/src/shared/form-generator.js:1894 -#: client/src/shared/list-generator/list-generator.factory.js:248 -msgid "PLEASE ADD ITEMS TO THIS LIST" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:43 -msgid "PREVIEW" -msgstr "" - -#: client/src/partials/job-template-details.html:2 -msgid "PROJECT" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:8 -#: client/src/organizations/linkout/organizations-linkout.route.js:196 -#: client/src/organizations/list/organizations-list.controller.js:73 -#: client/src/projects/main.js:86 -#: client/src/projects/projects.list.js:14 -#: client/src/projects/projects.list.js:15 -msgid "PROJECTS" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:33 -msgid "Page" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:232 -msgid "Pagerduty subdomain" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:358 -msgid "Pass extra command line variables to the playbook. Provide key/value pairs using either YAML or JSON. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/templates/workflows.form.js:90 -msgid "Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for example syntax." -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:139 -msgid "Pass extra command line variables. This is the %s or %s command line parameter for %s. Provide key/value pairs using either YAML or JSON." -msgstr "" - -#: client/src/credentials/credentials.form.js:226 -#: client/src/credentials/factories/become-method-change.factory.js:21 -#: client/src/credentials/factories/become-method-change.factory.js:40 -#: client/src/credentials/factories/become-method-change.factory.js:48 -#: client/src/credentials/factories/become-method-change.factory.js:68 -#: client/src/credentials/factories/become-method-change.factory.js:78 -#: client/src/credentials/factories/become-method-change.factory.js:88 -#: client/src/credentials/factories/kind-change.factory.js:105 -#: client/src/credentials/factories/kind-change.factory.js:125 -#: client/src/credentials/factories/kind-change.factory.js:135 -#: client/src/credentials/factories/kind-change.factory.js:145 -#: client/src/credentials/factories/kind-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:78 -#: client/src/credentials/factories/kind-change.factory.js:97 -#: client/src/job-submission/job-submission.partial.html:104 -#: client/src/notifications/shared/type-change.service.js:30 -#: client/src/users/users.form.js:71 -msgid "Password" -msgstr "" - -#: client/src/credentials/factories/kind-change.factory.js:58 -msgid "Password (API Key)" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:20 -msgid "Past 24 Hours" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:15 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:26 -msgid "Past Month" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:23 -msgid "Past Week" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:29 -#: client/src/credentials/factories/kind-change.factory.js:86 -msgid "Paste the contents of the PEM file associated with the service account email." -msgstr "" - -#: client/src/credentials/factories/kind-change.factory.js:51 -msgid "Paste the contents of the SSH private key file." -msgstr "" - -#: client/src/credentials/factories/kind-change.factory.js:26 -msgid "Paste the contents of the SSH private key file.%s or click to close%s" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:134 -msgid "Pending Delete" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:8 -msgid "Period" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:31 -#: client/src/users/add/users-add.controller.js:43 -msgid "Permission Error" -msgstr "" - -#: client/features/credentials/credentials.strings.js:14 -#: client/features/credentials/legacy.credentials.js:63 -#: client/src/credentials/credentials.form.js:439 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:104 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:106 -#: client/src/projects/projects.form.js:247 -#: client/src/teams/teams.form.js:120 -#: client/src/templates/job_templates/job-template.form.js:397 -#: client/src/templates/workflows.form.js:140 -#: client/src/users/users.form.js:190 -msgid "Permissions" -msgstr "" - -#: client/src/shared/form-generator.js:1078 -#: client/src/templates/job_templates/job-template.form.js:107 -#: client/src/templates/job_templates/job-template.form.js:115 -msgid "Playbook" -msgstr "" - -#: client/src/projects/projects.form.js:90 -msgid "Playbook Directory" -msgstr "" - -#: client/features/templates/templates.strings.js:59 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:52 -msgid "Playbook Run" -msgstr "" - -#: client/lib/components/components.strings.js:99 -msgid "Please add items to this list." -msgstr "" - -#: client/src/users/users.form.js:129 -msgid "Please add user to an Organization." -msgstr "" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:100 -msgid "Please assign roles to the selected resources" -msgstr "" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:60 -msgid "Please assign roles to the selected users/teams" -msgstr "" - -#: client/src/license/license.partial.html:84 -msgid "Please click the button below to visit Ansible's website to get a Tower license key." -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:27 -msgid "Please click the icon to edit the host filter." -msgstr "" - -#: client/src/shared/form-generator.js:870 -#: client/src/shared/form-generator.js:965 -msgid "Please enter a URL that begins with ssh, http or https. The URL may not contain the '@' character." -msgstr "" - -#: client/src/shared/form-generator.js:1167 -msgid "Please enter a number greater than %d and less than %d." -msgstr "" - -#: client/src/shared/form-generator.js:1169 -msgid "Please enter a number greater than %d." -msgstr "" - -#: client/src/shared/form-generator.js:1161 -msgid "Please enter a number." -msgstr "" - -#: client/features/templates/templates.strings.js:38 -#: client/src/job-submission/job-submission.partial.html:112 -#: client/src/job-submission/job-submission.partial.html:126 -#: client/src/job-submission/job-submission.partial.html:140 -#: client/src/job-submission/job-submission.partial.html:154 -#: client/src/login/loginModal/loginModal.partial.html:78 -msgid "Please enter a password." -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:58 -msgid "Please enter a username." -msgstr "" - -#: client/src/shared/form-generator.js:860 -#: client/src/shared/form-generator.js:955 -msgid "Please enter a valid email address." -msgstr "" - -#: client/lib/components/components.strings.js:15 -#: client/src/shared/form-generator.js:1025 -#: client/src/shared/form-generator.js:855 -#: client/src/shared/form-generator.js:950 -msgid "Please enter a value." -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/job-submission/job-submission.partial.html:311 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:14 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:19 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:30 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:36 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:42 -msgid "Please enter an answer between" -msgstr "" - -#: client/features/templates/templates.strings.js:58 -#: client/src/job-submission/job-submission.partial.html:316 -msgid "Please enter an answer that is a decimal number." -msgstr "" - -#: client/features/templates/templates.strings.js:57 -#: client/src/job-submission/job-submission.partial.html:310 -msgid "Please enter an answer that is a valid integer." -msgstr "" - -#: client/features/templates/templates.strings.js:55 -#: client/src/job-submission/job-submission.partial.html:288 -#: client/src/job-submission/job-submission.partial.html:293 -#: client/src/job-submission/job-submission.partial.html:304 -#: client/src/job-submission/job-submission.partial.html:309 -#: client/src/job-submission/job-submission.partial.html:315 -msgid "Please enter an answer." -msgstr "" - -#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:54 -msgid "Please save before adding a survey to this job template." -msgstr "" - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:51 -msgid "Please save before adding a survey to this workflow." -msgstr "" - -#: client/src/notifications/notifications.list.js:15 -msgid "Please save before adding notifications." -msgstr "" - -#: client/src/organizations/organizations.form.js:80 -#: client/src/teams/teams.form.js:72 -msgid "Please save before adding users." -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:100 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:102 -#: client/src/projects/projects.form.js:239 -#: client/src/teams/teams.form.js:116 -#: client/src/templates/job_templates/job-template.form.js:390 -#: client/src/templates/workflows.form.js:133 -msgid "Please save before assigning permissions." -msgstr "" - -#: client/src/users/users.form.js:127 -#: client/src/users/users.form.js:186 -msgid "Please save before assigning to organizations." -msgstr "" - -#: client/src/users/users.form.js:155 -msgid "Please save before assigning to teams." -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:147 -msgid "Please save before creating groups." -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:156 -msgid "Please save before creating hosts." -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:112 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:86 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:111 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:112 -msgid "Please save before defining groups." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:94 -msgid "Please save before defining hosts." -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:165 -msgid "Please save before defining inventory sources." -msgstr "" - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:50 -msgid "Please save before defining the workflow graph." -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:121 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:120 -msgid "Please save before viewing Insights." -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:105 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:104 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:105 -msgid "Please save before viewing facts." -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:146 -msgid "Please save before viewing hosts." -msgstr "" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 -msgid "Please select Users / Teams from the lists below." -msgstr "" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 -msgid "Please select Users from the list below." -msgstr "" - -#: client/src/shared/form-generator.js:1202 -msgid "Please select a number between" -msgstr "" - -#: client/src/shared/form-generator.js:1198 -msgid "Please select a number." -msgstr "" - -#: client/features/templates/templates.strings.js:56 -msgid "Please select a value" -msgstr "" - -#: client/src/shared/form-generator.js:1090 -#: client/src/shared/form-generator.js:1158 -#: client/src/shared/form-generator.js:1279 -#: client/src/shared/form-generator.js:1387 -msgid "Please select a value." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:77 -msgid "Please select an Inventory or check the Prompt on launch option." -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:26 -msgid "Please select an organization before editing the host filter." -msgstr "" - -#: client/src/shared/form-generator.js:1195 -msgid "Please select at least one value." -msgstr "" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:30 -msgid "Please select resources from the lists below." -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:47 -msgid "Populate the hosts for this inventory by using a search filter." -msgstr "" - -#: client/src/notifications/shared/type-change.service.js:29 -msgid "Port" -msgstr "" - -#: client/lib/components/components.strings.js:62 -msgid "Portal Mode" -msgstr "" - -#: client/features/templates/templates.strings.js:28 -msgid "Preview" -msgstr "" - -#: client/src/credentials/credentials.form.js:257 -#: client/src/credentials/factories/kind-change.factory.js:21 -#: client/src/credentials/factories/kind-change.factory.js:45 -msgid "Private Key" -msgstr "" - -#: client/features/templates/templates.strings.js:41 -#: client/src/credentials/credentials.form.js:264 -#: client/src/job-submission/job-submission.partial.html:118 -msgid "Private Key Passphrase" -msgstr "" - -#: client/src/credentials/credentials.form.js:279 -#: client/src/credentials/credentials.form.js:283 -msgid "Privilege Escalation" -msgstr "" - -#: client/features/templates/templates.strings.js:42 -#: client/src/credentials/credentials.form.js:305 -#: client/src/job-submission/job-submission.partial.html:132 -msgid "Privilege Escalation Password" -msgstr "" - -#: client/src/credentials/credentials.form.js:295 -msgid "Privilege Escalation Username" -msgstr "" - -#: client/features/jobs/jobs.strings.js:14 -#: client/features/templates/templates.strings.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:87 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:93 -#: client/src/templates/job_templates/job-template.form.js:100 -#: client/src/templates/job_templates/job-template.form.js:91 -msgid "Project" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:53 -#: client/src/credentials/factories/kind-change.factory.js:110 -msgid "Project (Tenant Name)" -msgstr "" - -#: client/src/projects/projects.form.js:76 -#: client/src/projects/projects.form.js:84 -msgid "Project Base Path" -msgstr "" - -#: client/src/credentials/credentials.form.js:365 -msgid "Project Name" -msgstr "" - -#: client/src/projects/projects.form.js:101 -msgid "Project Path" -msgstr "" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:66 -msgid "Project Sync Failures" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:187 -msgid "Project lookup failed. GET returned:" -msgstr "" - -#: client/lib/components/components.strings.js:63 -#: client/lib/models/models.strings.js:40 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:115 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:47 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:32 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:61 -#: client/src/organizations/linkout/organizations-linkout.route.js:207 -msgid "Projects" -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:18 -msgid "Promote group" -msgid_plural "Promote groups" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:43 -msgid "Promote groups" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:32 -msgid "Promote groups and hosts" -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:20 -msgid "Promote host" -msgid_plural "Promote hosts" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:54 -msgid "Promote hosts" -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:10 -msgid "Promote {{ group }} and {{ host }}" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:27 -msgid "Prompt" -msgstr "" - -#: client/lib/components/components.strings.js:34 -#: client/src/templates/job_templates/job-template.form.js:138 -#: client/src/templates/job_templates/job-template.form.js:168 -#: client/src/templates/job_templates/job-template.form.js:185 -#: client/src/templates/job_templates/job-template.form.js:202 -#: client/src/templates/job_templates/job-template.form.js:219 -#: client/src/templates/job_templates/job-template.form.js:265 -#: client/src/templates/job_templates/job-template.form.js:365 -#: client/src/templates/job_templates/job-template.form.js:60 -#: client/src/templates/job_templates/job-template.form.js:86 -msgid "Prompt on launch" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:238 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:252 -msgid "Provide a comma-separated list of filter expressions." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:254 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:270 -msgid "Provide a comma-separated list of filter expressions. Hosts are imported when all of the filters match. Refer to Ansible Tower documentation for more detail." -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:50 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:49 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:49 -msgid "Provide a host name, ip address, or ip address:port. Examples include:" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:162 -msgid "Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. Multiple patterns are allowed. Refer to Ansible documentation for more information and examples on patterns." -msgstr "" - -#: client/features/credentials/credentials.strings.js:22 -msgid "Provide account information using Google Compute Engine JSON credentials file." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:196 -msgid "Provide environment variables to pass to the custom inventory script." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:257 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:273 -msgid "Provide the named URL encoded name or id of the remote Tower inventory to be imported." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:321 -#: client/src/templates/job_templates/job-template.form.js:329 -msgid "Provisioning Callback URL" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Purple" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:131 -msgid "RADIUS" -msgstr "" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:4 -msgid "RECENT JOB RUNS" -msgstr "" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:40 -msgid "RECENTLY RUN JOBS" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:50 -msgid "RECENTLY USED JOB TEMPLATES" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:4 -msgid "RECENTLY USED TEMPLATES" -msgstr "" - -#: client/src/activity-stream/streams.list.js:54 -#: client/src/inventories-hosts/hosts/host.list.js:102 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:46 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:113 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:54 -#: client/src/projects/projects.list.js:71 -#: client/src/scheduler/schedules.list.js:69 -msgid "REFRESH" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:23 -msgid "REFRESH TOKEN" -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:48 -msgid "RELATED FIELDS:" -msgstr "" - -#: client/src/shared/directives.js:94 -msgid "REMOVE" -msgstr "" - -#: client/lib/components/components.strings.js:7 -msgid "REPLACE" -msgstr "" - -#: client/features/output/jobs.strings.js:8 -msgid "RESULTS" -msgstr "" - -#: client/features/templates/templates.strings.js:34 -#: client/lib/components/components.strings.js:8 -#: client/src/job-submission/job-submission.partial.html:44 -#: client/src/job-submission/job-submission.partial.html:87 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:60 -msgid "REVERT" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:25 -#: client/src/credentials/factories/kind-change.factory.js:82 -msgid "RSA Private Key" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.route.js:28 -msgid "RUN COMMAND" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:101 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:56 -msgid "RUN COMMANDS" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Random" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:30 -msgid "Read" -msgstr "" - -#: client/src/workflow-results/workflow-results.partial.html:155 -msgid "Read only view of extra variables added to the workflow." -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:49 -msgid "Read-only view of extra variables added to the job template." -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:26 -msgid "Recent Notifications" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:98 -msgid "Recipient List" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Red" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:47 -msgid "Refer to the Ansible Tower documentation for further syntax and examples." -msgstr "" - -#: client/src/activity-stream/streams.list.js:51 -#: client/src/bread-crumb/bread-crumb.partial.html:6 -#: client/src/inventories-hosts/hosts/host.list.js:98 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:42 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:109 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:50 -#: client/src/projects/projects.list.js:67 -#: client/src/scheduler/schedules.list.js:65 -msgid "Refresh the page" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:231 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:244 -msgid "Region:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:131 -msgid "Regions" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:65 -msgid "Related Groups" -msgstr "" - -#: client/lib/components/components.strings.js:89 -msgid "Relaunch On" -msgstr "" - -#: client/lib/components/components.strings.js:88 -msgid "Relaunch using host parameters" -msgstr "" - -#: client/lib/components/components.strings.js:87 -#: client/src/workflow-results/workflow-results.partial.html:29 -msgid "Relaunch using the same parameters" -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:180 -msgid "Remediate Inventory" -msgstr "" - -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:102 -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:103 -#: client/src/teams/teams.form.js:145 -#: client/src/users/users.form.js:225 -msgid "Remove" -msgstr "" - -#: client/src/projects/projects.form.js:159 -msgid "Remove any local modifications prior to performing an update." -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:149 -msgid "Repeat frequency" -msgstr "" - -#: client/src/license/license.partial.html:89 -msgid "Request License" -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:291 -msgid "Required" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:154 -msgid "Reset" -msgstr "" - -#: client/lib/components/components.strings.js:81 -msgid "Resources" -msgstr "" - -#: client/features/templates/templates.strings.js:88 -#: client/src/scheduler/schedules.list.js:24 -msgid "Resources are missing from this template." -msgstr "" - -#: client/lib/services/base-string.service.js:85 -msgid "Return" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:26 -msgid "Returned status:" -msgstr "" - -#: client/src/shared/form-generator.js:699 -msgid "Revert" -msgstr "" - -#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:59 -#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-ldap1.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-ldap2.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-ldap3.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-ldap4.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-ldap5.form.js:102 -#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:34 -#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:121 -#: client/src/configuration/auth-form/sub-forms/auth-tacacs.form.js:47 -#: client/src/configuration/jobs-form/configuration-jobs.form.js:73 -#: client/src/configuration/system-form/sub-forms/system-activity-stream.form.js:26 -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:74 -#: client/src/configuration/system-form/sub-forms/system-misc.form.js:53 -#: client/src/configuration/ui-form/configuration-ui.form.js:36 -msgid "Revert all to default" -msgstr "" - -#: client/src/projects/projects.list.js:50 -msgid "Revision" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:154 -#: client/src/projects/edit/projects-edit.controller.js:288 -msgid "Revision #" -msgstr "" - -#: client/features/credentials/legacy.credentials.js:85 -#: client/src/credentials/credentials.form.js:462 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:130 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:132 -#: client/src/organizations/organizations.form.js:109 -#: client/src/projects/projects.form.js:269 -#: client/src/teams/teams.form.js:101 -#: client/src/teams/teams.form.js:138 -#: client/src/templates/workflows.form.js:164 -#: client/src/users/users.form.js:208 -msgid "Role" -msgstr "" - -#: client/src/instance-groups/instance-groups.list.js:26 -msgid "Running Jobs" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:132 -msgid "SAML" -msgstr "" - -#: client/lib/services/base-string.service.js:61 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:17 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:17 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:17 -#: client/src/partials/survey-maker-modal.html:87 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:18 -msgid "SAVE" -msgstr "" - -#: client/src/scheduler/main.js:325 -msgid "SCHEDULED" -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:13 -msgid "SCHEDULED JOBS" -msgstr "" - -#: client/features/jobs/index.view.html:12 -#: client/src/activity-stream/get-target-title.factory.js:38 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:49 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:8 -#: client/src/management-jobs/scheduler/main.js:26 -#: client/src/management-jobs/scheduler/main.js:32 -#: client/src/scheduler/main.js:139 -#: client/src/scheduler/main.js:177 -#: client/src/scheduler/main.js:229 -#: client/src/scheduler/main.js:267 -#: client/src/scheduler/main.js:86 -msgid "SCHEDULES" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:126 -#: client/src/projects/edit/projects-edit.controller.js:261 -msgid "SCM Branch" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:145 -#: client/src/projects/edit/projects-edit.controller.js:279 -msgid "SCM Branch/Tag/Commit" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:166 -#: client/src/projects/edit/projects-edit.controller.js:300 -msgid "SCM Branch/Tag/Revision" -msgstr "" - -#: client/src/projects/projects.form.js:160 -msgid "SCM Clean" -msgstr "" - -#: client/src/projects/projects.form.js:171 -msgid "SCM Delete" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:20 -#: client/src/credentials/factories/kind-change.factory.js:77 -msgid "SCM Private Key" -msgstr "" - -#: client/src/projects/projects.form.js:56 -msgid "SCM Type" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:49 -#: client/src/projects/projects.form.js:181 -msgid "SCM Update" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:257 -msgid "SCM Update Cancel" -msgstr "" - -#: client/src/projects/projects.form.js:151 -msgid "SCM Update Options" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:138 -#: client/src/projects/list/projects-list.controller.js:86 -msgid "SCM update currently running" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js:36 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:84 -msgid "SELECT" -msgstr "" - -#: client/features/credentials/credentials.strings.js:20 -msgid "SELECT A CREDENTIAL TYPE" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:19 -msgid "SELECT AN APPLICATION" -msgstr "" - -#: client/features/applications/applications.strings.js:34 -#: client/features/credentials/credentials.strings.js:19 -msgid "SELECT AN ORGANIZATION" -msgstr "" - -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:6 -msgid "SELECT GROUPS" -msgstr "" - -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:6 -msgid "SELECT HOSTS" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:28 -msgid "SELECT INSTANCE" -msgstr "" - -#: client/features/templates/templates.strings.js:31 -msgid "SELECTED" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:29 -#: client/src/job-submission/job-submission.partial.html:56 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:18 -msgid "SELECTED:" -msgstr "" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 -msgid "SETTING CATEGORY" -msgstr "" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:24 -msgid "SETTING NAME" -msgstr "" - -#: client/lib/components/components.strings.js:11 -#: client/lib/services/base-string.service.js:64 -msgid "SHOW" -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:97 -msgid "SIGN IN" -msgstr "" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html:2 -msgid "SIGN IN WITH" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.list.js:110 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:14 -msgid "SMART INVENTORY" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js:26 -msgid "SOURCES" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:89 -#: client/src/credentials/factories/kind-change.factory.js:146 -msgid "SSH Key" -msgstr "" - -#: client/features/templates/templates.strings.js:40 -msgid "SSH Password" -msgstr "" - -#: client/src/credentials/credentials.form.js:255 -msgid "SSH key description" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:446 -msgid "SSL Connection" -msgstr "" - -#: client/src/credentials/credentials.form.js:119 -#: client/src/credentials/credentials.form.js:127 -msgid "STS Token" -msgstr "" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:61 -msgid "SUCCESSFUL" -msgstr "" - -#: client/src/partials/survey-maker-modal.html:24 -msgid "SURVEY" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:62 -msgid "SYNC ALL" -msgstr "" - -#: client/src/system-tracking/system-tracking.route.js:18 -msgid "SYSTEM TRACKING" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:70 -#: client/src/credentials/factories/kind-change.factory.js:127 -msgid "Satellite 6 URL" -msgstr "" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:110 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:193 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:158 -#: client/src/shared/form-generator.js:1700 -msgid "Save" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:104 -#: client/src/configuration/configuration.controller.js:242 -#: client/src/configuration/configuration.controller.js:319 -#: client/src/configuration/system-form/configuration-system.controller.js:68 -msgid "Save changes" -msgstr "" - -#: client/src/license/license.partial.html:140 -msgid "Save successful!" -msgstr "" - -#: client/src/templates/templates.list.js:93 -msgid "Schedule" -msgstr "" - -#: client/src/management-jobs/card/card.partial.html:28 -msgid "Schedule Management Job" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:77 -msgid "Schedule SCM revision updates" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:7 -msgid "Schedule inventory syncs" -msgstr "" - -#: client/src/templates/templates.list.js:96 -msgid "Schedule job template runs" -msgstr "" - -#: client/lib/components/components.strings.js:61 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:34 -msgid "Schedules" -msgstr "" - -#: client/src/shared/smart-search/smart-search.controller.js:108 -#: client/src/shared/smart-search/smart-search.controller.js:32 -msgid "Search" -msgstr "" - -#: client/src/credentials/credentials.form.js:104 -msgid "Secret Key" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:232 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:245 -msgid "Security Group:" -msgstr "" - -#: client/src/credentials/credentials.form.js:124 -msgid "Security Token Service (STS) is a web service that enables you to request temporary, limited-privilege credentials for AWS Identity and Access Management (IAM) users." -msgstr "" - -#: client/src/shared/form-generator.js:1704 -msgid "Select" -msgstr "" - -#: client/src/organizations/organizations.form.js:48 -#: client/src/projects/projects.form.js:209 -#: client/src/templates/job_templates/job-template.form.js:237 -msgid "Select Ansible Environment" -msgstr "" - -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:5 -msgid "Select Instance Groups" -msgstr "" - -#: client/src/job-submission/job-submission.directive.js:65 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:66 -msgid "Select a credential" -msgstr "" - -#: client/src/access/add-rbac-user-team/rbac-user-team.controller.js:68 -msgid "Select a role" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:29 -msgid "Select a scope" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:53 -msgid "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or a selection of multiple groups." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:98 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:53 -msgid "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:111 -msgid "Select an inventory source by clicking the check box beside it. The inventory source can be a single host or a selection of multiple hosts." -msgstr "" - -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:109 -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:134 -#: client/src/configuration/ui-form/configuration-ui.controller.js:95 -msgid "Select commands" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:132 -msgid "Select credentials that allow Tower to access the nodes this job will be ran against. You can only select one credential of each type. For machine credentials (SSH), checking \"Prompt on launch\" without selecting credentials will require you to select a machine credential at run time. If you select credentials and check \"Prompt on launch\", the selected credential(s) become the defaults that can be updated at run time." -msgstr "" - -#: client/src/projects/projects.form.js:99 -msgid "Select from the list of directories found in the Project Base Path. Together the base path and the playbook directory provide the full path used to locate playbooks." -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:343 -#: client/src/configuration/auth-form/configuration-auth.controller.js:362 -msgid "Select group types" -msgstr "" - -#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:24 -msgid "Select roles" -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:56 -msgid "Select the Instance Groups for this Inventory to run on." -msgstr "" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:63 -msgid "Select the Instance Groups for this Inventory to run on. Refer to the Ansible Tower documentation for more detail." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:249 -msgid "Select the Instance Groups for this Job Template to run on." -msgstr "" - -#: client/src/organizations/organizations.form.js:40 -msgid "Select the Instance Groups for this Organization to run on." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:239 -msgid "Select the custom Python virtual environment for this job template to run on." -msgstr "" - -#: client/src/organizations/organizations.form.js:51 -msgid "Select the custom Python virtual environment for this organization to run on." -msgstr "" - -#: client/src/projects/projects.form.js:211 -msgid "Select the custom Python virtual environment for this project to run on." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:79 -msgid "Select the inventory containing the hosts you want this job to manage." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:122 -msgid "Select the inventory file to be synced by this source. You can select from the dropdown or enter a file within the input." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:114 -msgid "Select the playbook to be executed by this job." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:99 -msgid "Select the project containing the playbook you want this job to execute." -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:197 -msgid "Select types" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:224 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:237 -msgid "Select which groups to create automatically." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:110 -msgid "Sender Email" -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:24 -#: client/src/credentials/factories/kind-change.factory.js:81 -msgid "Service Account Email Address" -msgstr "" - -#: client/features/credentials/credentials.strings.js:21 -msgid "Service Account JSON File" -msgstr "" - -#: client/lib/components/components.strings.js:77 -msgid "Settings" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:108 -#: client/src/job-submission/job-submission.partial.html:122 -#: client/src/job-submission/job-submission.partial.html:136 -#: client/src/job-submission/job-submission.partial.html:150 -#: client/src/job-submission/job-submission.partial.html:299 -#: client/src/shared/form-generator.js:885 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:24 -msgid "Show" -msgstr "" - -#: client/features/templates/templates.strings.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:115 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:118 -#: client/src/templates/job_templates/job-template.form.js:256 -#: client/src/templates/job_templates/job-template.form.js:259 -msgid "Show Changes" -msgstr "" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:33 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:44 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:55 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:76 -msgid "Sign in with %s" -msgstr "" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:63 -msgid "Sign in with %s Organizations" -msgstr "" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:61 -msgid "Sign in with %s Teams" -msgstr "" - -#: client/features/templates/templates.strings.js:46 -#: client/src/job-submission/job-submission.partial.html:245 -#: client/src/templates/job_templates/job-template.form.js:207 -#: client/src/templates/job_templates/job-template.form.js:214 -msgid "Skip Tags" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:213 -msgid "Skip tags are useful when you have a large playbook, and you want to skip specific parts of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:44 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:48 -msgid "Smart Host Filter" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:85 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:71 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/shared/form-generator.js:1465 -msgid "Smart Inventory" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:44 -msgid "Solvable With Playbook" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:57 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:64 -msgid "Source" -msgstr "" - -#: client/src/credentials/credentials.form.js:75 -msgid "Source Control" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:47 -#: client/src/projects/projects.form.js:26 -msgid "Source Details" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:192 -#: client/src/notifications/notificationTemplates.form.js:193 -msgid "Source Phone Number" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:136 -msgid "Source Regions" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:209 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:216 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:233 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:240 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:257 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:264 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:274 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:281 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:291 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:298 -msgid "Source Variables" -msgstr "" - -#: client/src/partials/logviewer.html:9 -msgid "Source Vars" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:34 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:167 -msgid "Sources" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:330 -msgid "Specify HTTP Headers in JSON format. Refer to the Ansible Tower documentation for example syntax." -msgstr "" - -#: client/src/credentials/credentials.form.js:285 -msgid "Specify a method for %s operations. This is equivalent to specifying the %s parameter, where %s could be %s" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:478 -msgid "Specify a notification color. Acceptable colors are hex color code (example: #3af or #789abc) ." -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:292 -msgid "Specify a notification color. Acceptable colors are: yellow, green, red purple, gray or random." -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:20 -msgid "Specify a scope for the token's access" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:253 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:269 -msgid "Specify which groups to create automatically. Group names will be created similar to the options selected. If blank, all groups above are created. Refer to Ansible Tower documentation for more detail." -msgstr "" - -#: client/src/partials/logviewer.html:5 -msgid "Standard Out" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:41 -msgid "Start Date" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:56 -msgid "Start Time" -msgstr "" - -#: client/lib/components/components.strings.js:95 -msgid "Start a job using this template" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:6 -msgid "Start sync process" -msgstr "" - -#: client/features/jobs/jobs.strings.js:8 -msgid "Started" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:53 -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:55 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:43 -#: client/src/notifications/notification-templates-list/list.controller.js:71 -#: client/src/partials/logviewer.html:4 -msgid "Status" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:4 -msgid "Sub Category" -msgstr "" - -#: client/src/license/license.partial.html:139 -msgid "Submit" -msgstr "" - -#: client/src/license/license.partial.html:27 -msgid "Subscription" -msgstr "" - -#: client/src/credentials/credentials.form.js:151 -#: client/src/credentials/credentials.form.js:162 -msgid "Subscription ID" -msgstr "" - -#: client/src/credentials/credentials.form.js:161 -msgid "Subscription ID is an Azure construct, which is mapped to a username." -msgstr "" - -#: client/src/notifications/notifications.list.js:39 -msgid "Success" -msgstr "" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:77 -msgid "Successful" -msgstr "" - -#: client/features/templates/templates.strings.js:27 -#: client/src/job-submission/job-submission.partial.html:20 -msgid "Survey" -msgstr "" - -#: client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js:62 -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:262 -msgid "Surveys allow users to be prompted at job launch with a series of questions related to the job. This allows for variables to be defined that affect the playbook run at time of launch." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:58 -msgid "Sync all inventory sources" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:29 -msgid "Sync canceled. Click to view log." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:35 -msgid "Sync completed. Click to view log." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:32 -msgid "Sync failed. Click to view log." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "Sync not performed. Click" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:38 -msgid "Sync pending." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:45 -msgid "Sync running" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:46 -msgid "Sync running. Click to view log." -msgstr "" - -#: client/src/configuration/configuration.partial.html:29 -msgid "System" -msgstr "" - -#: client/src/users/add/users-add.controller.js:12 -#: client/src/users/edit/users-edit.controller.js:12 -#: client/src/users/list/users-list.controller.js:12 -msgid "System Administrator" -msgstr "" - -#: client/src/users/add/users-add.controller.js:11 -#: client/src/users/edit/users-edit.controller.js:11 -#: client/src/users/list/users-list.controller.js:11 -msgid "System Auditor" -msgstr "" - -#: client/src/configuration/configuration.partial.html:3 -msgid "System auditors have read-only permissions in this section." -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:133 -msgid "TACACS+" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:23 -#: client/src/organizations/linkout/organizations-linkout.route.js:98 -#: client/src/organizations/list/organizations-list.controller.js:61 -#: client/src/teams/main.js:65 -#: client/src/teams/teams.list.js:14 -#: client/src/teams/teams.list.js:15 -msgid "TEAMS" -msgstr "" - -#: client/features/templates/routes/templatesList.route.js:12 -#: client/features/templates/templates.strings.js:12 -#: client/features/templates/templates.strings.js:8 -#: client/src/activity-stream/get-target-title.factory.js:44 -#: client/src/templates/templates.list.js:15 -#: client/src/templates/templates.list.js:16 -msgid "TEMPLATES" -msgstr "" - -#: client/src/instance-groups/instance-groups.list.js:8 -msgid "THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED" -msgstr "" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:104 -msgid "TIME" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:22 -msgid "TOKEN" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:21 -msgid "TOKEN INFORMATION" -msgstr "" - -#: client/features/applications/applications.strings.js:11 -#: client/features/users/tokens/tokens.strings.js:10 -#: client/features/users/tokens/tokens.strings.js:8 -#: client/features/users/tokens/users-tokens-list.route.js:11 -msgid "TOKENS" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:235 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:248 -msgid "Tag None:" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:196 -msgid "Tags are useful when you have a large playbook, and you want to run a specific part of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:233 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:246 -msgid "Tags:" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:309 -#: client/src/notifications/notificationTemplates.form.js:337 -#: client/src/notifications/notificationTemplates.form.js:376 -msgid "Target URL" -msgstr "" - -#: client/features/credentials/legacy.credentials.js:91 -#: client/src/credentials/credentials.form.js:468 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:136 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:138 -#: client/src/projects/projects.form.js:275 -#: client/src/templates/workflows.form.js:170 -msgid "Team Roles" -msgstr "" - -#: client/lib/components/components.strings.js:70 -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:35 -#: client/src/organizations/linkout/organizations-linkout.route.js:109 -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/users/users.form.js:162 -msgid "Teams" -msgstr "" - -#: client/src/templates/templates.list.js:14 -msgid "Template" -msgstr "" - -#: client/features/templates/templates.strings.js:66 -msgid "Template parameter is missing." -msgstr "" - -#: client/lib/components/components.strings.js:67 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:36 -msgid "Templates" -msgstr "" - -#: client/src/credentials/credentials.form.js:337 -msgid "Tenant ID" -msgstr "" - -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:79 -msgid "Test" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:77 -msgid "Test notification" -msgstr "" - -#: client/src/shared/form-generator.js:1395 -#: client/src/shared/form-generator.js:1401 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" - -#: client/lib/components/components.strings.js:47 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:66 -msgid "The Insights Credential for {{inventory.name}} was not found." -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:32 -#: client/src/credentials/factories/kind-change.factory.js:89 -msgid "The Project ID is the GCE assigned identification. It is constructed as two words followed by a three digit number. Such as:" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:339 -msgid "The SCM update process is running." -msgstr "" - -#: client/src/credentials/credentials.form.js:190 -msgid "The email address assigned to the Google Compute Engine %sservice account." -msgstr "" - -#: client/features/output/jobs.strings.js:12 -msgid "The host status bar will update when the job is complete." -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:62 -#: client/src/credentials/factories/kind-change.factory.js:119 -msgid "The host to authenticate with." -msgstr "" - -#: client/src/credentials/factories/kind-change.factory.js:60 -msgid "The host value" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:136 -msgid "The inventory will be in a pending status until the final delete is processed." -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:105 -msgid "The number of parallel or simultaneous processes to use while executing the playbook. Inputting no value will use the default value from the %sansible configuration file%s." -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:151 -msgid "The number of parallel or simultaneous processes to use while executing the playbook. Value defaults to 0. Refer to the Ansible documentation for details about the configuration file." -msgstr "" - -#: client/src/credentials/factories/kind-change.factory.js:59 -msgid "The project value" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:176 -msgid "The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, and then run an update." -msgstr "" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:52 -msgid "The suggested format for variable names is lowercase and underscore-separated (for example, foo_bar, user_id, host_name, etc.). Variable names with spaces are not allowed." -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:124 -msgid "The time must be in HH24:MM:SS format." -msgstr "" - -#: client/lib/services/base-string.service.js:76 -msgid "The {{ resourceType }} is currently being used by other resources." -msgstr "" - -#: client/src/activity-stream/streams.list.js:17 -msgid "There are no events to display at this time" -msgstr "" - -#: client/src/portal-mode/portal-job-templates.list.js:18 -msgid "There are no job templates to display at this time" -msgstr "" - -#: client/features/jobs/jobs.strings.js:16 -msgid "There are no running jobs." -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:152 -msgid "There is no SCM update information available for this project. An update has not yet been completed. If you have not already done so, start an update for this project." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:142 -msgid "There was an error deleting inventory source groups. Returned status:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:132 -msgid "There was an error deleting inventory source hosts. Returned status:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:169 -msgid "There was an error deleting inventory source. Returned status:" -msgstr "" - -#: client/src/configuration/configuration.controller.js:142 -msgid "There was an error getting config values:" -msgstr "" - -#: client/src/configuration/configuration.controller.js:403 -msgid "There was an error resetting value. Returned status:" -msgstr "" - -#: client/src/configuration/configuration.controller.js:584 -msgid "There was an error resetting values. Returned status:" -msgstr "" - -#: client/src/configuration/system-form/configuration-system.controller.js:232 -msgid "There was an error testing the log aggregator. Returned status:" -msgstr "" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:29 -msgid "These are the modules that {{BRAND_NAME}} supports running commands against." -msgstr "" - -#: client/features/templates/templates.strings.js:96 -msgid "This Job Template is missing a default inventory or project. This must be addressed in the Job Template form before this node can be saved." -msgstr "" - -#: client/src/credential-types/credential-types.strings.js:8 -msgid "This credential type is currently being used by one or more credentials. Credentials that use this credential type must be deleted before the credential type can be deleted." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:26 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "This group contains" -msgstr "" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:168 -msgid "This is not a valid number." -msgstr "" - -#: client/src/credentials/factories/become-method-change.factory.js:59 -#: client/src/credentials/factories/kind-change.factory.js:116 -msgid "This is the tenant name. This value is usually the same as the username." -msgstr "" - -#: client/features/templates/templates.strings.js:62 -msgid "This job template has a default {{typeLabel}} credential which must be included or replaced before proceeding." -msgstr "" - -#: client/src/notifications/notifications.list.js:21 -msgid "This list is populated by notification templates added from the %sNotifications%s section" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:4 -msgid "This machine has not checked in with Insights in {{last_check_in}} hours" -msgstr "" - -#: client/src/shared/form-generator.js:755 -msgid "This setting has been set manually in a settings file and is now disabled." -msgstr "" - -#: client/src/users/users.form.js:167 -msgid "This user is not a member of any teams" -msgstr "" - -#: client/src/shared/form-generator.js:865 -#: client/src/shared/form-generator.js:960 -msgid "This value does not match the password you entered previously. Please confirm that password." -msgstr "" - -#: client/src/configuration/configuration.controller.js:609 -msgid "This will reset all configuration values to their factory defaults. Are you sure you want to proceed?" -msgstr "" - -#: client/src/activity-stream/streams.list.js:25 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:14 -#: client/src/notifications/notification-templates-list/list.controller.js:72 -msgid "Time" -msgstr "" - -#: client/src/license/license.partial.html:45 -msgid "Time Remaining" -msgstr "" - -#: client/src/projects/projects.form.js:197 -msgid "Time in seconds to consider a project to be current. During job runs and callbacks the task system will evaluate the timestamp of the latest project update. If it is older than Cache Timeout, it is not considered current, and a new project update will be performed." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:387 -msgid "Time in seconds to consider an inventory sync to be current. During job runs and callbacks the task system will evaluate the timestamp of the latest sync. If it is older than Cache Timeout, it is not considered current, and a new inventory sync will be performed." -msgstr "" - -#: client/src/credentials/credentials.form.js:125 -msgid "To learn more about the IAM STS Token, refer to the %sAmazon documentation%s." -msgstr "" - -#: client/src/shared/form-generator.js:890 -msgid "Toggle the display of plaintext." -msgstr "" - -#: client/src/notifications/shared/type-change.service.js:36 -#: client/src/notifications/shared/type-change.service.js:42 -msgid "Token" -msgstr "" - -#: client/features/applications/applications.strings.js:16 -#: client/src/users/users.form.js:236 -msgid "Tokens" -msgstr "" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:10 -msgid "Total Issues" -msgstr "" - -#: client/src/partials/logviewer.html:6 -msgid "Traceback" -msgstr "" - -#: client/src/credentials/credentials.form.js:60 -#: client/src/credentials/credentials.form.js:84 -#: client/src/inventories-hosts/inventories/inventory.list.js:55 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:41 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:39 -#: client/src/notifications/notifications.list.js:32 -#: client/src/projects/projects.list.js:44 -#: client/src/scheduler/scheduled-jobs.list.js:42 -#: client/src/teams/teams.form.js:133 -#: client/src/templates/templates.list.js:31 -#: client/src/users/users.form.js:203 -msgid "Type" -msgstr "" - -#: client/features/credentials/credentials.strings.js:18 -#: client/src/credentials/credentials.form.js:23 -#: client/src/notifications/notificationTemplates.form.js:26 -msgid "Type Details" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:177 -#: client/src/projects/edit/projects-edit.controller.js:311 -msgid "URL popover text" -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:49 -msgid "USERNAME" -msgstr "" - -#: client/src/activity-stream/get-target-title.factory.js:20 -#: client/src/organizations/linkout/organizations-linkout.route.js:43 -#: client/src/organizations/list/organizations-list.controller.js:55 -#: client/src/users/main.js:67 -#: client/src/users/users.list.js:18 -#: client/src/users/users.list.js:19 -msgid "USERS" -msgstr "" - -#: client/lib/components/components.strings.js:24 -msgid "Unable to Submit" -msgstr "" - -#: client/features/templates/templates.strings.js:87 -msgid "Unable to copy template." -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:43 -msgid "Unable to delete instance group." -msgstr "" - -#: client/features/templates/templates.strings.js:83 -msgid "Unable to delete template." -msgstr "" - -#: client/features/templates/templates.strings.js:85 -msgid "Unable to determine template type." -msgstr "" - -#: client/features/templates/templates.strings.js:68 -msgid "Unable to determine this template's type while copying." -msgstr "" - -#: client/features/templates/templates.strings.js:69 -msgid "Unable to determine this template's type while deleting." -msgstr "" - -#: client/features/templates/templates.strings.js:70 -msgid "Unable to determine this template's type while editing." -msgstr "" - -#: client/features/templates/templates.strings.js:71 -msgid "Unable to determine this template's type while launching." -msgstr "" - -#: client/features/templates/templates.strings.js:72 -msgid "Unable to determine this template's type while scheduling." -msgstr "" - -#: client/features/templates/templates.strings.js:82 -msgid "Unable to edit template." -msgstr "" - -#: client/features/templates/templates.strings.js:84 -msgid "Unable to launch template." -msgstr "" - -#: client/features/templates/templates.strings.js:86 -msgid "Unable to schedule job." -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:33 -msgid "Unavailable" -msgstr "" - -#: client/src/instance-groups/instance-groups.strings.js:32 -msgid "Unavailable to run jobs." -msgstr "" - -#: client/lib/components/components.strings.js:26 -msgid "Unexpected Error" -msgstr "" - -#: client/lib/components/components.strings.js:25 -msgid "Unexpected server error. View the console for more information" -msgstr "" - -#: client/lib/components/components.strings.js:38 -msgid "Unsupported display model type" -msgstr "" - -#: client/lib/components/components.strings.js:30 -msgid "Unsupported input type" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:301 -msgid "Update Not Found" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:321 -msgid "Update Options" -msgstr "" - -#: client/src/projects/projects.form.js:178 -msgid "Update Revision on Launch" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:30 -msgid "Update canceled. Click for details" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:24 -msgid "Update failed. Click for details" -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:339 -msgid "Update in Progress" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:27 -msgid "Update missing. Click for details" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:352 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:357 -msgid "Update on Launch" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:364 -msgid "Update on Project Change" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:370 -msgid "Update on Project Update" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:14 -msgid "Update queued. Click for details" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:18 -msgid "Update running. Click for details" -msgstr "" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:21 -msgid "Update succeeded. Click for details" -msgstr "" - -#: client/src/license/license.partial.html:71 -msgid "Upgrade" -msgstr "" - -#: client/src/templates/job_templates/job-template.form.js:309 -#: client/src/templates/job_templates/job-template.form.js:314 -msgid "Use Fact Cache" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:466 -msgid "Use SSL" -msgstr "" - -#: client/src/notifications/notificationTemplates.form.js:461 -msgid "Use TLS" -msgstr "" - -#: client/src/credentials/credentials.form.js:76 -msgid "Used to check out and synchronize playbook repositories with a remote source control management system such as Git, Subversion (svn), or Mercurial (hg). These credentials are used by Projects." -msgstr "" - -#: client/features/credentials/legacy.credentials.js:80 -#: client/src/credentials/credentials.form.js:457 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:125 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:127 -#: client/src/organizations/organizations.form.js:104 -#: client/src/projects/projects.form.js:264 -#: client/src/teams/teams.form.js:96 -#: client/src/templates/workflows.form.js:159 -msgid "User" -msgstr "" - -#: client/src/configuration/configuration.partial.html:36 -msgid "User Interface" -msgstr "" - -#: client/src/users/users.form.js:98 -msgid "User Type" -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:30 -#: client/src/credentials/factories/become-method-change.factory.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:38 -#: client/src/credentials/factories/kind-change.factory.js:17 -#: client/src/credentials/factories/kind-change.factory.js:41 -#: client/src/credentials/factories/kind-change.factory.js:74 -#: client/src/credentials/factories/kind-change.factory.js:95 -#: client/src/notifications/notificationTemplates.form.js:348 -#: client/src/notifications/notificationTemplates.form.js:387 -#: client/src/notifications/notificationTemplates.form.js:64 -#: client/src/users/users.form.js:61 -#: client/src/users/users.list.js:29 -msgid "Username" -msgstr "" - -#: client/src/credentials/credentials.form.js:80 -msgid "Usernames, passwords, and access keys for authenticating to the specified cloud or infrastructure provider. These are used for smart inventory sources and for cloud provisioning and deployment in playbook runs." -msgstr "" - -#: client/lib/components/components.strings.js:69 -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:37 -#: client/src/organizations/organizations.form.js:86 -#: client/src/teams/teams.form.js:78 -msgid "Users" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:9 -msgid "VARIABLES" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:7 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:7 -msgid "VIEW ALL" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:48 -msgid "VIEW PER PAGE" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:234 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:247 -msgid "VPC ID:" -msgstr "" - -#: client/src/license/license.partial.html:10 -msgid "Valid License" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:68 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:46 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:67 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:67 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:63 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:71 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:77 -msgid "Variables" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:364 -msgid "Vault" -msgstr "" - -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:25 -msgid "Vault ID" -msgstr "" - -#: client/features/templates/templates.strings.js:43 -#: client/src/credentials/credentials.form.js:391 -#: client/src/job-submission/job-submission.partial.html:146 -msgid "Vault Password" -msgstr "" - -#: client/features/templates/templates.strings.js:50 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:82 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:91 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:307 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:314 -#: client/src/job-submission/job-submission.partial.html:183 -#: client/src/templates/job_templates/job-template.form.js:173 -#: client/src/templates/job_templates/job-template.form.js:180 -msgid "Verbosity" -msgstr "" - -#: client/src/license/license.partial.html:15 -msgid "Version" -msgstr "" - -#: client/src/activity-stream/streams.list.js:63 -#: client/src/credential-types/credential-types.list.js:64 -#: client/src/credentials/credentials.list.js:82 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:58 -#: client/src/inventories-hosts/inventories/inventory.list.js:119 -#: client/src/inventory-scripts/inventory-scripts.list.js:70 -#: client/src/notifications/notificationTemplates.list.js:91 -#: client/src/scheduler/schedules.list.js:91 -#: client/src/teams/teams.list.js:64 -#: client/src/templates/templates.list.js:108 -#: client/src/users/users.list.js:70 -msgid "View" -msgstr "" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "View Activity Stream" -msgstr "" - -#: client/lib/components/components.strings.js:57 -msgid "View Documentation" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:86 -msgid "View Insights Data" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:202 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:226 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:250 -msgid "View JSON examples at" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:78 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:77 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:77 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:73 -msgid "View JSON examples at %s" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:13 -msgid "View Less" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:11 -msgid "View More" -msgstr "" - -#: client/features/output/jobs.strings.js:24 -msgid "View Project checkout results" -msgstr "" - -#: client/src/shared/form-generator.js:1728 -#: client/src/templates/job_templates/job-template.form.js:449 -#: client/src/templates/workflows.form.js:187 -msgid "View Survey" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:203 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:227 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:251 -msgid "View YAML examples at" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.form.js:79 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:78 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:78 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:74 -msgid "View YAML examples at %s" -msgstr "" - -#: client/src/credentials/credentials.list.js:84 -msgid "View credential" -msgstr "" - -#: client/src/credential-types/credential-types.list.js:66 -msgid "View credential type" -msgstr "" - -#: client/src/activity-stream/streams.list.js:67 -msgid "View event details" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:93 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:103 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:91 -msgid "View group" -msgstr "" - -#: client/src/inventories-hosts/hosts/host.list.js:89 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:93 -msgid "View host" -msgstr "" - -#: client/src/inventories-hosts/inventories/inventory.list.js:121 -msgid "View inventory" -msgstr "" - -#: client/src/inventory-scripts/inventory-scripts.list.js:72 -msgid "View inventory script" -msgstr "" - -#: client/src/notifications/notificationTemplates.list.js:93 -msgid "View notification" -msgstr "" - -#: client/src/scheduler/schedules.list.js:93 -msgid "View schedule" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:118 -msgid "View source" -msgstr "" - -#: client/src/teams/teams.list.js:67 -msgid "View team" -msgstr "" - -#: client/src/templates/templates.list.js:110 -msgid "View template" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:246 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "View the" -msgstr "" - -#: client/features/output/jobs.strings.js:20 -msgid "View the Credential" -msgstr "" - -#: client/features/output/jobs.strings.js:19 -msgid "View the Inventory" -msgstr "" - -#: client/features/output/jobs.strings.js:21 -msgid "View the Job Template" -msgstr "" - -#: client/features/output/jobs.strings.js:23 -msgid "View the Project" -msgstr "" - -#: client/features/output/jobs.strings.js:18 -msgid "View the Schedule" -msgstr "" - -#: client/features/output/jobs.strings.js:17 -msgid "View the User" -msgstr "" - -#: client/src/projects/projects.list.js:118 -msgid "View the project" -msgstr "" - -#: client/src/scheduler/scheduled-jobs.list.js:74 -msgid "View the schedule" -msgstr "" - -#: client/features/output/jobs.strings.js:22 -msgid "View the source Workflow Job" -msgstr "" - -#: client/src/users/users.list.js:73 -msgid "View user" -msgstr "" - -#: client/lib/components/components.strings.js:80 -msgid "Views" -msgstr "" - -#: client/src/templates/workflows.form.js:20 -msgid "WORKFLOW" -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:91 -#: client/src/configuration/configuration.controller.js:229 -#: client/src/configuration/configuration.controller.js:309 -#: client/src/configuration/system-form/configuration-system.controller.js:55 -msgid "Warning: Unsaved Changes" -msgstr "" - -#: client/src/license/license.partial.html:78 -msgid "Welcome to Ansible Tower! Please complete the steps below to acquire a license." -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:17 -msgid "Welcome to Ansible {{BRAND_NAME}}!  Please sign in." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:344 -msgid "When not checked, a merge will be performed, combining local variables with those found on the external source." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:332 -msgid "When not checked, local child hosts and groups not found on the external source will remain untouched by the inventory update process." -msgstr "" - -#: client/src/shared/form-generator.js:1732 -#: client/src/templates/workflows.form.js:213 -msgid "Workflow Editor" -msgstr "" - -#: client/features/jobs/jobs.strings.js:10 -msgid "Workflow Job" -msgstr "" - -#: client/lib/models/models.strings.js:45 -msgid "Workflow Job Template Nodes" -msgstr "" - -#: client/features/templates/templates.strings.js:14 -#: client/src/templates/templates.list.js:66 -msgid "Workflow Template" -msgstr "" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:41 -msgid "Workflow Templates" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:31 -msgid "Write" -msgstr "" - -#: client/lib/components/code-mirror/code-mirror.strings.js:11 -#: client/lib/services/base-string.service.js:68 -#: client/src/job-submission/job-submission.partial.html:171 -msgid "YAML" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:200 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:224 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:248 -msgid "YAML:" -msgstr "" - -#: client/lib/services/base-string.service.js:72 -msgid "YES" -msgstr "" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Yellow" -msgstr "" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:56 -msgid "You can create a job template here." -msgstr "" - -#: client/features/templates/templates.strings.js:92 -msgid "You do not have access to all resources used by this workflow. Resources that you don't have access to will not be copied and will result in an incomplete workflow." -msgstr "" - -#: client/src/projects/edit/projects-edit.controller.js:63 -msgid "You do not have access to view this property" -msgstr "" - -#: client/src/projects/add/projects-add.controller.js:31 -msgid "You do not have permission to add a project." -msgstr "" - -#: client/src/users/add/users-add.controller.js:43 -msgid "You do not have permission to add a user." -msgstr "" - -#: client/features/templates/templates.strings.js:67 -msgid "You do not have permission to perform this action." -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:28 -msgid "You do not have sufficient permissions to edit the host filter." -msgstr "" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:90 -#: client/src/configuration/configuration.controller.js:228 -#: client/src/configuration/configuration.controller.js:308 -#: client/src/configuration/system-form/configuration-system.controller.js:54 -msgid "You have unsaved changes. Would you like to proceed without saving?" -msgstr "" - -#: client/src/projects/list/projects-list.controller.js:257 -msgid "Your request to cancel the update was submitted to the task manager." -msgstr "" - -#: client/src/login/loginModal/loginModal.partial.html:22 -msgid "Your session timed out due to inactivity. Please sign in." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/shared/form-generator.js:1202 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:42 -msgid "and" -msgstr "" - -#: client/features/users/tokens/tokens.strings.js:27 -msgid "by" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:14 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:19 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:30 -msgid "characters long." -msgstr "" - -#: client/src/shared/smart-search/smart-search.partial.html:53 -msgid "documentation" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:247 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:261 -msgid "for a complete list of supported filters." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "from the" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -#: client/src/inventories-hosts/inventory-hosts.strings.js:8 -msgid "group" -msgid_plural "groups" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "groups" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -msgid "groups and" -msgstr "" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:9 -msgid "host" -msgid_plural "hosts" -msgstr[0] "" -msgstr[1] "" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -msgid "hosts" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:60 -msgid "hosts with failures. Click for details." -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:21 -msgid "name" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:34 -msgid "of" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:239 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "of the filters match." -msgstr "" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:24 -msgid "organization" -msgstr "" - -#: client/src/shared/form-generator.js:1078 -msgid "playbook" -msgstr "" - -#: client/src/credentials/credentials.form.js:138 -#: client/src/credentials/credentials.form.js:364 -msgid "set in helpers/credentials" -msgstr "" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:45 -msgid "sources with sync failures. Click for details" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:244 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "test" -msgstr "" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:14 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:19 -#: client/src/templates/prompt/steps/survey/prompt-survey.partial.html:30 -msgid "to" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "to include all regions. Only Hosts associated with the selected regions will be updated." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "to start it now." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "to update." -msgstr "" - -#: client/src/credentials/credentials.form.js:381 -msgid "v2 URLs%s - leave blank" -msgstr "" - -#: client/src/credentials/credentials.form.js:382 -msgid "v3 default%s - set to 'default'" -msgstr "" - -#: client/src/credentials/credentials.form.js:383 -msgid "v3 multi-domain%s - your domain name" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:220 -msgid "view ec2.ini in the Ansible github repo." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:244 -msgid "view vmware_inventory.ini in the Ansible github repo." -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:239 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "when" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:225 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:238 -msgid "will create group names similar to the following examples based on the options selected:" -msgstr "" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:11 -msgid "with failed jobs." -msgstr "" - -#: client/lib/services/base-string.service.js:93 -msgid "{{ header }} {{ body }}" -msgstr "" - -#: client/features/output/details.partial.html:283 -#: client/features/output/details.partial.html:290 -msgid "{{ vm.jobTags.label }}" -msgstr "" - -#: client/features/output/details.partial.html:258 -#: client/features/output/details.partial.html:265 -msgid "{{ vm.labels.label }}" -msgstr "" - -#: client/features/output/details.partial.html:308 -#: client/features/output/details.partial.html:315 -msgid "{{ vm.skipTags.label }}" -msgstr "" - -#: client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html:5 -msgid "{{:: vm.strings.get('prompt.JOB_TYPE') }}" -msgstr "" - -#: client/lib/components/input/label.partial.html:5 -msgid "{{::state._hint}}" -msgstr "" - -#: client/src/shared/paginate/paginate.partial.html:55 -msgid "{{pageSize}}" -msgstr "" diff --git a/awx/ui/po/es.po b/awx/ui/po/es.po deleted file mode 100644 index 3b3f293d1277..000000000000 --- a/awx/ui/po/es.po +++ /dev/null @@ -1,6100 +0,0 @@ -# Froebel Flores , 2017. #zanata -# edrh01 , 2017. #zanata -# mkim , 2017. #zanata -# plocatelli , 2017. #zanata -# trh01 , 2017. #zanata -# trrh02 , 2017. #zanata -msgid "" -msgstr "" -"Project-Id-Version: \n" -"PO-Revision-Date: 2017-12-06 11:32+0000\n" -"Last-Translator: trrh02 \n" -"Language-Team: \n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"X-Generator: Zanata 4.3.2\n" - -#: client/src/projects/add/projects-add.controller.js:153 -#: client/src/projects/edit/projects-edit.controller.js:288 -msgid "" -"%sNote:%s Mercurial does not support password authentication for SSH. Do not" -" put the username and key in the URL. If using Bitbucket and SSH, do not " -"supply your Bitbucket username." -msgstr "" -"%sNota%s: Mercurial no soporta autentificación utilizando contraseña. No " -"introduzca el usuario y la clave en la dirección URL. Si utiliza Bitbucket y" -" SSH, no indique su usuario de Bitbucket." - -#: client/src/projects/add/projects-add.controller.js:132 -#: client/src/projects/edit/projects-edit.controller.js:267 -msgid "" -"%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key " -"only, do not enter a username (other than git). Additionally, GitHub and " -"Bitbucket do not support password authentication when using SSH. GIT read " -"only protocol (git://) does not use username or password information." -msgstr "" -"%sNota%s: Si usted utiliza el protocolo SSH para GitHub o Bitbucker, " -"introduzca sólo la clave de SSH, no introduzca el usuario (otro distinto a " -"git). Además, GitHub y Bitbucket no soporta autentificación utilizando " -"contraseña cuando se utiliza SSH. El protocolo de sólo lectura GIT (git://) " -"no utiliza usuario y contraseña." - -#: client/src/credentials/credentials.form.js:287 -msgid "(defaults to %s)" -msgstr "(valor por defecto a %s)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -msgid "(seconds)" -msgstr "(segundos)" - -#: client/src/organizations/list/organizations-list.partial.html:20 -msgid "+ ADD" -msgstr "+ AÑADIR" - -#: client/src/shared/paginate/paginate.partial.html:66 -msgid "100" -msgstr "100" - -#: client/src/shared/paginate/paginate.partial.html:60 -msgid "20" -msgstr "20" - -#: client/src/shared/paginate/paginate.partial.html:63 -msgid "50" -msgstr "50" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:33 -msgid "A schedule name is required." -msgstr "Un nombre para el planificador es necesario." - -#: client/src/users/add/users-add.controller.js:102 -msgid "A value is required" -msgstr "Un valor es necesario" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:167 -msgid "A value is required." -msgstr "Un valor es necesario." - -#: client/src/about/about.route.js:10 -msgid "ABOUT" -msgstr "ACERCA DE" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 -msgid "ACTION" -msgstr "ACCIÓN" - -#: client/src/activity-stream/activity-detail.form.js:23 -msgid "ACTIVITY DETAIL" -msgstr "DETALLES DE ACTIVIDAD" - -#: client/src/activity-stream/activitystream.route.js:28 -#: client/src/activity-stream/streams.list.js:14 -#: client/src/activity-stream/streams.list.js:15 -msgid "ACTIVITY STREAM" -msgstr "FLUJO DE ACTIVIDAD" - -#: client/features/credentials/legacy.credentials.js:76 -#: client/src/credential-types/credential-types.list.js:44 -#: client/src/credentials/credentials.form.js:449 -#: client/src/credentials/credentials.list.js:54 -#: client/src/inventories-hosts/inventories/inventory.list.js:77 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:71 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:120 -#: client/src/inventory-scripts/inventory-scripts.list.js:42 -#: client/src/notifications/notificationTemplates.list.js:54 -#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 -#: client/src/organizations/organizations.form.js:84 -#: client/src/projects/projects.form.js:243 -#: client/src/projects/projects.list.js:78 -#: client/src/scheduler/schedules.list.js:68 client/src/teams/teams.form.js:85 -#: client/src/teams/teams.list.js:45 -#: client/src/templates/job_templates/job-template.form.js:397 -#: client/src/templates/templates.list.js:58 -#: client/src/templates/workflows.form.js:125 -#: client/src/users/users.list.js:50 -msgid "ADD" -msgstr "AÑADIR" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:71 -msgid "ADD GROUP" -msgstr "AGREGAR GRUPO" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:125 -msgid "ADD HOST" -msgstr "AGREGAR HOST" - -#: client/src/teams/teams.form.js:157 client/src/users/users.form.js:216 -msgid "ADD PERMISSIONS" -msgstr "AÑADIR PERMISOS" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:70 -msgid "ADD SOURCE" -msgstr "AGREGAR FUENTE" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:16 -msgid "ADD SURVEY PROMPT" -msgstr "AGREGAR AVISO DE ENCUESTA" - -#: client/src/shared/smart-search/smart-search.partial.html:51 -msgid "ADDITIONAL INFORMATION" -msgstr "INFORMACIÓN ADICIONAL" - -#: client/src/organizations/linkout/organizations-linkout.route.js:330 -#: client/src/organizations/list/organizations-list.controller.js:84 -msgid "ADMINS" -msgstr "ADMINS" - -#: client/src/activity-stream/get-target-title.factory.js:4 -msgid "ALL ACTIVITY" -msgstr "TODA LA ACTIVIDAD" - -#: client/src/jobs/all-jobs.list.js:14 -msgid "ALL JOBS" -msgstr "TODOS LOS TRABAJOS" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "ANY" -msgstr "CUALQUIERA" - -#: client/src/credentials/credentials.form.js:198 -msgid "API Key" -msgstr "Clave API" - -#: client/src/notifications/notificationTemplates.form.js:243 -msgid "API Service/Integration Key" -msgstr "Servicio API/Clave de integración" - -#: client/src/notifications/shared/type-change.service.js:52 -msgid "API Token" -msgstr "Token API" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:71 -msgid "ASSOCIATE GROUP" -msgstr "ASOCIAR GRUPO" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js:19 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js:19 -msgid "ASSOCIATED GROUPS" -msgstr "GRUPOS ASOCIADOS" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js:19 -msgid "ASSOCIATED HOSTS" -msgstr "HOSTS ASOCIADOS" - -#: client/src/setup-menu/setup-menu.partial.html:66 -msgid "About {{BRAND_NAME}}" -msgstr "Acerca de {{BRAND_NAME}}" - -#: client/src/credentials/credentials.form.js:91 -msgid "Access Key" -msgstr "Clave de acceso" - -#: client/src/notifications/notificationTemplates.form.js:221 -msgid "Account SID" -msgstr "Cuenta SID" - -#: client/src/notifications/notificationTemplates.form.js:180 -msgid "Account Token" -msgstr "Cuenta Token" - -#: client/src/activity-stream/activity-detail.form.js:36 -msgid "Action" -msgstr "Acción" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/inventories-hosts/hosts/hosts.partial.html:47 -#: client/src/shared/list-generator/list-generator.factory.js:573 -msgid "Actions" -msgstr "Acciones" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:17 -#: client/src/templates/templates.list.js:36 -msgid "Activity" -msgstr "Actividad" - -#: client/src/configuration/system-form/configuration-system.controller.js:88 -msgid "Activity Stream" -msgstr "Flujo de actividad" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:131 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:132 -#: client/src/organizations/organizations.form.js:81 -#: client/src/teams/teams.form.js:82 -#: client/src/templates/workflows.form.js:122 -msgid "Add" -msgstr "Añadir" - -#: client/src/credentials/credentials.list.js:14 -msgid "Add Credentials" -msgstr "Añadir credencial" - -#: client/src/inventories-hosts/inventories/inventory.list.js:13 -msgid "Add Inventories" -msgstr "Añadir inventarios" - -#: client/src/shared/stateDefinitions.factory.js:288 -msgid "Add Permissions" -msgstr "Añadir permisos" - -#: client/src/projects/projects.list.js:13 -msgid "Add Project" -msgstr "Añadir proyecto" - -#: client/src/shared/form-generator.js:1711 -#: client/src/templates/job_templates/job-template.form.js:445 -#: client/src/templates/workflows.form.js:170 -msgid "Add Survey" -msgstr "Añadir encuesta" - -#: client/src/teams/teams.list.js:13 -msgid "Add Team" -msgstr "Añadir equipo" - -#: client/src/teams/teams.form.js:83 -msgid "Add User" -msgstr "Añadir usuario" - -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/shared/stateDefinitions.factory.js:578 -#: client/src/users/users.list.js:17 -msgid "Add Users" -msgstr "Añadir usuarios" - -#: client/src/organizations/organizations.form.js:82 -msgid "Add Users to this organization." -msgstr "Añadir usuarios a la organización." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:69 -msgid "Add a group" -msgstr "Agregar un grupo" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:118 -msgid "Add a host" -msgstr "Agregar un host" - -#: client/src/scheduler/schedules.list.js:66 -msgid "Add a new schedule" -msgstr "Añadir un nuevo planificador" - -#: client/features/credentials/legacy.credentials.js:74 -#: client/src/credentials/credentials.form.js:447 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:133 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:134 -#: client/src/projects/projects.form.js:241 -#: client/src/templates/job_templates/job-template.form.js:395 -#: client/src/templates/workflows.form.js:123 -msgid "Add a permission" -msgstr "Añadir un permiso" - -#: client/src/setup-menu/setup-menu.partial.html:23 -msgid "" -"Add passwords, SSH keys, and other credentials to use when launching jobs " -"against machines, or when syncing inventories or projects." -msgstr "" -"Agregar contraseñas, claves SSH y otras credenciales para utilizar cuando se" -" ejecutan tareas sobre máquinas o cuando se sincronizan inventarios o " -"proyectos." - -#: client/src/shared/form-generator.js:1446 -msgid "Admin" -msgstr "Administrador" - -#: client/src/organizations/linkout/organizations-linkout.route.js:354 -msgid "Admins" -msgstr "Administradores" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:367 -msgid "" -"After every project update where the SCM revision changes, refresh the " -"inventory from the selected source before executing job tasks. This is " -"intended for static content, like the Ansible inventory .ini file format." -msgstr "" -"Luego de cada actualización del proyecto en el que se modifique la revisión " -"SCM, actualice el inventario del origen seleccionado antes de llevar a cabo " -"tareas de trabajo. Esto está orientado a contenidos estáticos, como el " -"formato de archivo .ini del inventario Ansible." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:37 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:43 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:65 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:74 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "All" -msgstr "Todo" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 -msgid "All Activity" -msgstr "Todas las actividades" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:10 -#: client/src/portal-mode/portal-mode-layout.partial.html:17 -msgid "All Jobs" -msgstr "Todos los trabajos" - -#: client/src/templates/job_templates/job-template.form.js:275 -#: client/src/templates/job_templates/job-template.form.js:282 -msgid "Allow Provisioning Callbacks" -msgstr "Permitir la ejecución utilizando Callbacks" - -#: client/src/setup-menu/setup-menu.partial.html:11 -msgid "" -"Allow others to sign into {{BRAND_NAME}} and own the content they create." -msgstr "" -"Permitir a otros iniciar sesión en {{BRAND_NAME}} y poseer el contenido que " -"creen." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:43 -msgid "Always" -msgstr "Siempre" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "" -"An SCM update does not appear to be running for project: %s. Click the " -"%sRefresh%s button to view the latest status." -msgstr "" -"Una actualización de SCM no aparece estar siendo ejecutada para los " -"proyectos: %s. Pulse sobre el botón %sActualizar%s para ver el estado más " -"reciente." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:62 -#: client/src/templates/survey-maker/shared/question-definition.form.js:68 -msgid "Answer Type" -msgstr "Tipo de respuesta" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:44 -#: client/src/templates/survey-maker/shared/question-definition.form.js:53 -msgid "Answer Variable Name" -msgstr "Nombre de la variable" - -#: client/src/job-results/job-results.service.js:144 -msgid "Are you sure you want to cancel the job below?" -msgstr "¿Está seguro de que desea cancelar esta tarea?" - -#: client/src/credentials/list/credentials-list.controller.js:133 -msgid "Are you sure you want to delete the credential below?" -msgstr "¿Está seguro que quiere eliminar la credencial indicada?" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:100 -msgid "Are you sure you want to delete the inventory below?" -msgstr "¿Está seguro de que quiere eliminar el inventario indicado?" - -#: client/src/job-results/job-results.service.js:95 -#: client/src/jobs/factories/delete-job.factory.js:110 -msgid "Are you sure you want to delete the job below?" -msgstr "¿Está seguro que quiere eliminar el trabajo indicado?" - -#: client/src/notifications/notification-templates-list/list.controller.js:190 -msgid "Are you sure you want to delete the notification template below?" -msgstr "" -"¿Está seguro que quiere eliminar la plantilla de notificación indicada?" - -#: client/src/organizations/list/organizations-list.controller.js:172 -msgid "Are you sure you want to delete the organization below?" -msgstr "¿Está seguro que quiere eliminar la organización indicada?" - -#: client/src/projects/list/projects-list.controller.js:208 -msgid "Are you sure you want to delete the project below?" -msgstr "¿Está seguro que quiere eliminar el proyecto indicado?" - -#: client/src/templates/list/templates-list.controller.js:103 -msgid "Are you sure you want to delete the template below?" -msgstr "¿Está seguro de que quiere eliminar esta plantilla?" - -#: client/src/users/list/users-list.controller.js:90 -msgid "Are you sure you want to delete the user below?" -msgstr "¿Está seguro que quiere eliminar el usuario indicado?" - -#: client/src/partials/survey-maker-modal.html:13 -msgid "Are you sure you want to delete this {{deleteMode}}?" -msgstr "¿Esta seguro de que desea eliminar este {{deleteMode}}?" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:25 -msgid "Are you sure you want to disassociate the group below from" -msgstr "¿Está seguro de que quiere desasociar el grupo indicado de" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:23 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:26 -msgid "Are you sure you want to disassociate the host below from" -msgstr "¿Está seguro de que quiere desasociar el host indicado de" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:47 -msgid "" -"Are you sure you want to permanently delete the group below from the " -"inventory?" -msgstr "" -"¿Está seguro de que quiere eliminar permanentemente el grupo indicado del " -"inventario?" - -#: client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js:106 -msgid "" -"Are you sure you want to permanently delete the host below from the " -"inventory?" -msgstr "" -"¿Está seguro de que quiere eliminar permanentemente el host indicado del " -"inventario?" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:69 -msgid "" -"Are you sure you want to permanently delete the inventory source below from " -"the inventory?" -msgstr "" -"¿Está seguro de que quiere eliminar permanentemente la fuente del inventario" -" del inventario?" - -#: client/src/projects/edit/projects-edit.controller.js:244 -msgid "Are you sure you want to remove the %s below from %s?" -msgstr "¿Está seguro de que quiere eliminar el %s indicado de %s?" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:39 -msgid "Arguments" -msgstr "Argumentos" - -#: client/src/credentials/credentials.form.js:232 -#: client/src/credentials/credentials.form.js:271 -#: client/src/credentials/credentials.form.js:311 -#: client/src/credentials/credentials.form.js:397 -msgid "Ask at runtime?" -msgstr "¿Preguntar durante la ejecución?" - -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:69 -msgid "Associate an existing group" -msgstr "Asociar un grupo existente" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:51 -msgid "Associate this host with a new group" -msgstr "Asociar este host a un nuevo grupo" - -#: client/src/shared/form-generator.js:1448 -msgid "Auditor" -msgstr "Auditor" - -#: client/src/configuration/configuration.partial.html:15 -msgid "Authentication" -msgstr "Autentificación " - -#: client/src/credentials/credentials.form.js:72 -msgid "" -"Authentication for network device access. This can include SSH keys, " -"usernames, passwords, and authorize information. Network credentials are " -"used when submitting jobs to run playbooks against network devices." -msgstr "" -"Autentificación para el acceso a dispositivos de red. Puede incluir claves " -"SSH, usuarios, contraseñas, e información de autorización. Las credenciales " -"de Red son utilizadas al lanzar trabajos que ejecutan playbooks sobre " -"dispositivos de red." - -#: client/src/credentials/credentials.form.js:68 -msgid "" -"Authentication for remote machine access. This can include SSH keys, " -"usernames, passwords, and sudo information. Machine credentials are used " -"when submitting jobs to run playbooks against remote hosts." -msgstr "" -"Autentificación para máquinas remotas. Puede incluir claves SSH, usuarios, " -"contraseñas e información de sudo. Las credenciales de máquina son " -"utilizadas al lanzar trabajos que ejecutan playbooks contra servidores " -"remotos." - -#: client/src/credentials/credentials.form.js:343 -msgid "Authorize" -msgstr "Autorizar" - -#: client/src/credentials/credentials.form.js:351 -msgid "Authorize Password" -msgstr "Contraseña de autorización" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:172 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "Availability Zone:" -msgstr "Zona de disponibilidad:" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:106 -msgid "Azure AD" -msgstr "Azure AD" - -#: client/src/shared/directives.js:75 -msgid "BROWSE" -msgstr "NAVEGAR" - -#: client/src/projects/projects.form.js:80 -msgid "" -"Base path used for locating playbooks. Directories found inside this path " -"will be listed in the playbook directory drop-down. Together the base path " -"and selected playbook directory provide the full path used to locate " -"playbooks." -msgstr "" -"Directorio base utilizado para encontrar playbooks. Los directorios " -"encontrados dentro de este directorio serán listados en el desplegable " -"correspondiente a la lista de playbook. Junto a la ruta base y el el " -"directorio del playbook seleccionado se creará la ruta completa para " -"encontrar los playbooks." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:128 -msgid "Become Privilege Escalation" -msgstr "Activar la escalada de privilegios" - -#: client/src/license/license.partial.html:107 -msgid "Browse" -msgstr "Navegar" - -#: client/lib/services/base-string.service.js:61 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:28 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:73 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:16 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:16 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:16 -#: client/src/job-submission/job-submission.partial.html:370 -#: client/src/partials/survey-maker-modal.html:17 -#: client/src/partials/survey-maker-modal.html:85 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:17 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:65 -msgid "CANCEL" -msgstr "CANCELAR" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 -msgid "CHANGES" -msgstr "MODIFICACIONES" - -#: client/src/shared/smart-search/smart-search.partial.html:30 -msgid "CLEAR ALL" -msgstr "LIMPIAR TODO" - -#: client/src/partials/survey-maker-modal.html:86 -msgid "CLOSE" -msgstr "CERRAR" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:19 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js:19 -#: client/src/templates/completed-jobs.list.js:20 -msgid "COMPLETED JOBS" -msgstr "TRABAJOS COMPLETADOS" - -#: client/src/configuration/configuration.partial.html:10 -msgid "CONFIGURE {{BRAND_NAME}}" -msgstr "CONFIGURAR {{BRAND_NAME}}" - -#: client/src/shared/stateDefinitions.factory.js:157 -msgid "CREATE %s" -msgstr "CREAR %s" - -#: client/features/credentials/credentials.strings.js:8 -#: client/src/credentials/credentials.form.js:16 -msgid "CREATE CREDENTIAL" -msgstr "CREAR CREDENCIAL" - -#: client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:16 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:16 -msgid "CREATE GROUP" -msgstr "CREAR GRUPO" - -#: client/src/inventories-hosts/hosts/host.form.js:17 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:17 -#: client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:17 -msgid "CREATE HOST" -msgstr "CREAR HOST" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js:8 -msgid "CREATE INVENTORY SOURCE" -msgstr "CREAR FUENTE DE INVENTARIO" - -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js:8 -#: client/src/scheduler/main.js:113 client/src/scheduler/main.js:206 -#: client/src/scheduler/main.js:290 -msgid "CREATE SCHEDULE" -msgstr "CREAR PROGRAMACIÓN" - -#: client/src/management-jobs/scheduler/main.js:81 -msgid "CREATE SCHEDULED JOB" -msgstr "CREAR TRABAJO PROGRAMADO" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:32 -msgid "CREATE SOURCE" -msgstr "CREAR FUENTE" - -#: client/src/job-submission/job-submission.partial.html:351 -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:93 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:82 -msgid "CREDENTIAL" -msgstr "CREDENCIAL" - -#: client/src/credential-types/credential-types.form.js:21 -msgid "CREDENTIAL TYPE" -msgstr "TIPO DE CREDENCIAL" - -#: client/src/job-submission/job-submission.partial.html:92 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:56 -msgid "CREDENTIAL TYPE:" -msgstr "TIPO DE CREDENCIAL:" - -#: client/src/activity-stream/get-target-title.factory.js:11 -#: client/src/credential-types/credential-types.list.js:12 -#: client/src/credential-types/main.js:45 -msgid "CREDENTIAL TYPES" -msgstr "TIPOS DE CREDENCIAL" - -#: client/features/credentials/legacy.credentials.js:14 -#: client/src/activity-stream/get-target-title.factory.js:17 -#: client/src/credentials/credentials.list.js:15 -#: client/src/credentials/credentials.list.js:16 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:5 -msgid "CREDENTIALS" -msgstr "CREDENCIALES" - -#: client/features/credentials/credentials.strings.js:28 -msgid "CREDENTIALS PERMISSIONS" -msgstr "PERMISOS DE CREDENCIAL" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:390 -#: client/src/projects/projects.form.js:199 -msgid "Cache Timeout" -msgstr "Tiempo de espera para la expiración de la caché" - -#: client/src/projects/projects.form.js:188 -msgid "Cache Timeout%s (seconds)%s" -msgstr "Tiempo de espera para la expiración de la caché%s (segundos)%s" - -#: client/src/projects/list/projects-list.controller.js:199 -#: client/src/users/list/users-list.controller.js:83 -msgid "Call to %s failed. DELETE returned status:" -msgstr "Fallo en la llamada a %s. DELETE ha devuelto el estado:" - -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:263 -msgid "Call to %s failed. GET status:" -msgstr "Fallo en la llamada a %s. Estado GET:" - -#: client/src/projects/edit/projects-edit.controller.js:238 -msgid "Call to %s failed. POST returned status:" -msgstr "Fallo en la llamada a %s. POST ha devuelto el estado:" - -#: client/src/projects/list/projects-list.controller.js:225 -msgid "Call to %s failed. POST status:" -msgstr "Fallo en la llamada a %s. Estado POST :" - -#: client/src/management-jobs/card/card.controller.js:29 -msgid "Call to %s failed. Return status: %d" -msgstr "Fallo en la llamada a %s. Ha devuelto el estado: %d" - -#: client/src/projects/list/projects-list.controller.js:272 -msgid "Call to get project failed. GET status:" -msgstr "Fallo en la obtención del proyecto. Estado GET :" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:105 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:188 -#: client/src/configuration/configuration.controller.js:541 -#: client/src/job-results/job-results.partial.html:42 -#: client/src/jobs/factories/delete-job.factory.js:33 -#: client/src/shared/form-generator.js:1699 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:12 -#: client/src/workflow-results/workflow-results.partial.html:42 -msgid "Cancel" -msgstr "Cancelar" - -#: client/src/job-results/job-results.service.js:142 -msgid "Cancel Job" -msgstr "Cancelar tarea" - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "Cancel Not Allowed" -msgstr "Cancelación no permitida." - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:93 -msgid "Cancel sync process" -msgstr "Cancelar proceso de sincronización" - -#: client/src/projects/projects.list.js:124 -msgid "Cancel the SCM update" -msgstr "Cancelar la actualización de SCM" - -#: client/src/jobs/all-jobs.list.js:106 -msgid "Cancel the job" -msgstr "Cancelar el trabajo." - -#: client/src/projects/factories/get-project-tool-tip.factory.js:30 -#: client/src/projects/list/projects-list.controller.js:79 -msgid "Canceled. Click for details" -msgstr "Cancelado. Pulse para mostrar más detalles." - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:91 -msgid "Cannot search running job" -msgstr "Imposible buscar en trabajos en ejecución." - -#: client/src/instance-groups/instance-groups.list.js:22 -#: client/src/instance-groups/instances/instances.list.js:20 -msgid "Capacity" -msgstr "Capacidad" - -#: client/src/projects/projects.form.js:82 -msgid "Change %s under \"Configure {{BRAND_NAME}}\" to change this location." -msgstr "" -"Modificar %s dentro de \"Configurar {{BRAND_NAME}}\" para cambiar esta " -"ubicación." - -#: client/src/activity-stream/activity-detail.form.js:41 -msgid "Changes" -msgstr "Modificaciones" - -#: client/src/shared/form-generator.js:1071 -msgid "Choose a %s" -msgstr "Escoja un %s" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:64 -msgid "Choose an answer type" -msgstr "Elegir un tipo de respuesta" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:67 -msgid "" -"Choose an answer type or format you want as the prompt for the user. Refer " -"to the Ansible Tower Documentation for more additional information about " -"each option." -msgstr "" -"Especifique el tipo de respuesta o el formato que desee como indicador para " -"el usuario. Consulte la documentación de Ansible Tower para obtener más " -"información sobre cada una de las opciones." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:112 -msgid "Choose an inventory file" -msgstr "Escoja un archivo del inventario." - -#: client/src/shared/directives.js:76 -msgid "Choose file" -msgstr "Escoja fichero" - -#: client/src/license/license.partial.html:97 -msgid "" -"Choose your license file, agree to the End User License Agreement, and click" -" submit." -msgstr "" -"Escoja su fichero de licencia, aceptando el Acuerdo de licencia de usuario " -"final, y pulse sobre Enviar." - -#: client/src/projects/projects.form.js:156 -msgid "Clean" -msgstr "Limpiar" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:299 -msgid "Clear" -msgstr "Borrar" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:64 -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Click for details" -msgstr "Hacer clic para obtener más información" - -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:63 -msgid "Click here to open the workflow graph editor." -msgstr "Haga clic aquí para abrir el editor de gráficos del flujo de trabajo." - -#: client/src/inventories-hosts/inventories/inventory.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new inventory." -msgstr "" -"Pulse sobre una fila para seleccionarla, y pulse Finalizado una vez " -"terminado. Pulse sobre el botón %s para crear un nuevo inventario." - -#: client/src/teams/teams.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new team." -msgstr "" -"Pulse sobre una fila para seleccionarla, y pulse Finalizado una vez " -"terminado. Pulse sobre el botón %s para crear un nuevo equipo." - -#: client/src/templates/templates.list.js:17 -msgid "" -"Click on a row to select it, and click Finished when done. Use the %s button" -" to create a new job template." -msgstr "" -"Pulse sobre una fila para seleccionarla, y pulse Finalizado una vez " -"terminado. Pulse sobre el botón %s para crear una nueva plantilla de " -"trabajo." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:138 -msgid "" -"Click on the regions field to see a list of regions for your cloud provider." -" You can select multiple regions, or choose" -msgstr "" -"Haga clic en el campo de regiones para ver una lista de regiones para su " -"proveedor de nube. Puede seleccionar varias regiones o elegir" - -#: client/src/credentials/credentials.form.js:321 -msgid "Client ID" -msgstr "ID del cliente" - -#: client/src/notifications/notificationTemplates.form.js:254 -msgid "Client Identifier" -msgstr "Identificador del cliente" - -#: client/src/credentials/credentials.form.js:330 -msgid "Client Secret" -msgstr "Pregunta secreta del cliente" - -#: client/src/shared/form-generator.js:1703 -msgid "Close" -msgstr "Cerrar" - -#: client/src/job-results/job-results.partial.html:291 -msgid "Cloud Credential" -msgstr "Credencial cloud" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:26 -msgid "Cloud source not configured." -msgstr "Fuente de nube no configurada." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "Cloud source not configured. Click" -msgstr "Fuente de nube no configurada. Haga clic en" - -#: client/src/credentials/factories/become-method-change.factory.js:80 -#: client/src/credentials/factories/kind-change.factory.js:137 -msgid "CloudForms URL" -msgstr "URL CloudForms" - -#: client/src/job-results/job-results.controller.js:226 -#: client/src/standard-out/standard-out.controller.js:243 -#: client/src/workflow-results/workflow-results.controller.js:118 -msgid "Collapse Output" -msgstr "Colapsar salida" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:13 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:21 -msgid "Completed Jobs" -msgstr "Tareas completadas" - -#: client/src/management-jobs/card/card.partial.html:34 -msgid "Configure Notifications" -msgstr "Configurar las notificaciones" - -#: client/src/setup-menu/setup-menu.partial.html:60 -msgid "Configure {{BRAND_NAME}}" -msgstr "Configurar {{BRAND_NAME}}" - -#: client/src/users/users.form.js:81 -msgid "Confirm Password" -msgstr "Confirmar la contraseña" - -#: client/src/configuration/configuration.controller.js:548 -msgid "Confirm Reset" -msgstr "Confirmar la reinicialización" - -#: client/src/configuration/configuration.controller.js:557 -msgid "Confirm factory reset" -msgstr "Confirmar la reinicialización a valores de fábrica" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:120 -msgid "" -"Confirm that you want to permanently delete the inventory source below from " -"the inventory. Deleting this inventory source also deletes its associated " -"groups and hosts." -msgstr "" -"¿Está seguro de que quiere eliminar permanentemente la fuente del inventario" -" de este inventario? Eliminar la fuente del inventario también elimina los " -"grupos y los host asociados." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "Confirm the removal of the" -msgstr "Confirmar la eliminación de" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:134 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:149 -msgid "" -"Consult the Ansible documentation for further details on the usage of tags." -msgstr "" -"Consultar la documentación de Ansible para información más detallada del uso" -" de etiquetas (tags)." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:18 -msgid "Contains 0 hosts." -msgstr "Contiene 0 hosts." - -#: client/src/templates/job_templates/job-template.form.js:180 -msgid "" -"Control the level of output ansible will produce as the playbook executes." -msgstr "" -"Controlar el nivel de salida que ansible producirá al ejecutar playbooks." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:313 -msgid "" -"Control the level of output ansible will produce for inventory source update" -" jobs." -msgstr "" -"Controle el nivel de salida que Ansible producirá para las tareas de " -"actualización de fuentes de inventario." - -#: client/lib/components/components.strings.js:48 -msgid "Copied to clipboard." -msgstr "Copiado al portapapeles." - -#: client/src/templates/templates.list.js:95 -msgid "Copy" -msgstr "Copiar" - -#: client/lib/components/components.strings.js:47 -msgid "Copy full revision to clipboard." -msgstr "Copie la revisión completa al portapapeles." - -#: client/src/templates/templates.list.js:98 -msgid "Copy template" -msgstr "Copiar plantilla" - -#: client/src/about/about.partial.html:27 -msgid "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Visit Ansible.com for more information.
" -msgstr "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Visite Ansible.com para obtener más información.
" - -#: client/src/users/users.list.js:44 -msgid "Create New" -msgstr "Crear nuevo" - -#: client/src/credentials/credentials.list.js:52 -msgid "Create a new credential" -msgstr "Crear una nueva credencial" - -#: client/src/credential-types/credential-types.list.js:42 -msgid "Create a new credential type" -msgstr "Crear un nuevo tipo de credencial" - -#: client/src/inventory-scripts/inventory-scripts.list.js:40 -msgid "Create a new custom inventory" -msgstr "Crear un nuevo inventario personalizado" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:69 -msgid "Create a new group" -msgstr "Crear un nuevo grupo" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:123 -msgid "Create a new host" -msgstr "Crear un nuevo host" - -#: client/src/inventories-hosts/inventories/inventory.list.js:75 -msgid "Create a new inventory" -msgstr "Crear un nuevo inventario" - -#: client/src/notifications/notificationTemplates.list.js:52 -msgid "Create a new notification template" -msgstr "Crear una nueva plantilla de notificación" - -#: client/src/organizations/list/organizations-list.partial.html:21 -msgid "Create a new organization" -msgstr "Crear una nueva organización" - -#: client/src/projects/projects.list.js:76 -msgid "Create a new project" -msgstr "Crear un nuevo proyecto" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:68 -msgid "Create a new source" -msgstr "Crear una nueva fuente" - -#: client/src/teams/teams.list.js:43 -msgid "Create a new team" -msgstr "Crear un nuevo equipo" - -#: client/src/templates/templates.list.js:56 -msgid "Create a new template" -msgstr "Crear una nueva plantilla" - -#: client/src/users/users.list.js:48 -msgid "Create a new user" -msgstr "Crear un nuevo usuario" - -#: client/src/setup-menu/setup-menu.partial.html:42 -msgid "Create and edit scripts to dynamically load hosts from any source." -msgstr "" -"Crear y editar scripts que dinámicamente carguen servidores a partir de " -"cualquier origen." - -#: client/src/setup-menu/setup-menu.partial.html:30 -msgid "" -"Create custom credential types to be used for authenticating to network " -"hosts and cloud sources" -msgstr "" -"Crear tipos de credenciales personalizados para usar en la autenticación de " -"hosts de red y fuentes de nube" - -#: client/src/setup-menu/setup-menu.partial.html:49 -msgid "" -"Create templates for sending notifications with Email, HipChat, Slack, and " -"SMS." -msgstr "" -"Crear plantillas para enviar notificaciones a través de email, HipChat, " -"Slack y SMS." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:72 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:74 -#: client/src/job-submission/job-submission.partial.html:18 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:67 -#: client/src/templates/job_templates/job-template.form.js:121 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:53 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:62 -msgid "Credential" -msgstr "Credencial" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:32 -#: client/src/setup-menu/setup-menu.partial.html:29 -msgid "Credential Types" -msgstr "Tipos de credencial" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:129 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:58 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 -#: client/src/setup-menu/setup-menu.partial.html:22 -#: client/src/templates/job_templates/job-template.form.js:134 -msgid "Credentials" -msgstr "Credenciales" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:17 -msgid "Critical" -msgstr "Crítico" - -#: client/src/shared/directives.js:77 -msgid "Current Image:" -msgstr "Imagen actual:" - -#: client/src/job-results/job-results.controller.js:271 -msgid "Currently following standard out as it comes in. Click to unfollow." -msgstr "" -"Actualmente siguiendo la salida estándar. Haga clic para dejar de seguir." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:171 -msgid "Custom Inventory Script" -msgstr "Script de inventario personalizado" - -#: client/src/inventory-scripts/inventory-scripts.form.js:50 -#: client/src/inventory-scripts/inventory-scripts.form.js:60 -msgid "Custom Script" -msgstr "Script personalizado" - -#: client/src/home/home.route.js:21 -msgid "DASHBOARD" -msgstr "PANEL DE CONTROL" - -#: client/src/credentials/list/credentials-list.controller.js:135 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:103 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:52 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:74 -#: client/src/job-results/job-results.service.js:119 -#: client/src/jobs/factories/delete-job.factory.js:115 -#: client/src/notifications/notification-templates-list/list.controller.js:195 -#: client/src/organizations/list/organizations-list.controller.js:174 -#: client/src/partials/survey-maker-modal.html:18 -#: client/src/projects/edit/projects-edit.controller.js:246 -#: client/src/templates/list/templates-list.controller.js:154 -#: client/src/users/list/users-list.controller.js:92 -msgid "DELETE" -msgstr "ELIMINAR" - -#: client/src/partials/survey-maker-modal.html:84 -msgid "DELETE SURVEY" -msgstr "BORRAR ENCUESTA" - -#: client/src/job-results/job-results.partial.html:16 -msgid "DETAILS" -msgstr "DETALLES" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:31 -msgid "DISASSOCIATE" -msgstr "DISOCIAR" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:5 -msgid "DYNAMIC HOSTS" -msgstr "HOSTS DINÁMICOS" - -#: client/src/credential-types/credential-types.list.js:73 -#: client/src/credentials/credentials.list.js:85 -#: client/src/credentials/list/credentials-list.controller.js:132 -#: client/src/inventories-hosts/inventories/inventory.list.js:111 -#: client/src/inventory-scripts/inventory-scripts.list.js:71 -#: client/src/job-results/job-results.partial.html:54 -#: client/src/jobs/factories/delete-job.factory.js:37 -#: client/src/notifications/notification-templates-list/list.controller.js:192 -#: client/src/notifications/notificationTemplates.list.js:91 -#: client/src/organizations/list/organizations-list.controller.js:171 -#: client/src/projects/edit/projects-edit.controller.js:243 -#: client/src/projects/list/projects-list.controller.js:207 -#: client/src/scheduler/schedules.list.js:90 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:13 -#: client/src/teams/teams.list.js:72 -#: client/src/templates/list/templates-list.controller.js:102 -#: client/src/templates/templates.list.js:120 -#: client/src/users/list/users-list.controller.js:89 -#: client/src/users/users.list.js:79 -#: client/src/workflow-results/workflow-results.partial.html:54 -msgid "Delete" -msgstr "ELIMINAR" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:6 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:6 -msgid "Delete Group" -msgstr "Eliminar grupo" - -#: client/src/job-results/job-results.service.js:93 -msgid "Delete Job" -msgstr "Eliminar tarea" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:175 -msgid "Delete Source" -msgstr "Eliminar fuente" - -#: client/src/credentials/credentials.list.js:87 -msgid "Delete credential" -msgstr "Eliminar la credencial." - -#: client/src/credential-types/credential-types.list.js:75 -msgid "Delete credential type" -msgstr "Eliminar tipo de credencial" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:101 -#: client/src/inventories-hosts/inventory-hosts.strings.js:19 -msgid "Delete group" -msgid_plural "Delete groups" -msgstr[0] "Eliminar grupo" -msgstr[1] "Eliminar grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:48 -msgid "Delete groups" -msgstr "Eliminar grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:37 -msgid "Delete groups and hosts" -msgstr "Eliminar grupos y hosts" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:100 -#: client/src/inventories-hosts/inventory-hosts.strings.js:21 -msgid "Delete host" -msgid_plural "Delete hosts" -msgstr[0] "Eliminar host" -msgstr[1] "Eliminar hosts" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:59 -msgid "Delete hosts" -msgstr "Eliminar hosts" - -#: client/src/inventories-hosts/inventories/inventory.list.js:113 -msgid "Delete inventory" -msgstr "Eliminar el inventario" - -#: client/src/inventory-scripts/inventory-scripts.list.js:73 -msgid "Delete inventory script" -msgstr "Eliminar el script de inventario." - -#: client/src/notifications/notificationTemplates.list.js:93 -msgid "Delete notification" -msgstr "Eliminar la notificación" - -#: client/src/projects/projects.form.js:166 -msgid "Delete on Update" -msgstr "Eliminar la actualización" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:27 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:27 -msgid "Delete or promote the group's children?" -msgstr "¿Desea eliminar o promover los elementos secundarios del grupo?" - -#: client/src/scheduler/schedules.list.js:93 -msgid "Delete schedule" -msgstr "Eliminar planificación" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:125 -msgid "Delete source" -msgstr "Eliminar fuente" - -#: client/src/teams/teams.list.js:76 -msgid "Delete team" -msgstr "Eliminar el equipo" - -#: client/src/templates/templates.list.js:123 -msgid "Delete template" -msgstr "Eliminar la plantilla" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:84 -#: client/src/jobs/all-jobs.list.js:113 -#: client/src/templates/completed-jobs.list.js:85 -msgid "Delete the job" -msgstr "Eliminar el trabajo" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Delete the local repository in its entirety prior to performing an update." -msgstr "" -"Eliminar el repositorio local en su totalidad antes de realizar la " -"actualización." - -#: client/src/projects/projects.list.js:118 -msgid "Delete the project" -msgstr "Eliminar el proyecto" - -#: client/src/scheduler/scheduled-jobs.list.js:81 -msgid "Delete the schedule" -msgstr "Eliminar la planificación" - -#: client/src/users/users.list.js:83 -msgid "Delete user" -msgstr "Eliminar el usuario" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:14 -msgid "Delete {{ group }} and {{ host }}" -msgstr "Eliminar {{ group }} y {{ host }}" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:23 -msgid "Deleting group" -msgstr "Eliminando grupo" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Depending on the size of the repository this may significantly increase the " -"amount of time required to complete an update." -msgstr "" -"Dependiendo del tamaño del repositorio esto podría incrementar " -"significativamente el tiempo necesario para completar una actualización." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "Describe Instances documentation" -msgstr "Documentación de descripción de las instancias" - -#: client/src/credential-types/credential-types.form.js:34 -#: client/src/credentials/credentials.form.js:39 -#: client/src/inventories-hosts/hosts/host.form.js:63 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:39 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:62 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:62 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:58 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:46 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:53 -#: client/src/inventory-scripts/inventory-scripts.form.js:35 -#: client/src/notifications/notificationTemplates.form.js:39 -#: client/src/organizations/organizations.form.js:33 -#: client/src/projects/projects.form.js:36 client/src/teams/teams.form.js:32 -#: client/src/templates/job_templates/job-template.form.js:41 -#: client/src/templates/survey-maker/shared/question-definition.form.js:36 -#: client/src/templates/workflows.form.js:39 -#: client/src/users/users.form.js:145 client/src/users/users.form.js:171 -msgid "Description" -msgstr "Descripción" - -#: client/src/notifications/notificationTemplates.form.js:136 -#: client/src/notifications/notificationTemplates.form.js:140 -#: client/src/notifications/notificationTemplates.form.js:152 -#: client/src/notifications/notificationTemplates.form.js:156 -msgid "Destination Channels" -msgstr "Canales destinatarios" - -#: client/src/notifications/notificationTemplates.form.js:359 -#: client/src/notifications/notificationTemplates.form.js:363 -msgid "Destination Channels or Users" -msgstr "Canales destinatarios o usuarios" - -#: client/src/notifications/notificationTemplates.form.js:205 -#: client/src/notifications/notificationTemplates.form.js:206 -msgid "Destination SMS Number" -msgstr "Número SMS del destinatario" - -#: client/features/credentials/credentials.strings.js:13 -#: client/src/license/license.partial.html:5 -#: client/src/shared/form-generator.js:1481 -msgid "Details" -msgstr "Detalles" - -#: client/src/job-submission/job-submission.partial.html:263 -msgid "Diff Mode" -msgstr "Modo diff" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Group From Group" -msgstr "Desasociar un grupo de otro grupo" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:6 -msgid "Disassociate Host" -msgstr "Disociar host" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:6 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Host From Group" -msgstr "Desasociar un host de un grupo" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:65 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:110 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:98 -msgid "Disassociate group" -msgstr "Disociar grupo" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:87 -msgid "Disassociate host" -msgstr "Disociar host" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:75 -#: client/src/configuration/configuration.controller.js:202 -#: client/src/configuration/configuration.controller.js:264 -#: client/src/configuration/system-form/configuration-system.controller.js:57 -msgid "Discard changes" -msgstr "Descartar cambios" - -#: client/src/teams/teams.form.js:146 -msgid "Dissasociate permission from team" -msgstr "Desasociar permiso de un equipo." - -#: client/src/users/users.form.js:225 -msgid "Dissasociate permission from user" -msgstr "Desasociar permiso de un usuario" - -#: client/src/credentials/credentials.form.js:384 -#: client/src/credentials/factories/become-method-change.factory.js:54 -#: client/src/credentials/factories/kind-change.factory.js:111 -msgid "Domain Name" -msgstr "Nombre de dominio" - -#: client/src/job-results/job-results.controller.js:15 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:134 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:141 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:102 -msgid "Download Output" -msgstr "Descargar salida" - -#: client/src/inventory-scripts/inventory-scripts.form.js:59 -msgid "" -"Drag and drop your custom inventory script file here or create one in the " -"field to import your custom inventory. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Arrastre y suelte el archivo personalizado del script de inventario aquí o " -"cree uno en el campo para importar el inventario personalizado. Consulte la " -"documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/partials/survey-maker-modal.html:77 -msgid "Drop question here to reorder" -msgstr "Arrastre y suelte una pregunta aquí para reordenar" - -#: client/src/configuration/configuration.route.js:30 -msgid "EDIT CONFIGURATION" -msgstr "EDITAR CONFIGURACION" - -#: client/features/credentials/credentials.strings.js:9 -msgid "EDIT CREDENTIAL" -msgstr "EDITAR CREDENCIAL" - -#: client/src/management-jobs/scheduler/main.js:95 -msgid "EDIT SCHEDULED JOB" -msgstr "MODIFICAR UN TRABAJO PLANIFICADO" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:17 -msgid "EDIT SURVEY PROMPT" -msgstr "EDITAR AVISO DE ENCUESTA" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:46 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:79 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:59 -msgid "ELAPSED" -msgstr "TIEMPO TRANSCURRIDO" - -#: client/lib/components/components.strings.js:9 -msgid "ENCRYPTED" -msgstr "CIFRADO" - -#: client/src/shared/smart-search/smart-search.partial.html:39 -msgid "EXAMPLES:" -msgstr "EJEMPLOS:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:15 -msgid "EXECUTE COMMAND" -msgstr "EJECUTAR COMANDO" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:46 -msgid "EXPLANATION" -msgstr "EXPLICACIÓN" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:355 -msgid "" -"Each time a job runs using this inventory, refresh the inventory from the " -"selected source before executing job tasks." -msgstr "" -"Cada vez que se ejecuta un trabajo con este inventario, actualice el " -"inventario de la fuente seleccionada antes de ejecutar tareas de trabajo." - -#: client/src/projects/projects.form.js:179 -msgid "" -"Each time a job runs using this project, perform an update to the local " -"repository prior to starting the job." -msgstr "" -"Cada vez que un trabajo se ejecuta usando este proyecto, se realizará una " -"actualización al repositorio local antes de iniciar el trabajo." - -#: client/src/credential-types/credential-types.list.js:56 -#: client/src/credentials/credentials.list.js:66 -#: client/src/inventories-hosts/inventories/inventory.list.js:97 -#: client/src/inventory-scripts/inventory-scripts.list.js:54 -#: client/src/notifications/notificationTemplates.list.js:65 -#: client/src/notifications/notificationTemplates.list.js:74 -#: client/src/scheduler/schedules.list.js:75 client/src/teams/teams.list.js:55 -#: client/src/templates/templates.list.js:103 -#: client/src/users/users.list.js:60 -msgid "Edit" -msgstr "Editar" - -#: client/src/shared/form-generator.js:1715 -#: client/src/templates/job_templates/job-template.form.js:452 -#: client/src/templates/workflows.form.js:177 -msgid "Edit Survey" -msgstr "Editar la encuesta" - -#: client/src/credential-types/credential-types.list.js:58 -msgid "Edit credenital type" -msgstr "Editar tipo de credencial" - -#: client/src/credentials/credentials.list.js:68 -msgid "Edit credential" -msgstr "Editar credenciales" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:85 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:96 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:84 -msgid "Edit group" -msgstr "Editar grupo" - -#: client/src/inventories-hosts/hosts/host.list.js:83 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:73 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:87 -msgid "Edit host" -msgstr "Editar el servidor" - -#: client/src/inventories-hosts/inventories/inventory.list.js:99 -msgid "Edit inventory" -msgstr "Editar el inventario" - -#: client/src/inventory-scripts/inventory-scripts.list.js:56 -msgid "Edit inventory script" -msgstr "Editar el script de inventario" - -#: client/src/notifications/notificationTemplates.list.js:76 -msgid "Edit notification" -msgstr "Editar la notificación" - -#: client/src/scheduler/schedules.list.js:78 -msgid "Edit schedule" -msgstr "Editar la programación" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:111 -msgid "Edit source" -msgstr "Editar fuente" - -#: client/src/teams/teams.list.js:59 -msgid "Edit team" -msgstr "Editar el equipo" - -#: client/src/templates/templates.list.js:105 -msgid "Edit template" -msgstr "Editar la plantilla" - -#: client/src/job-results/job-results.partial.html:191 -msgid "Edit the Schedule" -msgstr "Editar la planificación" - -#: client/src/job-results/job-results.partial.html:175 -#: client/src/workflow-results/workflow-results.partial.html:124 -msgid "Edit the User" -msgstr "Editar el usuario" - -#: client/src/job-results/job-results.partial.html:265 -#: client/src/job-results/job-results.partial.html:280 -#: client/src/job-results/job-results.partial.html:296 -#: client/src/job-results/job-results.partial.html:311 -#: client/src/job-results/job-results.partial.html:326 -msgid "Edit the credential" -msgstr "Editar la credencial" - -#: client/src/job-results/job-results.partial.html:206 -msgid "Edit the inventory" -msgstr "Editar el inventario" - -#: client/src/job-results/job-results.partial.html:140 -msgid "Edit the job template" -msgstr "Editar la plantilla de trabajo" - -#: client/src/job-results/job-results.partial.html:229 -#: client/src/projects/projects.list.js:105 -msgid "Edit the project" -msgstr "Editar el proyecto" - -#: client/src/scheduler/scheduled-jobs.list.js:67 -msgid "Edit the schedule" -msgstr "Editar la planificación" - -#: client/src/users/users.list.js:64 -msgid "Edit user" -msgstr "Editar el usuario" - -#: client/src/setup-menu/setup-menu.partial.html:61 -msgid "Edit {{BRAND_NAME}}'s configuration." -msgstr "Editar la configuración de {{BRAND_NAME}}." - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "" -"Either you do not have access or the SCM update process completed. Click the" -" %sRefresh%s button to view the latest status." -msgstr "" -"Usted no tiene acceso o el proceso de actualización de SCM ha sido " -"completado. Pulse sobre el botón %sActualizar%s para ver el estado más " -"reciente." - -#: client/src/job-results/job-results.partial.html:520 -msgid "Elapsed" -msgstr "Tiempo transcurrido" - -#: client/src/credentials/credentials.form.js:191 -#: client/src/users/users.form.js:51 -msgid "Email" -msgstr "Correo" - -#: client/src/templates/job_templates/job-template.form.js:288 -#: client/src/templates/job_templates/job-template.form.js:293 -msgid "Enable Concurrent Jobs" -msgstr "Activar los trabajos concurrentes" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:123 -#: client/src/templates/job_templates/job-template.form.js:264 -#: client/src/templates/job_templates/job-template.form.js:269 -msgid "Enable Privilege Escalation" -msgstr "Activar la elevación de privilegios" - -#: client/src/templates/job_templates/job-template.form.js:279 -msgid "" -"Enables creation of a provisioning callback URL. Using the URL a host can " -"contact {{BRAND_NAME}} and request a configuration update using this job " -"template." -msgstr "" -"Habilita la creación de una dirección URL para el uso de retorno de " -"llamadas. Mediante esta URL, un host puede contactar a {{BRAND_NAME}} y " -"solicitar la actualización de la configuración utilizando esta plantilla de " -"trabajo." - -#: client/src/credentials/factories/credential-form-save.factory.js:73 -msgid "Encrypted credentials are not supported." -msgstr "Credenciales cifrados no están soportados." - -#: client/src/license/license.partial.html:113 -msgid "End User License Agreement" -msgstr "Acuerdo de licencia de usuario final" - -#: client/src/inventories-hosts/hosts/host.form.js:73 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:72 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:86 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two." -msgstr "" -"Introduzca variables del inventario usando sintaxis JSON o YAML. Utilice el " -"botón de selección para elegir entre los dos." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:93 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two. Refer to the Ansible Tower documentation " -"for example syntax." -msgstr "" -"Ingrese variables de inventario por medio del uso de sintaxis JSON o YAML. " -"Utilice el botón de selección para alternar entre los dos. Consulte la " -"documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/notifications/notificationTemplates.form.js:155 -msgid "" -"Enter one HipChat channel per line. The pound symbol (#) is not required." -msgstr "" -"Ingrese un canal de HipChat por línea. El símbolo numeral (#) no es " -"necesario." - -#: client/src/notifications/notificationTemplates.form.js:362 -msgid "" -"Enter one IRC channel or username per line. The pound symbol (#) for " -"channels, and the at (@) symbol for users, are not required." -msgstr "" -"Ingrese un canal de IRC o nombre de usuario por línea. El símbolo numeral " -"(#) para canales y el símbolo arroba (@) para usuarios no son necesarios." - -#: client/src/notifications/notificationTemplates.form.js:139 -msgid "" -"Enter one Slack channel per line. The pound symbol (#) is not required." -msgstr "" -"Ingrese un canal de Slack por línea. El símbolo numeral (#) no es necesario." - -#: client/src/notifications/notificationTemplates.form.js:97 -msgid "" -"Enter one email address per line to create a recipient list for this type of" -" notification." -msgstr "" -"Ingrese una dirección de correo electrónico por línea para crear una lista " -"de destinatarios para este tipo de notificación." - -#: client/src/notifications/notificationTemplates.form.js:209 -msgid "" -"Enter one phone number per line to specify where to route SMS messages." -msgstr "" -"Ingrese un número de teléfono por línea para indicar adónde enviar los " -"mensajes de SMS." - -#: client/src/credentials/factories/become-method-change.factory.js:81 -#: client/src/credentials/factories/kind-change.factory.js:138 -msgid "" -"Enter the URL for the virtual machine which %scorresponds to your CloudForm " -"instance. %sFor example, %s" -msgstr "" -"Introduzca la URL para la máquina virtual la cual %scorresponda a su " -"instancia CloudForm. %sPor ejemplo, %s" - -#: client/src/credentials/factories/become-method-change.factory.js:71 -#: client/src/credentials/factories/kind-change.factory.js:128 -msgid "" -"Enter the URL which corresponds to your %sRed Hat Satellite 6 server. %sFor " -"example, %s" -msgstr "" -"Introduzca la URL que corresponda a su servidor %sRed Hat Satellite 6. %sPor" -" ejemplo, %s" - -#: client/src/credentials/factories/become-method-change.factory.js:49 -#: client/src/credentials/factories/kind-change.factory.js:106 -msgid "" -"Enter the hostname or IP address which corresponds to your VMware vCenter." -msgstr "" -"Introduzca el nombre de servidor o dirección IP que corresponda a su VMWare " -"vCenter." - -#: client/src/notifications/notificationTemplates.form.js:195 -msgid "" -"Enter the number associated with the \"Messaging Service\" in Twilio in the " -"format +18005550199." -msgstr "" -"Ingrese el número asociado con el \"Servicio de mensajería\" en Twilio con " -"el formato +18005550199." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:197 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:221 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:245 -msgid "" -"Enter variables using either JSON or YAML syntax. Use the radio button to " -"toggle between the two." -msgstr "" -"Ingrese variables con sintaxis JSON o YAML. Use el botón de selección para " -"alternar entre los dos." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:187 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:194 -msgid "Environment Variables" -msgstr "Variables del entorno" - -#: client/src/configuration/configuration.controller.js:348 -#: client/src/configuration/configuration.controller.js:449 -#: client/src/configuration/configuration.controller.js:483 -#: client/src/configuration/configuration.controller.js:530 -#: client/src/configuration/system-form/configuration-system.controller.js:231 -#: client/src/credentials/factories/credential-form-save.factory.js:77 -#: client/src/credentials/factories/credential-form-save.factory.js:93 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:129 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:139 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:166 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:194 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:213 -#: client/src/management-jobs/card/card.controller.js:140 -#: client/src/management-jobs/card/card.controller.js:230 -#: client/src/management-jobs/card/card.controller.js:28 -#: client/src/projects/add/projects-add.controller.js:108 -#: client/src/projects/edit/projects-edit.controller.js:156 -#: client/src/projects/edit/projects-edit.controller.js:222 -#: client/src/projects/edit/projects-edit.controller.js:238 -#: client/src/projects/list/projects-list.controller.js:169 -#: client/src/projects/list/projects-list.controller.js:198 -#: client/src/projects/list/projects-list.controller.js:225 -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:262 -#: client/src/projects/list/projects-list.controller.js:271 -#: client/src/users/add/users-add.controller.js:99 -#: client/src/users/edit/users-edit.controller.js:180 -#: client/src/users/edit/users-edit.controller.js:80 -#: client/src/users/list/users-list.controller.js:82 -msgid "Error!" -msgstr "¡Error!" - -#: client/src/activity-stream/streams.list.js:40 -msgid "Event" -msgstr "Evento" - -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Event ID" -msgstr "ID de evento" - -#: client/src/activity-stream/factories/build-description.factory.js:120 -msgid "Event summary not available" -msgstr "Resumen del evento no disponible." - -#: client/src/projects/add/projects-add.controller.js:129 -#: client/src/projects/edit/projects-edit.controller.js:265 -msgid "Example URLs for GIT SCM include:" -msgstr "Ejemplos de URLs para SCM GIT :" - -#: client/src/projects/add/projects-add.controller.js:150 -#: client/src/projects/edit/projects-edit.controller.js:285 -msgid "Example URLs for Mercurial SCM include:" -msgstr "Ejemplos de URLs para SCM Mercurial :" - -#: client/src/projects/add/projects-add.controller.js:141 -#: client/src/projects/edit/projects-edit.controller.js:276 -msgid "Example URLs for Subversion SCM include:" -msgstr "Ejemplos de URLs para SCM Subversion :" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Example: ansible_facts.ansible_distribution:\"RedHat\"" -msgstr "Ejemplo: ansible_facts.ansible_distribution:\"RedHat\"" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:76 -msgid "Existing Group" -msgstr "Grupo existente" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:125 -msgid "Existing Host" -msgstr "Host existente" - -#: client/src/job-results/job-results.controller.js:18 -#: client/src/job-results/job-results.controller.js:228 -#: client/src/standard-out/standard-out.controller.js:24 -#: client/src/standard-out/standard-out.controller.js:245 -#: client/src/workflow-results/workflow-results.controller.js:120 -#: client/src/workflow-results/workflow-results.controller.js:76 -msgid "Expand Output" -msgstr "Extender salida" - -#: client/src/license/license.partial.html:39 -msgid "Expires On" -msgstr "Fecha de expiración el" - -#: client/src/job-results/job-results.partial.html:81 -msgid "Explanation" -msgstr "Explicación" - -#: client/src/job-results/job-results.partial.html:275 -msgid "Extra Credentials" -msgstr "Credenciales adicionales" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:132 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:144 -#: client/src/job-results/job-results.partial.html:409 -#: client/src/job-submission/job-submission.partial.html:165 -#: client/src/partials/logviewer.html:8 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:105 -#: client/src/templates/job_templates/job-template.form.js:342 -#: client/src/templates/job_templates/job-template.form.js:349 -#: client/src/templates/workflows.form.js:74 -#: client/src/templates/workflows.form.js:81 -msgid "Extra Variables" -msgstr "Variables adicionales" - -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html:4 -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js:7 -msgid "FACTS" -msgstr "EVENTOS" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:64 -msgid "FAILED" -msgstr "FALLIDO" - -#: client/src/shared/smart-search/smart-search.partial.html:45 -msgid "FIELDS:" -msgstr "CAMPOS:" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:39 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:72 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:52 -msgid "FINISHED" -msgstr "FINALIZADO" - -#: client/src/inventories-hosts/hosts/host.form.js:107 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:106 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:107 -msgid "Facts" -msgstr "Eventos" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:80 -msgid "Failed" -msgstr "Fallido" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:44 -msgid "Failed Hosts" -msgstr "Servidores fallidos" - -#: client/src/users/add/users-add.controller.js:99 -msgid "Failed to add new user. POST returned status:" -msgstr "Ha fallado la creación de nuevo usuario. POST ha devuelto el estado:" - -#: client/src/credentials/factories/credential-form-save.factory.js:78 -msgid "Failed to create new Credential. POST status:" -msgstr "Ha fallado la creación de un nuevo Credencial. Estado POST :" - -#: client/src/projects/add/projects-add.controller.js:109 -msgid "Failed to create new project. POST returned status:" -msgstr "" -"Ha fallado la creación de un nuevo proyecto. POST ha devuelto el estado:" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:214 -msgid "Failed to retrieve job template extra variables." -msgstr "" -"Ha fallado la obtención de variables adicionales para la plantilla de tarea." - -#: client/src/projects/edit/projects-edit.controller.js:157 -msgid "Failed to retrieve project: %s. GET status:" -msgstr "Ha fallado la obtención del proyecto: %s. Estado GET :" - -#: client/src/users/edit/users-edit.controller.js:181 -#: client/src/users/edit/users-edit.controller.js:81 -msgid "Failed to retrieve user: %s. GET status:" -msgstr "Ha fallado la obtención del usuario: %s. Estado GET :" - -#: client/src/configuration/configuration.controller.js:450 -msgid "Failed to save settings. Returned status:" -msgstr "Ha fallado guardar los ajustes. Estado devuelto:" - -#: client/src/configuration/configuration.controller.js:484 -msgid "Failed to save toggle settings. Returned status:" -msgstr "Ha fallado el guardado de los ajustes cambiados. Estado devuelto:" - -#: client/src/credentials/factories/credential-form-save.factory.js:94 -msgid "Failed to update Credential. PUT status:" -msgstr "Ha fallado la actualización de Credencial. Estado PUT :" - -#: client/src/projects/edit/projects-edit.controller.js:222 -msgid "Failed to update project: %s. PUT status:" -msgstr "Ha fallado la actualización del proyecto: %s. Estado PUT :" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:195 -#: client/src/management-jobs/card/card.controller.js:141 -#: client/src/management-jobs/card/card.controller.js:231 -msgid "Failed updating job %s with variables. POST returned: %d" -msgstr "" -"Ha fallado la actualización del trabajo %s con variables. POST ha devuelto: " -"%d" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:24 -msgid "Failed. Click for details" -msgstr "Fallido. Pulse para obtener más información" - -#: client/src/notifications/notifications.list.js:48 -msgid "Failure" -msgstr "Fallo" - -#: client/src/scheduler/schedules.list.js:48 -msgid "Final Run" -msgstr "Última ejecución" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:59 -#: client/src/instance-groups/jobs/jobs.list.js:57 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:54 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:58 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:44 -#: client/src/job-results/job-results.partial.html:111 -#: client/src/jobs/all-jobs.list.js:66 -#: client/src/portal-mode/portal-jobs.list.js:40 -#: client/src/templates/completed-jobs.list.js:59 -msgid "Finished" -msgstr "Finalizado" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:21 -#: client/src/users/users.form.js:26 client/src/users/users.list.js:33 -msgid "First Name" -msgstr "Nombre" - -#: client/src/scheduler/schedules.list.js:38 -msgid "First Run" -msgstr "Primera ejecución" - -#: client/src/shared/smart-search/smart-search.partial.html:52 -msgid "" -"For additional information on advanced search search syntax please see the " -"Ansible Tower" -msgstr "" -"Para obtener información adicional sobre la sintaxis de búsqueda avanzada, " -"consulte Ansible Tower" - -#: client/src/credentials/factories/become-method-change.factory.js:63 -#: client/src/credentials/factories/kind-change.factory.js:120 -msgid "For example, %s" -msgstr "Por ejemplo, %s" - -#: client/src/inventories-hosts/hosts/host.form.js:36 -#: client/src/inventories-hosts/hosts/host.list.js:36 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:35 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:32 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:35 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:31 -msgid "" -"For hosts that are part of an external inventory, this flag cannot be " -"changed. It will be set by the inventory sync process." -msgstr "" -"Para servidores que son parte de un inventario externo, este indicador de " -"estado no puede ser cambiado. Será establecido en el proceso de " -"sincronización del inventario." - -#: client/src/templates/job_templates/job-template.form.js:54 -msgid "" -"For job templates, select run to execute the playbook. Select check to only " -"check playbook syntax, test environment setup, and report problems without " -"executing the playbook." -msgstr "" -"En lo que respecta a plantillas de trabajo, seleccione ejecutar para " -"ejecutar el manual. Seleccione marcar para marcar únicamente la sintaxis del" -" manual, probar la configuración del entorno e informar problemas sin " -"ejecutar el manual." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:118 -msgid "" -"For more information and examples see %sthe Patterns topic at " -"docs.ansible.com%s." -msgstr "" -"Para más información y ejemplos, observe el tema llamado %sPatterns en " -"docs.ansible.com%s." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:109 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:96 -#: client/src/job-results/job-results.partial.html:336 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:87 -#: client/src/templates/job_templates/job-template.form.js:144 -#: client/src/templates/job_templates/job-template.form.js:154 -msgid "Forks" -msgstr "Forks" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:172 -msgid "Frequency Details" -msgstr "Información sobre la frecuencia" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js:45 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js:46 -msgid "GROUPS" -msgstr "GRUPOS" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:107 -msgid "GitHub" -msgstr "GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:108 -msgid "GitHub Org" -msgstr "GitHub Org" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:109 -msgid "GitHub Team" -msgstr "Equipo GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:110 -msgid "Google OAuth2" -msgstr "Google OAuth2" - -#: client/src/teams/teams.form.js:155 client/src/users/users.form.js:214 -msgid "Grant Permission" -msgstr "Conceder permiso" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Gray" -msgstr "Gris" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Green" -msgstr "Verde" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:52 -msgid "Group Variables" -msgstr "Variables de grupo" - -#: client/src/setup-menu/setup-menu.partial.html:5 -msgid "" -"Group all of your content to manage permissions across departments in your " -"company." -msgstr "" -"Agrupar todo su contenido para administrar permisos a través de los " -"diferentes departamentos en su compañía." - -#: client/src/inventories-hosts/hosts/host.form.js:115 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:31 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:89 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:88 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:115 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:167 -msgid "Groups" -msgstr "Grupos" - -#: client/lib/components/components.strings.js:12 -msgid "HIDE" -msgstr "OCULTAR" - -#: client/lib/components/components.strings.js:39 -msgid "HINT: Drag and drop an SSH private key file on the field below." -msgstr "" -"SUGERENCIA: Arrastre y suelte el archivo de clave privada SSH en el " -"siguiente campo." - -#: client/src/activity-stream/get-target-title.factory.js:41 -#: client/src/inventories-hosts/hosts/hosts.partial.html:9 -#: client/src/inventories-hosts/hosts/main.js:80 -#: client/src/inventories-hosts/inventories/inventories.partial.html:14 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.route.js:18 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js:17 -msgid "HOSTS" -msgstr "SERVIDORES" - -#: client/src/notifications/notificationTemplates.form.js:320 -#: client/src/notifications/notificationTemplates.form.js:321 -msgid "HTTP Headers" -msgstr "Cabeceras HTTP" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "Hide Activity Stream" -msgstr "Ocultar flujo de actividad" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:23 -msgid "High" -msgstr "Alto" - -#: client/src/credentials/credentials.form.js:139 -#: client/src/notifications/notificationTemplates.form.js:83 -msgid "Host" -msgstr "Servidor" - -#: client/src/credentials/factories/become-method-change.factory.js:52 -#: client/src/credentials/factories/kind-change.factory.js:109 -msgid "Host (Authentication URL)" -msgstr "Servidor (URL de autentificación)" - -#: client/src/templates/job_templates/job-template.form.js:324 -#: client/src/templates/job_templates/job-template.form.js:333 -msgid "Host Config Key" -msgstr "Clave de configuración del servidor" - -#: client/src/inventories-hosts/hosts/host.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:39 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:39 -msgid "Host Enabled" -msgstr "Servidor habilitado" - -#: client/src/inventories-hosts/hosts/host.form.js:46 -#: client/src/inventories-hosts/hosts/host.form.js:57 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:45 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:56 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:45 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:56 -msgid "Host Name" -msgstr "Nombre de Host" - -#: client/src/inventories-hosts/hosts/host.form.js:80 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:79 -msgid "Host Variables" -msgstr "Variables de Host" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is available" -msgstr "El host está disponible" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is available. Click to toggle." -msgstr "El host está disponible. Haga clic para alternar." - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is not available" -msgstr "El host no está disponible" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is not available. Click to toggle." -msgstr "El host no está disponible. Haga clic para alternar." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:39 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:98 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:57 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:56 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:167 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:176 -#: client/src/job-results/job-results.partial.html:504 -msgid "Hosts" -msgstr "Servidores" - -#: client/src/license/license.partial.html:52 -msgid "Hosts Available" -msgstr "Servidores disponibles" - -#: client/src/license/license.partial.html:64 -msgid "Hosts Remaining" -msgstr "Servidores restantes" - -#: client/src/license/license.partial.html:58 -msgid "Hosts Used" -msgstr "Servidores utilizados" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "Hosts are imported to" -msgstr "Los hosts se importan a" - -#: client/src/license/license.partial.html:121 -msgid "I agree to the End User License Agreement" -msgstr "Yo acepto el Acuerdo de licencia de usuario final." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:27 -#: client/src/instance-groups/jobs/jobs.list.js:26 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:38 -msgid "ID" -msgstr "ID" - -#: client/src/partials/job-template-details.html:2 -msgid "INFO" -msgstr "INFORMACIÓN" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 -msgid "INITIATED BY" -msgstr "INICIALIZADO POR" - -#: client/src/inventories-hosts/inventories/insights/insights.route.js:7 -msgid "INSIGHTS" -msgstr "OBSERVACIONES" - -#: client/src/instance-groups/instance-groups.list.js:6 -#: client/src/instance-groups/instance-groups.list.js:7 -#: client/src/instance-groups/instance-groups.route.js:10 -#: client/src/instance-groups/list/instance-groups-list.partial.html:3 -msgid "INSTANCE GROUPS" -msgstr "GRUPOS DE INSTANCIA" - -#: client/src/instance-groups/instance-group.partial.html:27 -msgid "INSTANCES" -msgstr "INSTANCIAS" - -#: client/src/activity-stream/get-target-title.factory.js:14 -#: client/src/inventories-hosts/hosts/hosts.partial.html:8 -#: client/src/inventories-hosts/inventories/inventories.partial.html:13 -#: client/src/inventories-hosts/inventories/inventories.route.js:8 -#: client/src/inventories-hosts/inventories/inventory.list.js:14 -#: client/src/inventories-hosts/inventories/inventory.list.js:15 -#: client/src/main-menu/main-menu.partial.html:104 -#: client/src/main-menu/main-menu.partial.html:27 -#: client/src/organizations/linkout/organizations-linkout.route.js:143 -#: client/src/organizations/list/organizations-list.controller.js:66 -msgid "INVENTORIES" -msgstr "INVENTARIOS" - -#: client/src/job-submission/job-submission.partial.html:346 -#: client/src/partials/job-template-details.html:2 -msgid "INVENTORY" -msgstr "INVENTARIO" - -#: client/src/inventory-scripts/inventory-scripts.form.js:23 -msgid "INVENTORY SCRIPT" -msgstr "SCRIPT DE INVENTARIO" - -#: client/src/activity-stream/get-target-title.factory.js:35 -#: client/src/inventory-scripts/inventory-scripts.list.js:12 -#: client/src/inventory-scripts/main.js:66 -msgid "INVENTORY SCRIPTS" -msgstr "SCRIPTS DE INVENTARIO" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js:8 -msgid "INVENTORY SOURCES" -msgstr "FUENTES DE INVENTARIO" - -#: client/src/notifications/notificationTemplates.form.js:348 -msgid "IRC Nick" -msgstr "Alias en IRC" - -#: client/src/notifications/notificationTemplates.form.js:337 -msgid "IRC Server Address" -msgstr "Dirección del servidor IRC" - -#: client/src/notifications/shared/type-change.service.js:58 -msgid "IRC Server Password" -msgstr "Contraseña del servidor IRC" - -#: client/src/notifications/shared/type-change.service.js:57 -msgid "IRC Server Port" -msgstr "Puerto del servidor IRC" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:79 -msgid "ISSUE: {{report.rule.description}}" -msgstr "PROBLEMA: {{report.rule.description}}" - -#: client/src/shared/paginate/paginate.partial.html:43 -msgid "ITEMS" -msgstr "ELEMENTOS" - -#: client/src/login/authenticationServices/timer.factory.js:157 -msgid "Idle Session" -msgstr "Sesión inactiva" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "If blank, all groups above are created except" -msgstr "Si está en blanco, se crean todos los grupos de arriba, excepto" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:343 -msgid "" -"If checked, all variables for child groups and hosts will be removed and " -"replaced by those found on the external source." -msgstr "" -"Si las opciones están marcadas, todas las variables de los grupos de hijos y" -" hosts se eliminarán y reemplazarán con aquellas que se hallen en la fuente " -"externa." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:331 -msgid "" -"If checked, any hosts and groups that were previously present on the " -"external source but are now removed will be removed from the Tower " -"inventory. Hosts and groups that were not managed by the inventory source " -"will be promoted to the next manually created group or if there is no " -"manually created group to promote them into, they will be left in the " -"\"all\" default group for the inventory." -msgstr "" -"Si las opciones están marcadas, cualquier grupo o host que estuvo presente " -"previamente en la fuente externa pero que ahora se eliminó, se eliminará del" -" inventario de Tower. Los hosts y grupos que no fueron administrados por la " -"fuente del inventario serán promovidos al siguiente grupo creado manualmente" -" o, si no hay un grupo creado manualmente al que puedan ser promovidos, se " -"los dejará en el grupo predeterminado \"Todo\" para el inventario." - -#: client/src/templates/job_templates/job-template.form.js:267 -msgid "If enabled, run this playbook as an administrator." -msgstr "" -"Si se encuentra habilitada la opción, ejecute este manual como " -"administrador." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:120 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Si se habilita, muestra los cambios realizados por las tareas de Ansible, " -"donde sea compatible. Esto es equivalente al modo --diff de Ansible." - -#: client/src/templates/job_templates/job-template.form.js:251 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Si se habilita, muestra los cambios realizados por las tareas de Ansible, " -"donde sea compatible. Esto es equivalente al modo --diff de Ansible." - -#: client/src/templates/job_templates/job-template.form.js:291 -msgid "If enabled, simultaneous runs of this job template will be allowed." -msgstr "" -"Si se habilita esta opción, la ejecución de esta plantilla de trabajo en " -"paralelo será permitida." - -#: client/src/templates/job_templates/job-template.form.js:302 -msgid "" -"If enabled, use cached facts if available and store discovered facts in the " -"cache." -msgstr "" -"Si se habilita, usa los eventos almacenados en caché, si están disponibles," -" y almacena los elementos detectados en la caché." - -#: client/src/credentials/credentials.form.js:52 -msgid "" -"If no organization is given, the credential can only be used by the user " -"that creates the credential. Organization admins and system administrators " -"can assign an organization so that roles for the credential can be assigned " -"to users and teams in that organization." -msgstr "" -"Si no se especifica ninguna organización, el credencial puede ser sólo " -"utilizado por el usuario que ha creado dicho credencial. Administradores de " -"organización y administradores de sistema pueden asignar una organización " -"para que los roles puedan permitir que los credenciales puedan ser asignados" -" a usuarios y equipos en esa organización" - -#: client/src/license/license.partial.html:70 -msgid "" -"If you are ready to upgrade, please contact us by clicking the button below" -msgstr "" -"Si usted está listo para la actualización, por favor contáctenos pulsando el" -" siguiente botón" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:173 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:254 -msgid "Image ID:" -msgstr "ID de la imagen:" - -#: client/src/inventories-hosts/hosts/host.form.js:34 -#: client/src/inventories-hosts/hosts/host.list.js:34 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:33 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:30 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:33 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:29 -msgid "" -"Indicates if a host is available and should be included in running jobs." -msgstr "" -"Indica si el servidor está disponible y debe ser incluído en trabajos en " -"ejecución." - -#: client/src/activity-stream/activity-detail.form.js:31 -#: client/src/activity-stream/streams.list.js:33 -msgid "Initiated by" -msgstr "Inicializado por" - -#: client/src/credential-types/credential-types.form.js:53 -#: client/src/credential-types/credential-types.form.js:61 -msgid "Injector Configuration" -msgstr "Configuración del inyector" - -#: client/src/credential-types/credential-types.form.js:39 -#: client/src/credential-types/credential-types.form.js:47 -msgid "Input Configuration" -msgstr "Configuración de entrada" - -#: client/src/inventories-hosts/hosts/host.form.js:123 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:122 -msgid "Insights" -msgstr "Insights" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:69 -msgid "Insights Credential" -msgstr "Credencial de Insights" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:145 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:148 -msgid "Instance Filters" -msgstr "Filtros de instancias" - -#: client/src/job-results/job-results.partial.html:369 -msgid "Instance Group" -msgstr "Grupo de instancias" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:75 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:78 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:81 -#: client/src/organizations/organizations.form.js:38 -#: client/src/organizations/organizations.form.js:41 -#: client/src/setup-menu/setup-menu.partial.html:54 -#: client/src/templates/job_templates/job-template.form.js:191 -#: client/src/templates/job_templates/job-template.form.js:194 -msgid "Instance Groups" -msgstr "Grupos de instancias" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "Instance ID" -msgstr "ID de instancia" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:174 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:255 -msgid "Instance ID:" -msgstr "ID de instancia:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:175 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:256 -msgid "Instance Type:" -msgstr "Tipo de instancia:" - -#: client/src/license/license.partial.html:11 -msgid "Invalid License" -msgstr "Licencia no valida" - -#: client/src/license/license.controller.js:63 -#: client/src/license/license.controller.js:70 -msgid "Invalid file format. Please upload valid JSON." -msgstr "Formato de fichero inválido. Por favor cargue un JSON válido." - -#: client/lib/components/components.strings.js:16 -msgid "Invalid input for this type." -msgstr "Entrada no válida para este tipo." - -#: client/src/login/loginModal/loginModal.partial.html:34 -msgid "Invalid username and/or password. Please try again." -msgstr "Nombre de usuario o contraseña inválida. Por favor intente de nuevo." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:122 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:52 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:50 -#: client/src/organizations/linkout/organizations-linkout.route.js:155 -msgid "Inventories" -msgstr "Inventarios" - -#: client/src/inventories-hosts/hosts/host.list.js:69 -#: client/src/inventories-hosts/inventories/inventory.list.js:80 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/job-results/job-results.partial.html:201 -#: client/src/job-submission/job-submission.partial.html:17 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:58 -#: client/src/templates/job_templates/job-template.form.js:66 -#: client/src/templates/job_templates/job-template.form.js:80 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:72 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:82 -msgid "Inventory" -msgstr "Inventario" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:110 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:124 -msgid "Inventory File" -msgstr "Archivo de inventario" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 -#: client/src/setup-menu/setup-menu.partial.html:41 -msgid "Inventory Scripts" -msgstr "Scripts de inventario" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:46 -msgid "Inventory Sync" -msgstr "Sincronización de inventario" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:55 -msgid "Inventory Sync Failures" -msgstr "Errores de sincronización de inventario" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:93 -msgid "Inventory Variables" -msgstr "Variables de inventario" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:66 -msgid "Inventory contains 0 hosts." -msgstr "El inventario contiene 0 hosts." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:4 -msgid "JOB STATUS" -msgstr "ESTADO DEL TRABAJO" - -#: client/src/templates/job_templates/job-template.form.js:22 -msgid "JOB TEMPLATE" -msgstr "PLANTILLA DE TRABAJO" - -#: client/src/organizations/linkout/organizations-linkout.route.js:256 -#: client/src/organizations/list/organizations-list.controller.js:78 -#: client/src/portal-mode/portal-job-templates.list.js:13 -#: client/src/portal-mode/portal-job-templates.list.js:14 -msgid "JOB TEMPLATES" -msgstr "PLANTILLAS DE TRABAJO" - -#: client/src/activity-stream/get-target-title.factory.js:32 -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:118 -#: client/src/instance-groups/instance-group.partial.html:28 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:27 -#: client/src/instance-groups/jobs/jobs-list.route.js:9 -#: client/src/jobs/jobs.route.js:15 -#: client/src/main-menu/main-menu.partial.html:122 -#: client/src/main-menu/main-menu.partial.html:43 -#: client/src/portal-mode/portal-jobs.list.js:13 -#: client/src/portal-mode/portal-jobs.list.js:17 -msgid "JOBS" -msgstr "TRABAJOS" - -#: client/src/job-submission/job-submission.partial.html:173 -msgid "JSON" -msgstr "JSON" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:198 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:222 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:246 -msgid "JSON:" -msgstr "JSON:" - -#: client/src/job-results/job-results.partial.html:384 -#: client/src/job-submission/job-submission.partial.html:228 -#: client/src/templates/job_templates/job-template.form.js:200 -#: client/src/templates/job_templates/job-template.form.js:207 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:127 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:135 -msgid "Job Tags" -msgstr "Etiquetas de trabajo" - -#: client/src/templates/templates.list.js:61 -msgid "Job Template" -msgstr "Plantilla de trabajo" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:36 -#: client/src/organizations/linkout/organizations-linkout.route.js:268 -msgid "Job Templates" -msgstr "Plantillas de trabajo" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:32 -#: client/src/job-results/job-results.partial.html:159 -#: client/src/job-submission/job-submission.partial.html:202 -#: client/src/templates/job_templates/job-template.form.js:47 -#: client/src/templates/job_templates/job-template.form.js:55 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:103 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:92 -msgid "Job Type" -msgstr "Tipo de trabajo" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:46 -msgid "" -"Job details are not available for this job. Please download to view " -"standard out." -msgstr "" -"Los detalles de la tarea no están disponibles para esta tarea. Descargue " -"para ver la salida estándar." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 -#: client/src/configuration/configuration.partial.html:16 -#: client/src/jobs/jobs.partial.html:7 -msgid "Jobs" -msgstr "Trabajos" - -#: client/src/job-results/job-results.controller.js:269 -#: client/src/job-results/job-results.controller.js:366 -msgid "Jump to last line of standard out." -msgstr "Ir a la última línea de la salida estándar." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:61 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:154 -#: client/src/shared/smart-search/smart-search.partial.html:14 -msgid "Key" -msgstr "Clave" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:176 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:257 -msgid "Key Name:" -msgstr "Nombre de la clave:" - -#: client/src/credential-types/credential-types.list.js:31 -#: client/src/credentials/credentials.list.js:33 -msgid "Kind" -msgstr "Tipo" - -#: client/src/job-submission/job-submission.partial.html:6 -msgid "LAUNCH JOB" -msgstr "EJECUTAR TAREA" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:86 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:66 -msgid "LAUNCH TYPE" -msgstr "TIPO DE EJECUCIÓN" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:111 -msgid "LDAP" -msgstr "LDAP" - -#: client/src/license/license.route.js:19 -msgid "LICENSE" -msgstr "LICENCIA" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:58 -msgid "LICENSE ERROR" -msgstr "ERROR DE LICENCIA" - -#: client/src/main-menu/main-menu.partial.html:83 -msgid "LOG OUT" -msgstr "CERRAR SESIÓN" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:68 -#: client/src/instance-groups/jobs/jobs.list.js:66 -#: client/src/job-results/job-results.partial.html:434 -#: client/src/job-results/job-results.partial.html:443 -#: client/src/jobs/all-jobs.list.js:74 -#: client/src/templates/job_templates/job-template.form.js:234 -#: client/src/templates/job_templates/job-template.form.js:238 -#: client/src/templates/templates.list.js:43 -#: client/src/templates/workflows.form.js:62 -#: client/src/templates/workflows.form.js:67 -msgid "Labels" -msgstr "Etiquetas" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:25 -#: client/src/users/users.form.js:33 client/src/users/users.list.js:37 -msgid "Last Name" -msgstr "Apellidos" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:56 -msgid "Last Sync" -msgstr "Última sincronización" - -#: client/src/projects/projects.list.js:56 -msgid "Last Updated" -msgstr "Última actualización" - -#: client/src/portal-mode/portal-job-templates.list.js:36 -#: client/src/shared/form-generator.js:1707 -#: client/src/templates/templates.list.js:80 -msgid "Launch" -msgstr "Ejecutar" - -#: client/src/management-jobs/card/card.partial.html:23 -msgid "Launch Management Job" -msgstr "Ejecutar trabajo de gestión" - -#: client/src/job-results/job-results.partial.html:170 -#: client/src/job-results/job-results.partial.html:185 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:76 -msgid "Launched By" -msgstr "Ejecutado por" - -#: client/src/job-submission/job-submission.partial.html:99 -msgid "" -"Launching this job requires the passwords listed below. Enter and confirm " -"each password before continuing." -msgstr "" -"Ejecutar esta tarea requiere las siguientes contraseñas. Ingrese y confirme " -"cada contraseña antes de continuar." - -#: client/features/credentials/legacy.credentials.js:357 -msgid "Legacy state configuration for does not exist" -msgstr "No existe la configuración del estado heredado de" - -#: client/src/license/license.controller.js:40 -#: client/src/license/license.partial.html:8 -msgid "License" -msgstr "Licencia" - -#: client/src/license/license.partial.html:104 -msgid "License File" -msgstr "Fichero de licencia" - -#: client/src/license/license.partial.html:33 -msgid "License Key" -msgstr "Clave de licencia" - -#: client/src/license/license.controller.js:40 -msgid "License Management" -msgstr "Gestión de licencia" - -#: client/src/license/license.partial.html:21 -msgid "License Type" -msgstr "Tipo de licencia" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:55 -#: client/src/job-results/job-results.partial.html:347 -#: client/src/job-submission/job-submission.partial.html:220 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:92 -#: client/src/templates/job_templates/job-template.form.js:160 -#: client/src/templates/job_templates/job-template.form.js:164 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:113 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:120 -msgid "Limit" -msgstr "Límite" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:186 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:268 -msgid "Limit to hosts having a tag:" -msgstr "Se limita a hosts que tengan una etiqueta:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:188 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:270 -msgid "Limit to hosts using either key pair:" -msgstr "Se limita a hosts que utilicen un par de claves:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "Limit to hosts where the Name tag begins with" -msgstr "Se limita a hosts en los que la etiqueta Nombre comience con" - -#: client/src/shared/socket/socket.service.js:168 -msgid "Live events: attempting to connect to the server." -msgstr "Eventos en directo: intentando conectar al servidor." - -#: client/src/shared/socket/socket.service.js:172 -msgid "" -"Live events: connected. Pages containing job status information will " -"automatically update in real-time." -msgstr "" -"Eventos en directo: Páginas que contienen información del estado de un " -"trabajo serán actualizados automáticamente en tiempo real." - -#: client/src/shared/socket/socket.service.js:176 -msgid "Live events: error connecting to the server." -msgstr "Eventos en directo: error al conectar al servidor." - -#: client/src/shared/form-generator.js:1983 -msgid "Loading..." -msgstr "Cargando..." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:133 -msgid "Local Time Zone" -msgstr "Huso horario local" - -#: client/src/main-menu/main-menu.partial.html:188 -msgid "Log Out" -msgstr "Cerrar sesión" - -#: client/src/configuration/system-form/configuration-system.controller.js:225 -msgid "Log aggregator test failed.
Detail:" -msgstr "Error en la prueba del agregador de registros.
Detalles:" - -#: client/src/configuration/system-form/configuration-system.controller.js:218 -msgid "Log aggregator test successful." -msgstr "Se realizó correctamente la prueba del agregador de registros." - -#: client/src/configuration/system-form/configuration-system.controller.js:89 -msgid "Logging" -msgstr "Iniciando sesión" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:35 -msgid "Low" -msgstr "Bajo" - -#: client/src/management-jobs/card/card.partial.html:6 -#: client/src/management-jobs/card/card.route.js:21 -msgid "MANAGEMENT JOBS" -msgstr "TAREAS DE GESTIÓN" - -#: client/src/portal-mode/portal-mode.route.js:12 -msgid "MY VIEW" -msgstr "MI VISTA" - -#: client/src/credentials/credentials.form.js:67 -#: client/src/job-submission/job-submission.partial.html:356 -msgid "Machine" -msgstr "Máquina" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:60 -#: client/src/job-results/job-results.partial.html:260 -msgid "Machine Credential" -msgstr "Credenciales de máquina" - -#: client/src/setup-menu/setup-menu.partial.html:36 -msgid "" -"Manage the cleanup of old job history, activity streams, data marked for " -"deletion, and system tracking info." -msgstr "" -"Gestionar la limpieza del histórico de trabajos antiguos, flujos de " -"actividad, datos marcados para eliminación e información de sistema de " -"rastreo." - -#: client/src/setup-menu/setup-menu.partial.html:35 -msgid "Management Jobs" -msgstr "Trabajos de gestión" - -#: client/src/projects/list/projects-list.controller.js:89 -msgid "Manual projects do not require a schedule" -msgstr "Los proyectos manuales no necesitan de una planificación." - -#: client/src/projects/edit/projects-edit.controller.js:141 -#: client/src/projects/list/projects-list.controller.js:88 -msgid "Manual projects do not require an SCM update" -msgstr "Los proyectos manuales no necesitan una actualización del SCM" - -#: client/src/login/loginModal/loginModal.partial.html:28 -msgid "Maximum per-user sessions reached. Please sign in." -msgstr "" -"Máximo número de sesiones por usuario alcanzado. Por favor inicie sesión." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:29 -msgid "Medium" -msgstr "Medio" - -#: client/src/configuration/system-form/configuration-system.controller.js:90 -msgid "Misc. System" -msgstr "Miscelánea del sistema" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:27 -msgid "Missing. Click for details" -msgstr "Desaparecido. Pulse para obtener más información" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:22 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:30 -msgid "Module" -msgstr "Módulo" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:53 -msgid "Module Args" -msgstr "Argumentos del módulo" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:25 -msgid "Most recent job failed. Click to view jobs." -msgstr "Error en la tarea más reciente. Haga clic para ver las tareas." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:29 -msgid "Most recent job successful. Click to view jobs." -msgstr "" -"La tarea más reciente se completó correctamente. Haga clic para ver las " -"tareas." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:77 -msgid "Multiple Choice Options" -msgstr "Opciones de selección múltiple" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:4 -#: client/src/portal-mode/portal-mode-layout.partial.html:11 -msgid "My Jobs" -msgstr "Mis trabajos" - -#: client/src/main-menu/main-menu.partial.html:160 -msgid "My View" -msgstr "Mi vista" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:19 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:19 -msgid "NAME" -msgstr "NOMBRE" - -#: client/features/credentials/credentials.strings.js:24 -msgid "NEW CREDENTIAL" -msgstr "NUEVA CREDENCIAL" - -#: client/src/credential-types/credential-types.form.js:16 -msgid "NEW CREDENTIAL TYPE" -msgstr "NUEVO TIPO DE CREDENCIAL" - -#: client/src/inventory-scripts/inventory-scripts.form.js:16 -msgid "NEW CUSTOM INVENTORY" -msgstr "NUEVO INVENTARIO PERSONALIZADO" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:34 -msgid "NEW INVENTORY" -msgstr "NUEVO INVENTARIO" - -#: client/src/templates/job_templates/job-template.form.js:19 -msgid "NEW JOB TEMPLATE" -msgstr "NEVA PLANTILLA DE TRABAJO" - -#: client/src/notifications/notificationTemplates.form.js:16 -msgid "NEW NOTIFICATION TEMPLATE" -msgstr "NUEVA PLANTILLA DE NOTIFICACION" - -#: client/src/organizations/organizations.form.js:18 -msgid "NEW ORGANIZATION" -msgstr "NUEVA ORGANIZACION" - -#: client/src/projects/projects.form.js:16 -msgid "NEW PROJECT" -msgstr "NUEVO PROYECTO" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:28 -msgid "NEW SMART INVENTORY" -msgstr "NUEVO INVENTARIO INTELIGENTE" - -#: client/src/teams/teams.form.js:16 -msgid "NEW TEAM" -msgstr "NUEVO EQUIPO" - -#: client/src/users/users.form.js:16 -msgid "NEW USER" -msgstr "NUEVO USUARIO" - -#: client/src/templates/workflows.form.js:17 -msgid "NEW WORKFLOW JOB TEMPLATE" -msgstr "NUEVA PLANTILLA DE FLUJO DE TRABAJO" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:38 -msgid "NO HOSTS HAVE BEEN CREATED" -msgstr "NO SE CREARON HOSTS" - -#: client/lib/components/components.strings.js:35 -msgid "NO OPTIONS AVAILABLE" -msgstr "NO HAY OPCIONES DISPONIBLES" - -#: client/src/login/loginModal/loginModal.partial.html:89 -msgid "NOTICE" -msgstr "AVISO" - -#: client/src/notifications/notificationTemplates.form.js:21 -msgid "NOTIFICATION TEMPLATE" -msgstr "PLANTILLA DE NOTIFICACIÓN" - -#: client/src/activity-stream/get-target-title.factory.js:26 -#: client/src/notifications/notificationTemplates.list.js:14 -msgid "NOTIFICATION TEMPLATES" -msgstr "PLANTILLAS DE NOTIFICACIÓN" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js:9 -#: client/src/management-jobs/notifications/notification.route.js:46 -#: client/src/notifications/main.js:43 client/src/notifications/main.js:91 -msgid "NOTIFICATIONS" -msgstr "NOTIFICACIONES" - -#: client/src/credential-types/credential-types.form.js:27 -#: client/src/credential-types/credential-types.list.js:24 -#: client/src/credentials/credentials.form.js:32 -#: client/src/credentials/credentials.list.js:26 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:14 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:13 -#: client/src/instance-groups/instance-groups.list.js:15 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:35 -#: client/src/instance-groups/instances/instances-list.partial.html:15 -#: client/src/instance-groups/instances/instances.list.js:14 -#: client/src/instance-groups/jobs/jobs.list.js:34 -#: client/src/instance-groups/list/instance-groups-list.partial.html:26 -#: client/src/inventories-hosts/hosts/host.list.js:61 -#: client/src/inventories-hosts/inventories/inventory.list.js:47 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:45 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:33 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:51 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:39 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:45 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:45 -#: client/src/inventory-scripts/inventory-scripts.form.js:28 -#: client/src/inventory-scripts/inventory-scripts.list.js:20 -#: client/src/jobs/all-jobs.list.js:43 -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 -#: client/src/notifications/notificationTemplates.form.js:32 -#: client/src/notifications/notificationTemplates.list.js:32 -#: client/src/notifications/notifications.list.js:26 -#: client/src/organizations/organizations.form.js:26 -#: client/src/portal-mode/portal-job-templates.list.js:23 -#: client/src/portal-mode/portal-jobs.list.js:35 -#: client/src/projects/projects.form.js:29 -#: client/src/projects/projects.list.js:37 -#: client/src/scheduler/scheduled-jobs.list.js:31 -#: client/src/scheduler/schedules.list.js:33 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:19 -#: client/src/teams/teams.form.js:124 client/src/teams/teams.form.js:25 -#: client/src/teams/teams.list.js:23 -#: client/src/templates/completed-jobs.list.js:46 -#: client/src/templates/job_templates/job-template.form.js:34 -#: client/src/templates/templates.list.js:24 -#: client/src/templates/workflows.form.js:32 -#: client/src/users/users.form.js:142 client/src/users/users.form.js:168 -#: client/src/users/users.form.js:194 -msgid "Name" -msgstr "Nombre" - -#: client/src/credentials/credentials.form.js:71 -msgid "Network" -msgstr "Red" - -#: client/src/job-results/job-results.partial.html:306 -msgid "Network Credential" -msgstr "Credenciales de Red" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:81 -msgid "New Group" -msgstr "Nuevo grupo" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:130 -msgid "New Host" -msgstr "Nuevo host" - -#: client/src/users/add/users-add.controller.js:91 -msgid "New user successfully created!" -msgstr "¡Nuevo usuario creado correctamente!" - -#: client/src/scheduler/scheduled-jobs.list.js:51 -#: client/src/scheduler/schedules.list.js:43 -msgid "Next Run" -msgstr "Siguiente ejecución" - -#: client/src/credentials/credentials.list.js:21 -msgid "No Credentials Have Been Created" -msgstr "Ningún credencial ha sido creado" - -#: client/src/job-submission/lists/credential/job-sub-cred-list.controller.js:44 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:140 -msgid "No Credentials Matching This Type Have Been Created" -msgstr "No se crearon credenciales que coincidan con este tipo" - -#: client/src/job-results/host-event/host-event-codemirror.partial.html:3 -msgid "No JSON data returned by the module" -msgstr "El módulo no arrojó datos JSON" - -#: client/src/projects/projects.list.js:20 -msgid "No Projects Have Been Created" -msgstr "No se crearon proyectos" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:50 -msgid "No Remediation Playbook Available" -msgstr "No hay un playbook de reparación disponible" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "No SCM Configuration" -msgstr "Ninguna configuración SCM" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:9 -msgid "No SCM updates have run for this project" -msgstr "Ninguna actualización SCM ha sido ejecutada para este proyecto" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:17 -msgid "No Teams exist" -msgstr "No existe ningún equipo" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "No Updates Available" -msgstr "No existen actualizaciones disponibles" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:18 -msgid "No Users exist" -msgstr "No existe ningún usuario" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:23 -#: client/src/templates/completed-jobs.list.js:24 -msgid "No completed jobs" -msgstr "No hay trabajos completados" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:63 -msgid "No data is available. There are no issues to report." -msgstr "No hay datos disponibles. No hay problemas para informar." - -#: client/src/license/license.controller.js:39 -msgid "No file selected." -msgstr "Ningún fichero seleccionado." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:62 -msgid "No hosts with failures. Click for details." -msgstr "No hay hosts con fallos. Haga clic para obtener más información." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:47 -msgid "No inventory sync failures. Click for details." -msgstr "" -"No hay fallos en la sincronización de inventario. Haga clic para obtener más" -" información." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:16 -msgid "No job data" -msgstr "No hay datos de tareas" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:75 -msgid "No job data available." -msgstr "No hay datos de tareas disponibles." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:22 -msgid "No job failures" -msgstr "No hay fallos en las tareas" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:54 -msgid "No job templates were recently used." -msgstr "Ninguna plantilla de trabajo fue recientemente utilizada." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:9 -#: client/src/instance-groups/jobs/jobs.list.js:9 -#: client/src/jobs/all-jobs.list.js:18 -msgid "No jobs have yet run." -msgstr "Ningún trabajo ha sido ejecutado todavía." - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:44 -msgid "No jobs were recently run." -msgstr "Ningún trabajo ha sido recientemente ejecutado." - -#: client/src/teams/teams.form.js:121 client/src/users/users.form.js:191 -msgid "No permissions have been granted" -msgstr "Ningún permiso concedido" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:17 -msgid "No recent job data available for this host." -msgstr "No hay datos de tareas recientes disponibles para este host." - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:75 -msgid "No recent job data available for this inventory." -msgstr "No hay datos de tareas recientes disponibles para este inventario." - -#: client/src/notifications/notification-templates-list/list.controller.js:86 -msgid "No recent notifications." -msgstr "No hay notificaciones recientes" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:36 -#: client/src/shared/form-generator.js:1879 -#: client/src/shared/list-generator/list-generator.factory.js:240 -msgid "No records matched your search." -msgstr "No existe registros que coincidan con su búsqueda." - -#: client/src/scheduler/scheduled-jobs.list.js:16 -msgid "No schedules exist" -msgstr "No existen planificaciones" - -#: client/src/job-submission/job-submission.partial.html:348 -#: client/src/job-submission/job-submission.partial.html:353 -msgid "None selected" -msgstr "Ninguno seleccionado" - -#: client/src/users/add/users-add.controller.js:10 -#: client/src/users/edit/users-edit.controller.js:10 -#: client/src/users/list/users-list.controller.js:10 -msgid "Normal User" -msgstr "Usuario normal" - -#: client/src/projects/list/projects-list.controller.js:91 -msgid "Not configured for SCM" -msgstr "No configurado para SCM" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:52 -msgid "Not configured for inventory sync." -msgstr "No configurado para la sincronización de inventario." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -msgid "" -"Note that only hosts directly in this group can be disassociated. Hosts in " -"sub-groups must be disassociated directly from the sub-group level that they" -" belong." -msgstr "" -"Tenga en cuenta que solo se pueden desasociar los hosts asociados " -"directamente a este grupo. Los hosts en subgrupos deben ser desasociados del" -" nivel de subgrupo al que pertenecen." - -#: client/src/notifications/notificationTemplates.form.js:288 -#: client/src/notifications/notificationTemplates.form.js:289 -msgid "Notification Color" -msgstr "Color de notificación" - -#: client/src/notifications/notification-templates-list/list.controller.js:113 -msgid "Notification Failed." -msgstr "Notificación fallida" - -#: client/src/notifications/notificationTemplates.form.js:277 -msgid "Notification Label" -msgstr "Etiqueta de Notificación" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 -msgid "Notification Templates" -msgstr "Plantillas de notificación" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:20 -#: client/src/management-jobs/notifications/notification.route.js:21 -#: client/src/notifications/notifications.list.js:17 -#: client/src/setup-menu/setup-menu.partial.html:48 -msgid "Notifications" -msgstr "Notificación" - -#: client/src/notifications/notificationTemplates.form.js:302 -msgid "Notify Channel" -msgstr "Notificar canal" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:55 -#: client/src/job-submission/job-submission.partial.html:269 -#: client/src/partials/survey-maker-modal.html:27 -#: client/src/shared/form-generator.js:542 -#: client/src/shared/form-generator.js:773 -#: client/src/shared/generator-helpers.js:551 -msgid "OFF" -msgstr "OFF" - -#: client/lib/services/base-string.service.js:63 -#: client/src/jobs/factories/delete-job.factory.js:115 -msgid "OK" -msgstr "Aceptar" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:54 -#: client/src/job-submission/job-submission.partial.html:267 -#: client/src/partials/survey-maker-modal.html:26 -#: client/src/shared/form-generator.js:538 -#: client/src/shared/form-generator.js:771 -#: client/src/shared/generator-helpers.js:547 -msgid "ON" -msgstr "ON" - -#: client/lib/components/components.strings.js:10 -msgid "OPTIONS" -msgstr "OPCIONES" - -#: client/src/activity-stream/get-target-title.factory.js:29 -#: client/src/organizations/list/organizations-list.partial.html:6 -#: client/src/organizations/main.js:52 -msgid "ORGANIZATIONS" -msgstr "ORGANIZACIONES" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:116 -msgid "OVERWRITE" -msgstr "REEMPLAZAR" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:123 -msgid "OVERWRITE VARS" -msgstr "REEMPLAZAR VARS" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:38 -msgid "On Failure" -msgstr "En caso de error" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:33 -msgid "On Success" -msgstr "En caso de éxito" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:157 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:162 -msgid "Only Group By" -msgstr "Agrupar solo por" - -#: client/src/credentials/credentials.form.js:379 -msgid "" -"OpenStack domains define administrative boundaries. It is only needed for " -"Keystone v3 authentication URLs. Common scenarios include:" -msgstr "" -"Los dominios OpenStack definen los límites administrativos. Sólo es " -"necesario para las direcciones URLs en el uso de autentificación para " -"KeyStone v3. Los escenarios más habituales:" - -#: client/src/templates/job_templates/job-template.form.js:240 -#: client/src/templates/workflows.form.js:69 -msgid "" -"Optional labels that describe this job template, such as 'dev' or 'test'. " -"Labels can be used to group and filter job templates and completed jobs." -msgstr "" -"Etiquetas opcionales que describen esta plantilla de trabajo, como puede ser" -" 'dev' o 'test'. Las etiquetas pueden ser utilizadas para agrupar y filtrar " -"plantillas de trabajo y tareas completadas." - -#: client/src/notifications/notificationTemplates.form.js:382 -#: client/src/partials/logviewer.html:7 -#: client/src/templates/job_templates/job-template.form.js:259 -msgid "Options" -msgstr "Opciones" - -#: client/src/credentials/credentials.form.js:46 -#: client/src/credentials/credentials.form.js:53 -#: client/src/inventories-hosts/inventories/inventory.list.js:60 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:51 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:58 -#: client/src/inventory-scripts/inventory-scripts.form.js:40 -#: client/src/inventory-scripts/inventory-scripts.list.js:27 -#: client/src/notifications/notificationTemplates.form.js:44 -#: client/src/projects/projects.form.js:41 -#: client/src/projects/projects.form.js:47 client/src/teams/teams.form.js:37 -#: client/src/teams/teams.list.js:30 client/src/templates/workflows.form.js:45 -#: client/src/templates/workflows.form.js:51 client/src/users/users.form.js:40 -msgid "Organization" -msgstr "Organización" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:136 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:64 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:30 -#: client/src/setup-menu/setup-menu.partial.html:4 -#: client/src/users/users.form.js:132 -msgid "Organizations" -msgstr "Organizaciones" - -#: client/src/job-submission/job-submission.partial.html:19 -msgid "Other Prompts" -msgstr "Otros avisos" - -#: client/src/credentials/credentials.form.js:79 -msgid "Others (Cloud Providers)" -msgstr "Otros (Proveedores Cloud)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:283 -msgid "" -"Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variables de sobreescritura halladas en cloudforms.ini y utilizadas en el script de actualización del inventario. Para acceder a un ejemplo de configuración variable, \n" -" \n" -" vea cloudforms.ini en el repositorio github de Ansible. Ingrese variables de inventario con sintaxis JSON o YAML. Utilice el botón de selección para alternar entre los dos. Consulte la documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:218 -msgid "" -"Override variables found in ec2.ini and used by the inventory update script." -" For a detailed description of these variables" -msgstr "" -"Variables de sobreescritura halladas en ec2.ini y utilizadas en el script de" -" actualización del inventario. Para acceder a una descripción detallada de " -"estas variables" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:300 -msgid "" -"Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variables de sobreescritura halladas en foreman.ini y utilizadas en el script de actualización del inventario. Para acceder a un ejemplo de configuración de variable\n" -" \n" -" vea foreman.ini en el repositorio github de Ansible. Ingrese variables de inventario con sintaxis JSON o YAML. Utilice el botón de selección para alternar entre los dos. Consulte la documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:266 -msgid "" -"Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration\n" -" \n" -" view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variables de sobreescritura halladas en openstack.yml y utilizadas en el script de actualización del inventario. Para acceder a un ejemplo de configuración de variable,\n" -" Ingrese variables de inventario con la sintaxis JSON o YAML. Utilice el botón de opción para alternar entre los dos. Consulte la documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:242 -msgid "" -"Override variables found in vmware.ini and used by the inventory update " -"script. For a detailed description of these variables" -msgstr "" -"Variables de sobreescritura halladas en vmware.ini y utilizadas en el script" -" de actualización del inventario. Para acceder a un ejemplo de configuración" -" de estas variables" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:328 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:333 -msgid "Overwrite" -msgstr "Anular" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:340 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:345 -msgid "Overwrite Variables" -msgstr "Anular variables" - -#: client/src/credentials/credentials.list.js:40 -msgid "Owners" -msgstr "Propietarios" - -#: client/src/login/loginModal/loginModal.partial.html:68 -msgid "PASSWORD" -msgstr "CONTRASEÑA" - -#: client/features/credentials/legacy.credentials.js:122 -msgid "PERMISSIONS" -msgstr "PERMISOS" - -#: client/src/partials/job-template-details.html:2 -msgid "PLAYBOOK" -msgstr "PLAYBOOK" - -#: client/src/partials/survey-maker-modal.html:45 -msgid "PLEASE ADD A SURVEY PROMPT." -msgstr "AGREGAR UN AVISO DE ENCUESTA." - -#: client/src/instance-groups/instances/instances-list.partial.html:6 -#: client/src/instance-groups/list/instance-groups-list.partial.html:16 -#: client/src/organizations/list/organizations-list.partial.html:47 -#: client/src/shared/form-generator.js:1885 -#: client/src/shared/list-generator/list-generator.factory.js:248 -msgid "PLEASE ADD ITEMS TO THIS LIST" -msgstr "Por favor añada elementos a la lista" - -#: client/src/main-menu/main-menu.partial.html:67 -msgid "PORTAL MODE" -msgstr "MODO PORTAL" - -#: client/src/partials/survey-maker-modal.html:43 -msgid "PREVIEW" -msgstr "VISTA PREVIA" - -#: client/src/job-results/job-results.service.js:166 -msgid "PROCEED" -msgstr "PROCEDER" - -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:73 -msgid "PROJECT" -msgstr "PROYECTO" - -#: client/src/activity-stream/get-target-title.factory.js:8 -#: client/src/main-menu/main-menu.partial.html:19 -#: client/src/main-menu/main-menu.partial.html:95 -#: client/src/organizations/linkout/organizations-linkout.route.js:195 -#: client/src/organizations/list/organizations-list.controller.js:72 -#: client/src/projects/main.js:73 client/src/projects/projects.list.js:14 -#: client/src/projects/projects.list.js:15 -msgid "PROJECTS" -msgstr "PROYECTOS" - -#: client/src/shared/paginate/paginate.partial.html:33 -msgid "Page" -msgstr "Página" - -#: client/src/notifications/notificationTemplates.form.js:232 -msgid "Pagerduty subdomain" -msgstr "Subdominio Pagerduty" - -#: client/src/templates/job_templates/job-template.form.js:348 -msgid "" -"Pass extra command line variables to the playbook. Provide key/value pairs " -"using either YAML or JSON. Refer to the Ansible Tower documentation for " -"example syntax." -msgstr "" -"Traslade variables de línea de comando adicionales al manual. Proporcione " -"claves/pares de valores utilizando YAML o JSON. Consulte la documentación de" -" Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/templates/workflows.form.js:80 -msgid "" -"Pass extra command line variables to the playbook. This is the -e or " -"--extra-vars command line parameter for ansible-playbook. Provide key/value " -"pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for" -" example syntax." -msgstr "" -"Traslade variables de línea de comando adicionales al manual. Este es el " -"parámetro de línea de comando -e o --extra vars para el manual de Ansible. " -"Proporcione claves/pares de valores utilizando YAML o JSON. Consulte la " -"documentación de Ansible Tower para acceder a ejemplos de sintaxis." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:138 -msgid "" -"Pass extra command line variables. This is the %s or %s command line " -"parameter for %s. Provide key/value pairs using either YAML or JSON." -msgstr "" -"Transmitir variables adicionales en la línea de comandos a los playbook. " -"Este es el parámetro de línea de comandos %s o %s para %s. Introduzca pareja" -" de clave/valor utilizando la sintaxis YAML o JSON." - -#: client/src/credentials/credentials.form.js:226 -#: client/src/credentials/factories/become-method-change.factory.js:21 -#: client/src/credentials/factories/become-method-change.factory.js:40 -#: client/src/credentials/factories/become-method-change.factory.js:48 -#: client/src/credentials/factories/become-method-change.factory.js:68 -#: client/src/credentials/factories/become-method-change.factory.js:78 -#: client/src/credentials/factories/become-method-change.factory.js:88 -#: client/src/credentials/factories/kind-change.factory.js:105 -#: client/src/credentials/factories/kind-change.factory.js:125 -#: client/src/credentials/factories/kind-change.factory.js:135 -#: client/src/credentials/factories/kind-change.factory.js:145 -#: client/src/credentials/factories/kind-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:78 -#: client/src/credentials/factories/kind-change.factory.js:97 -#: client/src/job-submission/job-submission.partial.html:104 -#: client/src/notifications/shared/type-change.service.js:28 -#: client/src/users/users.form.js:68 -msgid "Password" -msgstr "Contraseña" - -#: client/src/credentials/factories/kind-change.factory.js:58 -msgid "Password (API Key)" -msgstr "Contraseña (clave API)" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:20 -msgid "Past 24 Hours" -msgstr "Últimas 24 horas" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:15 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:26 -msgid "Past Month" -msgstr "Mes pasado" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:23 -msgid "Past Week" -msgstr "Semana pasada" - -#: client/src/credentials/factories/become-method-change.factory.js:29 -#: client/src/credentials/factories/kind-change.factory.js:86 -msgid "" -"Paste the contents of the PEM file associated with the service account " -"email." -msgstr "" -"Pegue el contenido del fichero PEM asociado al correo de la cuenta de " -"servicio." - -#: client/src/credentials/factories/kind-change.factory.js:51 -msgid "Paste the contents of the SSH private key file." -msgstr "Pegue el contenido del fichero de la clave privada SSH." - -#: client/src/credentials/factories/kind-change.factory.js:26 -msgid "Paste the contents of the SSH private key file.%s or click to close%s" -msgstr "" -"Pegue el contenido del fichero de la clave privada SSH. %s o pulse cerrar%s" - -#: client/src/inventories-hosts/inventories/inventory.list.js:119 -msgid "Pending Delete" -msgstr "Eliminación pendiente" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:8 -msgid "Period" -msgstr "Periodo" - -#: client/src/projects/add/projects-add.controller.js:29 -#: client/src/users/add/users-add.controller.js:43 -msgid "Permission Error" -msgstr "Error de permiso" - -#: client/features/credentials/credentials.strings.js:14 -#: client/features/credentials/legacy.credentials.js:66 -#: client/src/credentials/credentials.form.js:439 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:122 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:123 -#: client/src/projects/projects.form.js:233 client/src/teams/teams.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:386 -#: client/src/templates/workflows.form.js:114 -#: client/src/users/users.form.js:187 -msgid "Permissions" -msgstr "Permisos" - -#: client/src/job-results/job-results.partial.html:249 -#: client/src/shared/form-generator.js:1069 -#: client/src/templates/job_templates/job-template.form.js:107 -#: client/src/templates/job_templates/job-template.form.js:115 -msgid "Playbook" -msgstr "Playbook" - -#: client/src/projects/projects.form.js:89 -msgid "Playbook Directory" -msgstr "Directorio de playbook" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:52 -msgid "Playbook Run" -msgstr "Ejecución de playbook" - -#: client/src/job-results/job-results.partial.html:488 -msgid "Plays" -msgstr "Reproduccciones" - -#: client/src/users/users.form.js:126 -msgid "Please add user to an Organization." -msgstr "Por favor añada un usuario a su organización." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:100 -msgid "Please assign roles to the selected resources" -msgstr "Por favor asigne funciones a los recursos seleccionados" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:60 -msgid "Please assign roles to the selected users/teams" -msgstr "Por favor asigne funciones a los usuarios/equipos seleccionados" - -#: client/src/license/license.partial.html:84 -msgid "" -"Please click the button below to visit Ansible's website to get a Tower " -"license key." -msgstr "" -"Por favor pulse sobre el siguiente botón para visitar la página web de " -"Ansible para obtener una clave de licencia Tower." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:27 -msgid "Please click the icon to edit the host filter." -msgstr "Haga clic en el icono para editar el filtro del host." - -#: client/src/shared/form-generator.js:861 -#: client/src/shared/form-generator.js:956 -msgid "" -"Please enter a URL that begins with ssh, http or https. The URL may not " -"contain the '@' character." -msgstr "" -"Por favor introduzca una URL que inicie por ssh, http o https. La URL no " -"puede contener el caracter '@'." - -#: client/src/shared/form-generator.js:1158 -msgid "Please enter a number greater than %d and less than %d." -msgstr "Por favor introduzca un número mayor que %d y menor que %d." - -#: client/src/shared/form-generator.js:1160 -msgid "Please enter a number greater than %d." -msgstr "Por favor introduzca un número mayor que %d." - -#: client/src/shared/form-generator.js:1152 -msgid "Please enter a number." -msgstr "Por favor introduzca un número." - -#: client/src/job-submission/job-submission.partial.html:112 -#: client/src/job-submission/job-submission.partial.html:126 -#: client/src/job-submission/job-submission.partial.html:140 -#: client/src/job-submission/job-submission.partial.html:154 -#: client/src/login/loginModal/loginModal.partial.html:78 -msgid "Please enter a password." -msgstr "Por favor introduzca una contraseña." - -#: client/src/login/loginModal/loginModal.partial.html:58 -msgid "Please enter a username." -msgstr "Por favor introduzca un nombre de usuario." - -#: client/src/shared/form-generator.js:851 -#: client/src/shared/form-generator.js:946 -msgid "Please enter a valid email address." -msgstr "Por favor introduzca una dirección de correo válida." - -#: client/lib/components/components.strings.js:15 -#: client/src/shared/form-generator.js:1016 -#: client/src/shared/form-generator.js:846 -#: client/src/shared/form-generator.js:941 -msgid "Please enter a value." -msgstr "Por favor introduzca un valor." - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/job-submission/job-submission.partial.html:311 -#: client/src/job-submission/job-submission.partial.html:317 -msgid "Please enter an answer between" -msgstr "Ingrese una respuesta entre" - -#: client/src/job-submission/job-submission.partial.html:316 -msgid "Please enter an answer that is a decimal number." -msgstr "Ingrese una respuesta que sea un número decimal." - -#: client/src/job-submission/job-submission.partial.html:310 -msgid "Please enter an answer that is a valid integer." -msgstr "Ingrese una respuesta que sea un valor entero válido." - -#: client/src/job-submission/job-submission.partial.html:288 -#: client/src/job-submission/job-submission.partial.html:293 -#: client/src/job-submission/job-submission.partial.html:304 -#: client/src/job-submission/job-submission.partial.html:309 -#: client/src/job-submission/job-submission.partial.html:315 -msgid "Please enter an answer." -msgstr "Ingrese una respuesta." - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:11 -#: client/src/templates/completed-jobs.list.js:11 -msgid "Please save and run a job to view." -msgstr "Guarde y ejecute una tarea para ver." - -#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:50 -msgid "Please save before adding a survey to this job template." -msgstr "Guarde antes de agregar una encuesta a esta plantilla de trabajo." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:46 -msgid "Please save before adding a survey to this workflow." -msgstr "Guarde antes de agregar una encuesta a este flujo de trabajo." - -#: client/src/notifications/notifications.list.js:15 -msgid "Please save before adding notifications." -msgstr "Guarde antes de agregar notificaciones." - -#: client/src/organizations/organizations.form.js:68 -#: client/src/teams/teams.form.js:69 -msgid "Please save before adding users." -msgstr "Guarde antes de agregar usuarios." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:118 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:119 -#: client/src/projects/projects.form.js:225 client/src/teams/teams.form.js:113 -#: client/src/templates/job_templates/job-template.form.js:379 -#: client/src/templates/workflows.form.js:107 -msgid "Please save before assigning permissions." -msgstr "Guarde antes de asignar permisos." - -#: client/src/users/users.form.js:124 client/src/users/users.form.js:183 -msgid "Please save before assigning to organizations." -msgstr "Guarde antes de asignar a organizaciones" - -#: client/src/users/users.form.js:152 -msgid "Please save before assigning to teams." -msgstr "Guarde antes de asignar a equipos." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:164 -msgid "Please save before creating groups." -msgstr "Guarde antes de crear grupos." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:173 -msgid "Please save before creating hosts." -msgstr "Guarde antes de crear hosts." - -#: client/src/inventories-hosts/hosts/host.form.js:112 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:86 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:111 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:112 -msgid "Please save before defining groups." -msgstr "Guarde antes de definir grupos." - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:94 -msgid "Please save before defining hosts." -msgstr "Guarde antes de definir hosts." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:182 -msgid "Please save before defining inventory sources." -msgstr "Guarde antes de definir fuentes de inventario." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:45 -msgid "Please save before defining the workflow graph." -msgstr "Guarde antes de definir un gráfico de flujo de trabajo." - -#: client/src/inventories-hosts/hosts/host.form.js:121 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:120 -msgid "Please save before viewing Insights." -msgstr "Guarde antes de ver Insights." - -#: client/src/inventories-hosts/hosts/host.form.js:105 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:104 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:105 -msgid "Please save before viewing facts." -msgstr "Guarde antes de ver eventos." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:164 -msgid "Please save before viewing hosts." -msgstr "Guarde antes de ver los hosts." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 -msgid "Please select Users / Teams from the lists below." -msgstr "Por favor seleccione Usuarios / Equipos de la siguiente lista." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 -msgid "Please select Users from the list below." -msgstr "Por favor seleccione Usuarios de la siguiente lista.." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:58 -msgid "Please select a Credential." -msgstr "Por favor seleccione un credencial." - -#: client/src/templates/job_templates/multi-credential/multi-credential.partial.html:46 -msgid "" -"Please select a machine (SSH) credential or check the \"Prompt on launch\" " -"option." -msgstr "" -"Seleccione una credencial de máquina (SSH) o marque la opción “Preguntar al " -"ejecutar”." - -#: client/src/shared/form-generator.js:1193 -msgid "Please select a number between" -msgstr "Por favor seleccione un número entre" - -#: client/src/shared/form-generator.js:1189 -msgid "Please select a number." -msgstr "Por favor seleccione un número." - -#: client/src/shared/form-generator.js:1081 -#: client/src/shared/form-generator.js:1149 -#: client/src/shared/form-generator.js:1270 -#: client/src/shared/form-generator.js:1378 -msgid "Please select a value." -msgstr "Por favor seleccione un valor." - -#: client/src/templates/job_templates/job-template.form.js:77 -msgid "Please select an Inventory or check the Prompt on launch option." -msgstr "" -"Por favor seleccione un inventario o seleccione la opción Preguntar al " -"ejecutar." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:79 -msgid "Please select an Inventory." -msgstr "Por favor seleccione un Inventario." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:26 -msgid "Please select an organization before editing the host filter." -msgstr "Seleccione una organización antes de editar el filtro del host." - -#: client/src/shared/form-generator.js:1186 -msgid "Please select at least one value." -msgstr "Por favor seleccione al menos un valor." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:30 -msgid "Please select resources from the lists below." -msgstr "Por favor seleccione recursos de la lista siguiente." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Populate the hosts for this inventory by using a search filter." -msgstr "" -"Complete los hosts de este inventario por medio del filtro de búsqueda." - -#: client/src/notifications/shared/type-change.service.js:27 -msgid "Port" -msgstr "Puerto" - -#: client/src/credentials/credentials.form.js:257 -#: client/src/credentials/factories/kind-change.factory.js:21 -#: client/src/credentials/factories/kind-change.factory.js:45 -msgid "Private Key" -msgstr "Clave privada" - -#: client/src/credentials/credentials.form.js:264 -#: client/src/job-submission/job-submission.partial.html:118 -msgid "Private Key Passphrase" -msgstr "Frase de contraseña para la clave privada" - -#: client/src/credentials/credentials.form.js:279 -#: client/src/credentials/credentials.form.js:283 -msgid "Privilege Escalation" -msgstr "Elevación de privilegios" - -#: client/src/credentials/credentials.form.js:305 -#: client/src/job-submission/job-submission.partial.html:132 -msgid "Privilege Escalation Password" -msgstr "Contraseña para la elevación de privilegios" - -#: client/src/credentials/credentials.form.js:295 -msgid "Privilege Escalation Username" -msgstr "Usuario para la elevación de privilegios" - -#: client/src/credentials/factories/become-method-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:87 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:93 -#: client/src/job-results/job-results.partial.html:216 -#: client/src/templates/job_templates/job-template.form.js:100 -#: client/src/templates/job_templates/job-template.form.js:91 -msgid "Project" -msgstr "Proyecto" - -#: client/src/credentials/factories/become-method-change.factory.js:53 -#: client/src/credentials/factories/kind-change.factory.js:110 -msgid "Project (Tenant Name)" -msgstr "Proyecto (Nombre del inquilino [Tenant])" - -#: client/src/projects/projects.form.js:75 -#: client/src/projects/projects.form.js:83 -msgid "Project Base Path" -msgstr "Ruta base del proyecto" - -#: client/src/credentials/credentials.form.js:365 -msgid "Project Name" -msgstr "Nombre del proyecto" - -#: client/src/projects/projects.form.js:100 -msgid "Project Path" -msgstr "Ruta del proyecto" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:66 -msgid "Project Sync Failures" -msgstr "Errores de sincronización del proyecto" - -#: client/src/projects/list/projects-list.controller.js:170 -msgid "Project lookup failed. GET returned:" -msgstr "La búsqueda del proyecto ha fallado. GET ha devuelto:" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:115 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:47 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:31 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:61 -#: client/src/organizations/linkout/organizations-linkout.route.js:206 -msgid "Projects" -msgstr "Proyectos" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:18 -msgid "Promote group" -msgid_plural "Promote groups" -msgstr[0] "Promover grupo" -msgstr[1] "Promover grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:43 -msgid "Promote groups" -msgstr "Promover grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:32 -msgid "Promote groups and hosts" -msgstr "Promover grupos y hosts" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:20 -msgid "Promote host" -msgid_plural "Promote hosts" -msgstr[0] "Promover host" -msgstr[1] "Promover hosts" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:54 -msgid "Promote hosts" -msgstr "Promover hosts" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:10 -msgid "Promote {{ group }} and {{ host }}" -msgstr "Promover {{ group }} y {{ host }}" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:27 -msgid "Prompt" -msgstr "Aviso" - -#: client/lib/components/components.strings.js:30 -#: client/src/templates/job_templates/job-template.form.js:139 -#: client/src/templates/job_templates/job-template.form.js:169 -#: client/src/templates/job_templates/job-template.form.js:186 -#: client/src/templates/job_templates/job-template.form.js:212 -#: client/src/templates/job_templates/job-template.form.js:229 -#: client/src/templates/job_templates/job-template.form.js:254 -#: client/src/templates/job_templates/job-template.form.js:354 -#: client/src/templates/job_templates/job-template.form.js:60 -#: client/src/templates/job_templates/job-template.form.js:86 -msgid "Prompt on launch" -msgstr "Preguntar al ejecutar" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:132 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:147 -msgid "Provide a comma separated list of tags." -msgstr "Introduzca una lista de etiquetas separadas por coma." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:184 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:266 -msgid "Provide a comma-separated list of filter expressions." -msgstr "Proporcione una lista de expresiones de filtrado separadas por coma." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:200 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:284 -msgid "" -"Provide a comma-separated list of filter expressions. Hosts are imported " -"when all of the filters match. Refer to Ansible Tower documentation for more" -" detail." -msgstr "" -"Proporcione una lista de expresiones de filtrado separadas por coma. Los " -"hosts se importan cuando coinciden todos los filtros. Consulte la " -"documentación de Ansible Tower para obtener más información detallada." - -#: client/src/inventories-hosts/hosts/host.form.js:50 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:49 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:49 -msgid "Provide a host name, ip address, or ip address:port. Examples include:" -msgstr "" -"Provea un nombre de host, dirección ip, ó dirección:puerto. Por ejemplo:" - -#: client/src/templates/job_templates/job-template.form.js:163 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns are allowed. Refer to" -" Ansible documentation for more information and examples on patterns." -msgstr "" -"Proporcione un patrón de host para limitar aun más la lista de hosts que se " -"encontrarán bajo la administración del manual o se verán afectados por él. " -"Se permiten distintos patrones. Consulte la documentación de Ansible para " -"obtener más información y ejemplos relacionados con los patrones." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:116 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns can be separated by " -"%s %s or %s" -msgstr "" -"Introduzca un patrón de servidores para restringir aún más la lista de " -"servidores que serán administrados o afectados por el playbook. Varios " -"patrones pueden ser separados por %s %s o %s" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:196 -msgid "Provide environment variables to pass to the custom inventory script." -msgstr "" -"Proporcione variables del entorno para trasladar al script del inventario " -"personalizado." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:203 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:287 -msgid "" -"Provide the named URL encoded name or id of the remote Tower inventory to be" -" imported." -msgstr "" -"Indique la URL, el nombre cifrado o id del inventario remoto de Tower para " -"importarlos." - -#: client/src/templates/job_templates/job-template.form.js:311 -#: client/src/templates/job_templates/job-template.form.js:319 -msgid "Provisioning Callback URL" -msgstr "Dirección URL para las llamadas callback" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Purple" -msgstr "Púrpura" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:14 -msgid "Queued. Click for details" -msgstr "En cola. Pulse para más información" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:112 -msgid "RADIUS" -msgstr "RADIUS" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:4 -msgid "RECENT JOB RUNS" -msgstr "TRABAJOS EJECUTADOS RECIENTEMENTE" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:40 -msgid "RECENTLY RUN JOBS" -msgstr "TRABAJOS EJECUTADOS RECIENTEMENTE" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:50 -msgid "RECENTLY USED JOB TEMPLATES" -msgstr "PLANTILLAS DE TRABAJO USADOS RECIENTEMENTE" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:4 -msgid "RECENTLY USED TEMPLATES" -msgstr "PLANTILLAS USADAS RECIENTEMENTE" - -#: client/src/activity-stream/streams.list.js:54 -#: client/src/inventories-hosts/hosts/host.list.js:102 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:46 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:113 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:54 -#: client/src/jobs/jobs.partial.html:15 -#: client/src/portal-mode/portal-mode-jobs.partial.html:20 -#: client/src/projects/projects.list.js:71 -#: client/src/scheduler/schedules.list.js:61 -msgid "REFRESH" -msgstr "ACTUALIZAR" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:109 -msgid "REGIONS" -msgstr "REGIONES" - -#: client/src/shared/smart-search/smart-search.partial.html:48 -msgid "RELATED FIELDS:" -msgstr "CAMPOS RELACIONADOS:" - -#: client/src/shared/directives.js:78 -msgid "REMOVE" -msgstr "ELIMINAR" - -#: client/lib/components/components.strings.js:7 -msgid "REPLACE" -msgstr "REEMPLAZAR" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:7 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:7 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:7 -msgid "RESULTS" -msgstr "RESULTADOS" - -#: client/lib/components/components.strings.js:8 -#: client/src/job-submission/job-submission.partial.html:44 -#: client/src/job-submission/job-submission.partial.html:87 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:52 -msgid "REVERT" -msgstr "REVERTIR" - -#: client/src/credentials/factories/become-method-change.factory.js:25 -#: client/src/credentials/factories/kind-change.factory.js:82 -msgid "RSA Private Key" -msgstr "Clave privada RSA" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.route.js:28 -msgid "RUN COMMAND" -msgstr "EJECUTAR COMANDO" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:101 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:56 -msgid "RUN COMMANDS" -msgstr "EJECUTAR COMANDOS" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Random" -msgstr "Aleatorio" - -#: client/src/job-results/job-results.partial.html:411 -msgid "Read only view of extra variables added to the job template." -msgstr "" -"Vista de solo lectura de las variables adicionales añadidas a la plantilla " -"de trabajo." - -#: client/src/workflow-results/workflow-results.partial.html:155 -msgid "Read only view of extra variables added to the workflow." -msgstr "" -"Vista de sólo lectura de las variables adicionales añadidas al flujo de " -"trabajo." - -#: client/src/notifications/notificationTemplates.list.js:26 -msgid "Recent Notifications" -msgstr "Notificaciones recientes" - -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:98 -msgid "Recipient List" -msgstr "Lista de destinatarios" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Red" -msgstr "Rojo" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "" -"Refer to the Ansible Tower documentation for further syntax and examples." -msgstr "" -"Consulte la documentación de Ansible Tower para obtener más ejemplos sobre " -"sintaxis." - -#: client/src/activity-stream/streams.list.js:51 -#: client/src/bread-crumb/bread-crumb.partial.html:6 -#: client/src/inventories-hosts/hosts/host.list.js:98 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:42 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:109 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:50 -#: client/src/projects/projects.list.js:67 -#: client/src/scheduler/schedules.list.js:57 -msgid "Refresh the page" -msgstr "Actualizar la página" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:177 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "Region:" -msgstr "Región:" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:131 -msgid "Regions" -msgstr "Regiones" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:65 -msgid "Related Groups" -msgstr "Grupos relacionados" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:77 -#: client/src/job-results/job-results.partial.html:29 -#: client/src/jobs/all-jobs.list.js:99 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:11 -#: client/src/templates/completed-jobs.list.js:78 -#: client/src/workflow-results/workflow-results.partial.html:29 -msgid "Relaunch using the same parameters" -msgstr "Relanzar utilizando los mismos parámetros" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:194 -msgid "Remediate Inventory" -msgstr "Reparar inventario" - -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:96 -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:97 -#: client/src/teams/teams.form.js:142 client/src/users/users.form.js:222 -msgid "Remove" -msgstr "Eliminar" - -#: client/src/projects/projects.form.js:158 -msgid "Remove any local modifications prior to performing an update." -msgstr "" -"Eliminar cualquier modificación local antes de realizar una actualización." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:149 -msgid "Repeat frequency" -msgstr "Frecuencia de repetición" - -#: client/src/license/license.partial.html:89 -msgid "Request License" -msgstr "Solicitar una licencia" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:291 -msgid "Required" -msgstr "Obligatorio" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:153 -msgid "Reset" -msgstr "Restablecer" - -#: client/src/job-results/job-results.partial.html:123 -msgid "Results Traceback" -msgstr "Resultados Traceback" - -#: client/src/shared/form-generator.js:690 -msgid "Revert" -msgstr "Revertir" - -#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:59 -#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:95 -#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:34 -#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:87 -#: client/src/configuration/auth-form/sub-forms/auth-tacacs.form.js:47 -#: client/src/configuration/jobs-form/configuration-jobs.form.js:73 -#: client/src/configuration/system-form/sub-forms/system-activity-stream.form.js:26 -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:74 -#: client/src/configuration/system-form/sub-forms/system-misc.form.js:50 -#: client/src/configuration/ui-form/configuration-ui.form.js:36 -msgid "Revert all to default" -msgstr "Revertir todo a valores por defecto" - -#: client/src/job-results/job-results.partial.html:239 -#: client/src/projects/projects.list.js:50 -msgid "Revision" -msgstr "Revisión" - -#: client/src/projects/add/projects-add.controller.js:146 -#: client/src/projects/edit/projects-edit.controller.js:281 -msgid "Revision #" -msgstr "Revisión n°" - -#: client/features/credentials/legacy.credentials.js:88 -#: client/src/credentials/credentials.form.js:461 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:148 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:149 -#: client/src/organizations/organizations.form.js:97 -#: client/src/projects/projects.form.js:255 client/src/teams/teams.form.js:135 -#: client/src/teams/teams.form.js:98 -#: client/src/templates/workflows.form.js:138 -#: client/src/users/users.form.js:205 -msgid "Role" -msgstr "Función" - -#: client/src/instance-groups/instance-group.partial.html:14 -#: client/src/instance-groups/instance-groups.list.js:26 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:14 -#: client/src/instance-groups/instances/instances-list.partial.html:18 -#: client/src/instance-groups/instances/instances.list.js:24 -#: client/src/instance-groups/list/instance-groups-list.partial.html:29 -msgid "Running Jobs" -msgstr "Tareas en ejecución" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:18 -msgid "Running! Click for details" -msgstr "¡En ejecución!. Pulse para más detalles" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:113 -msgid "SAML" -msgstr "SAML" - -#: client/lib/services/base-string.service.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:17 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:17 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:17 -#: client/src/partials/survey-maker-modal.html:87 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:18 -msgid "SAVE" -msgstr "GUARDAR" - -#: client/src/scheduler/main.js:331 -msgid "SCHEDULED" -msgstr "PROGRAMADO" - -#: client/src/scheduler/scheduled-jobs.list.js:13 -msgid "SCHEDULED JOBS" -msgstr "TRABAJOS PROGRAMADOS" - -#: client/src/activity-stream/get-target-title.factory.js:38 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:49 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:8 -#: client/src/management-jobs/scheduler/main.js:26 -#: client/src/management-jobs/scheduler/main.js:32 -#: client/src/scheduler/main.js:145 client/src/scheduler/main.js:183 -#: client/src/scheduler/main.js:235 client/src/scheduler/main.js:273 -#: client/src/scheduler/main.js:52 client/src/scheduler/main.js:90 -msgid "SCHEDULES" -msgstr "PROGRAMACIONES" - -#: client/src/projects/add/projects-add.controller.js:118 -#: client/src/projects/edit/projects-edit.controller.js:254 -msgid "SCM Branch" -msgstr "Rama SCM" - -#: client/src/projects/add/projects-add.controller.js:137 -#: client/src/projects/edit/projects-edit.controller.js:272 -msgid "SCM Branch/Tag/Commit" -msgstr "Consigna/Etiqueta/Rama SCM" - -#: client/src/projects/add/projects-add.controller.js:158 -#: client/src/projects/edit/projects-edit.controller.js:293 -msgid "SCM Branch/Tag/Revision" -msgstr "Revisión/Etiqueta/Rama SCM" - -#: client/src/projects/projects.form.js:159 -msgid "SCM Clean" -msgstr "Limpiar SCM" - -#: client/src/projects/projects.form.js:170 -msgid "SCM Delete" -msgstr "Eliminar SCM" - -#: client/src/credentials/factories/become-method-change.factory.js:20 -#: client/src/credentials/factories/kind-change.factory.js:77 -msgid "SCM Private Key" -msgstr "Clave privada SCM" - -#: client/src/projects/projects.form.js:55 -msgid "SCM Type" -msgstr "Tipo SCM" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:49 -#: client/src/projects/projects.form.js:180 -msgid "SCM Update" -msgstr "Actualización SCM" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "SCM Update Cancel" -msgstr "Cancelar actualización SCM" - -#: client/src/projects/projects.form.js:150 -msgid "SCM Update Options" -msgstr "Opciones de actualización SCM" - -#: client/src/projects/edit/projects-edit.controller.js:137 -#: client/src/projects/list/projects-list.controller.js:84 -msgid "SCM update currently running" -msgstr "Actualización SCM actualmente en ejecución" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js:35 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:70 -msgid "SELECT" -msgstr "SELECCIONAR" - -#: client/features/credentials/credentials.strings.js:20 -msgid "SELECT A CREDENTIAL TYPE" -msgstr "SELECCIONAR UN TIPO DE CREDENCIAL" - -#: client/features/credentials/credentials.strings.js:19 -msgid "SELECT AN ORGANIZATION" -msgstr "SELECCIONAR UNA ORGANIZACIÓN" - -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:6 -msgid "SELECT GROUPS" -msgstr "SELECCIONAR GRUPOS" - -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:6 -msgid "SELECT HOSTS" -msgstr "SELECCIONAR HOSTS" - -#: client/src/job-submission/job-submission.partial.html:29 -#: client/src/job-submission/job-submission.partial.html:56 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:20 -msgid "SELECTED:" -msgstr "SELECCIONADO:" - -#: client/src/main-menu/main-menu.partial.html:59 -#: client/src/setup-menu/setup.route.js:9 -msgid "SETTINGS" -msgstr "AJUSTES" - -#: client/lib/components/components.strings.js:11 -msgid "SHOW" -msgstr "MOSTRAR" - -#: client/src/login/loginModal/loginModal.partial.html:97 -msgid "SIGN IN" -msgstr "INICIAR SESIÓN" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html:2 -msgid "SIGN IN WITH" -msgstr "INICIAR SESIÓN CON" - -#: client/src/inventories-hosts/hosts/host.list.js:110 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:32 -msgid "SMART INVENTORY" -msgstr "INVENTARIO INTELIGENTE" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:102 -msgid "SOURCE" -msgstr "FUENTE" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js:26 -msgid "SOURCES" -msgstr "FUENTES" - -#: client/src/credentials/factories/become-method-change.factory.js:89 -#: client/src/credentials/factories/kind-change.factory.js:146 -msgid "SSH Key" -msgstr "Clave SSH" - -#: client/src/credentials/credentials.form.js:255 -msgid "SSH key description" -msgstr "Descripción de la clave SSH" - -#: client/src/notifications/notificationTemplates.form.js:375 -msgid "SSL Connection" -msgstr "Conexión SSL" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:128 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:135 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:96 -msgid "STANDARD OUT" -msgstr "SALIDA ESTÁNDAR" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:32 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:65 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:45 -msgid "STARTED" -msgstr "INICIADO" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:24 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:37 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:37 -msgid "STATUS" -msgstr "ESTADO" - -#: client/src/credentials/credentials.form.js:119 -#: client/src/credentials/credentials.form.js:127 -msgid "STS Token" -msgstr "Token STS" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:61 -msgid "SUCCESSFUL" -msgstr "CORRECTO" - -#: client/src/partials/survey-maker-modal.html:24 -msgid "SURVEY" -msgstr "ENCUESTA" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:62 -msgid "SYNC ALL" -msgstr "SINCRONIZAR TODO" - -#: client/src/system-tracking/system-tracking.route.js:18 -msgid "SYSTEM TRACKING" -msgstr "SISTEMA DE RASTREO" - -#: client/src/credentials/factories/become-method-change.factory.js:70 -#: client/src/credentials/factories/kind-change.factory.js:127 -msgid "Satellite 6 URL" -msgstr "URL Satellite 6" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:110 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:193 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:157 -#: client/src/shared/form-generator.js:1691 -msgid "Save" -msgstr "Guardar" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:86 -#: client/src/configuration/configuration.controller.js:213 -#: client/src/configuration/configuration.controller.js:272 -#: client/src/configuration/system-form/configuration-system.controller.js:68 -msgid "Save changes" -msgstr "Guardar los cambios" - -#: client/src/license/license.partial.html:127 -msgid "Save successful!" -msgstr "Guardado correctamente" - -#: client/src/templates/templates.list.js:88 -msgid "Schedule" -msgstr "Planificar" - -#: client/src/management-jobs/card/card.partial.html:28 -msgid "Schedule Management Job" -msgstr "Planificar trabajo de gestión" - -#: client/src/projects/list/projects-list.controller.js:75 -msgid "Schedule future SCM updates" -msgstr "Planificar futuras actualizaciones SCM" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:7 -msgid "Schedule future inventory syncs" -msgstr "Programar futuras sincronizaciones de inventario" - -#: client/src/templates/templates.list.js:91 -msgid "Schedule future job template runs" -msgstr "Planificar futuras ejecuciones de plantilla de trabajo." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:33 -#: client/src/jobs/jobs.partial.html:10 -msgid "Schedules" -msgstr "Programaciones" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:94 -msgid "Search" -msgstr "Buscar" - -#: client/src/credentials/credentials.form.js:104 -msgid "Secret Key" -msgstr "Clave secreta" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:259 -msgid "Security Group:" -msgstr "Grupo de seguridad:" - -#: client/src/credentials/credentials.form.js:124 -msgid "" -"Security Token Service (STS) is a web service that enables you to request " -"temporary, limited-privilege credentials for AWS Identity and Access " -"Management (IAM) users." -msgstr "" -"El Security Token Service (STS) es un servicio web que habilita su solicitud" -" temporalmente y con credenciales con privilegio limitado para usuarios de " -"AWS Identity y Access Management (IAM)." - -#: client/src/shared/form-generator.js:1695 -msgid "Select" -msgstr "Seleccionar" - -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:5 -msgid "Select Instance Groups" -msgstr "Seleccionar grupos de instancias" - -#: client/src/job-submission/job-submission.directive.js:64 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:46 -msgid "Select a credential" -msgstr "Seleccionar una credencial" - -#: client/src/access/add-rbac-user-team/rbac-user-team.controller.js:68 -msgid "Select a role" -msgstr "Seleccionar un rol" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or a selection of multiple groups." -msgstr "" -"Seleccione una fuente de inventario al hacer clic en la casilla de " -"verificación a su lado. La fuente de inventario puede ser un único grupo o " -"una selección de varios grupos." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:98 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or host, a selection of multiple " -"hosts, or a selection of multiple groups." -msgstr "" -"Seleccione una fuente de inventario al hacer clic en la casilla de " -"verificación a su lado. La fuente de inventario puede ser un único grupo o " -"host, una selección de varios hosts o una selección de varios grupos." - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:111 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single host or a selection of multiple hosts." -msgstr "" -"Seleccione una fuente de inventario al hacer clic en la casilla de " -"verificación a su lado. La fuente de inventario puede ser un único host o " -"una selección de varios hosts." - -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:109 -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:134 -#: client/src/configuration/ui-form/configuration-ui.controller.js:95 -msgid "Select commands" -msgstr "Seleccionar comandos" - -#: client/src/templates/job_templates/job-template.form.js:133 -msgid "" -"Select credentials that allow Tower to access the nodes this job will be ran" -" against. You can only select one credential of each type. For machine " -"credentials (SSH), checking \"Prompt on launch\" without selecting " -"credentials will require you to select a machine credential at run time. If " -"you select credentials and check \"Prompt on launch\", the selected " -"credential(s) become the defaults that can be updated at run time." -msgstr "" -"Seleccione las credenciales que le permiten a Tower acceder a los nodos en " -"función de los cuales se ejecutará este trabajo. Solo puede seleccionar una " -"credencial de cada tipo. Para las credenciales de equipo (SSH), si marca " -"\"Preguntar al ejecutar\" sin seleccionar las credenciales, se le pedirá que" -" seleccione una credencial del equipo en el momento de la ejecución. Si " -"selecciona credenciales y marca \"Preguntar al ejecutar\", las credenciales " -"seleccionadas se convierten en las predeterminadas que pueden actualizarse " -"al momento de la ejecución." - -#: client/src/projects/projects.form.js:98 -msgid "" -"Select from the list of directories found in the Project Base Path. Together" -" the base path and the playbook directory provide the full path used to " -"locate playbooks." -msgstr "" -"Seleccione desde la lista de directorios encontrados en el directorio base " -"del proyecto. Junto al directorio base y el directorio del playbook se " -"construirá la ruta completa utilizada para encontrar playbooks." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:263 -#: client/src/configuration/auth-form/configuration-auth.controller.js:282 -msgid "Select group types" -msgstr "Seleccionar un tipo de grupo" - -#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:24 -msgid "Select roles" -msgstr "Seleccionar roles" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:74 -msgid "Select the Instance Groups for this Inventory to run on." -msgstr "" -"Seleccione los grupos de instancias en los que se ejecutará este inventario." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:80 -msgid "" -"Select the Instance Groups for this Inventory to run on. Refer to the " -"Ansible Tower documentation for more detail." -msgstr "" -"Seleccione los Grupos de instancias respecto de los cuales se ejecutará este" -" Inventario. Consulte la documentación de Ansible Tower para obtener más " -"información." - -#: client/src/templates/job_templates/job-template.form.js:193 -msgid "Select the Instance Groups for this Job Template to run on." -msgstr "" -"Seleccione los grupos de instancias en los que se ejecutará esta plantilla " -"de trabajo." - -#: client/src/organizations/organizations.form.js:40 -msgid "Select the Instance Groups for this Organization to run on." -msgstr "" -"Seleccione los grupos de instancias en los que se ejecutará esta " -"organización." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:60 -msgid "" -"Select the credential you want the job to use when accessing the remote " -"hosts. Choose the credential containing the username and SSH key or " -"password that Ansible will need to log into the remote hosts." -msgstr "" -"Seleccione la credential que desea que el trabajo utilice al conectarse a " -"servidores remotos. Escoja una credencial que contenga el usuario y la clave" -" SSH o la contraseña que Ansible necesitará para autentificarse dentro de " -"los sistema remotos" - -#: client/src/templates/job_templates/job-template.form.js:79 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:81 -msgid "Select the inventory containing the hosts you want this job to manage." -msgstr "" -"Seleccione el inventario que contenga los servidores que desea que este " -"trabajo administre." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:122 -msgid "" -"Select the inventory file to be synced by this source. You can select from " -"the dropdown or enter a file within the input." -msgstr "" -"Seleccione el archivo del inventario que sincronizará esta fuente. Puede " -"seleccionar del menú desplegable o ingresar un archivo en la entrada." - -#: client/src/templates/job_templates/job-template.form.js:114 -msgid "Select the playbook to be executed by this job." -msgstr "Seleccionar el playbook a ser ejecutado por este trabajo." - -#: client/src/templates/job_templates/job-template.form.js:99 -msgid "" -"Select the project containing the playbook you want this job to execute." -msgstr "" -"Seleccionar el proyecto que contiene el playbook que desea ejecutar este " -"trabajo." - -#: client/src/configuration/system-form/configuration-system.controller.js:197 -msgid "Select types" -msgstr "Seleccionar los tipos" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:170 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:251 -msgid "Select which groups to create automatically." -msgstr "Seleccione los grupos que se crearán de manera automática." - -#: client/src/notifications/notificationTemplates.form.js:110 -msgid "Sender Email" -msgstr "Dirección de correo del remitente" - -#: client/src/credentials/factories/become-method-change.factory.js:24 -#: client/src/credentials/factories/kind-change.factory.js:81 -msgid "Service Account Email Address" -msgstr "Dirección de correo de cuenta de servicio" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:101 -msgid "" -"Setting the type to %s will execute the playbook and store any scanned " -"facts for use with 's System Tracking feature." -msgstr "" -"La configuración del tipo en %s ejecutará el playbook y almacenará cualquier" -" evento analizado para el uso de la función del sistema de rastreo." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:99 -msgid "" -"Setting the type to %s will not execute the playbook. Instead, %s will check" -" playbook syntax, test environment setup and report problems." -msgstr "" -"La configuración del tipo a %s no ejecutará el playbook. En cambio, %s " -"comprobará la sintaxis del playbook, la configuración del entorno de pruebas" -" e informará de problemas." - -#: client/src/main-menu/main-menu.partial.html:147 -msgid "Settings" -msgstr "Ajustes" - -#: client/src/job-submission/job-submission.partial.html:108 -#: client/src/job-submission/job-submission.partial.html:122 -#: client/src/job-submission/job-submission.partial.html:136 -#: client/src/job-submission/job-submission.partial.html:150 -#: client/src/job-submission/job-submission.partial.html:299 -#: client/src/shared/form-generator.js:876 -msgid "Show" -msgstr "Mostrar" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:114 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:245 -#: client/src/templates/job_templates/job-template.form.js:248 -msgid "Show Changes" -msgstr "Mostrar cambios" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:33 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:44 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:55 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:76 -msgid "Sign in with %s" -msgstr "Iniciar sesión con %s" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:63 -msgid "Sign in with %s Organizations" -msgstr "Iniciar sesión con las organizaciones %s" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:61 -msgid "Sign in with %s Teams" -msgstr "Iniciar sesión con los equipos %s" - -#: client/src/job-results/job-results.partial.html:395 -#: client/src/job-submission/job-submission.partial.html:245 -#: client/src/templates/job_templates/job-template.form.js:217 -#: client/src/templates/job_templates/job-template.form.js:224 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:142 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:150 -msgid "Skip Tags" -msgstr "Omitir etiquetas" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:148 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task." -msgstr "" -"Omitir etiquetas es útil cuando se posee de un playbook largo y desea omitir" -" algunas partes de una jugada o tarea." - -#: client/src/templates/job_templates/job-template.form.js:223 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task. Use commas to separate multiple tags. " -"Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"La omisión de etiquetas resulta útil cuando tiene un manual de gran tamaño y" -" desea omitir partes específicas de la tarea o la reproducción. Utilice " -"comas para separar las distintas etiquetas. Consulte la documentación de " -"Ansible Tower para obtener información detallada sobre el uso de etiquetas." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:66 -msgid "Smart Host Filter" -msgstr "Filtro de host inteligente" - -#: client/src/inventories-hosts/inventories/inventory.list.js:85 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/shared/form-generator.js:1456 -msgid "Smart Inventory" -msgstr "Inventario inteligente" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:44 -msgid "Solvable With Playbook" -msgstr "Se puede solucionar con playbook" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:57 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:64 -msgid "Source" -msgstr "Fuente" - -#: client/src/credentials/credentials.form.js:75 -msgid "Source Control" -msgstr "Fuente de control" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:47 -#: client/src/projects/projects.form.js:25 -msgid "Source Details" -msgstr "Detalles de la fuente" - -#: client/src/notifications/notificationTemplates.form.js:192 -#: client/src/notifications/notificationTemplates.form.js:193 -msgid "Source Phone Number" -msgstr "Número de teléfono de la fuente" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:136 -msgid "Source Regions" -msgstr "Regiones de fuente" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:209 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:216 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:233 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:240 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:257 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:264 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:274 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:281 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:291 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:298 -msgid "Source Variables" -msgstr "Variables de fuente" - -#: client/src/partials/logviewer.html:9 -msgid "Source Vars" -msgstr "Vars de la fuente" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:34 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:184 -msgid "Sources" -msgstr "Fuentes" - -#: client/src/notifications/notificationTemplates.form.js:330 -msgid "" -"Specify HTTP Headers in JSON format. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Especifique los encabezados HTTP en formato JSON. Consulte la documentación " -"de Ansible Tower para obtener ejemplos de sintaxis." - -#: client/src/credentials/credentials.form.js:285 -msgid "" -"Specify a method for %s operations. This is equivalent to specifying the %s " -"parameter, where %s could be %s" -msgstr "" -"Especificar un método para las operaciones %s. Esto es equivalente a " -"especificar el parámetro %s, cuando %s puede ser %s." - -#: client/src/notifications/notificationTemplates.form.js:292 -msgid "" -"Specify a notification color. Acceptable colors are: yellow, green, red " -"purple, gray or random." -msgstr "" -"Especifique un color para la notificación. Se aceptan los siguientes " -"colores: amarillo, verde, rojo, púrpura, gris o al azar." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:199 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:283 -msgid "" -"Specify which groups to create automatically. Group names will be created " -"similar to the options selected. If blank, all groups above are created. " -"Refer to Ansible Tower documentation for more detail." -msgstr "" -"Especifique los grupos que se crearán de manera automática. Los nombres de " -"grupos creados serán similares a los de las opciones seleccionadas. Si la " -"opción se deja en blanco, se crearán todos los grupos de arriba. Consulte la" -" documentación de Ansible Tower para obtener información detallada." - -#: client/src/setup-menu/setup-menu.partial.html:17 -msgid "" -"Split up your organization to associate content and control permissions for " -"groups." -msgstr "" -"Dividir su organización para asociar contenido y controlar permisos para los" -" grupos." - -#: client/src/partials/logviewer.html:5 -msgid "Standard Out" -msgstr "Salida estándar" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:41 -msgid "Start Date" -msgstr "Fecha de inicio" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:56 -msgid "Start Time" -msgstr "Hora de inicio" - -#: client/src/portal-mode/portal-job-templates.list.js:39 -#: client/src/templates/templates.list.js:83 -msgid "Start a job using this template" -msgstr "Iniciar un trabajo usando esta plantilla" - -#: client/src/projects/edit/projects-edit.controller.js:134 -#: client/src/projects/list/projects-list.controller.js:74 -msgid "Start an SCM update" -msgstr "Iniciar una actualización de SCM" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:6 -msgid "Start sync process" -msgstr "Iniciar proceso de sincronización" - -#: client/src/job-results/job-results.partial.html:100 -msgid "Started" -msgstr "Iniciado" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:53 -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:55 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:43 -#: client/src/job-results/job-results.partial.html:67 -#: client/src/job-results/parse-stdout.service.js:68 -#: client/src/notifications/notification-templates-list/list.controller.js:71 -#: client/src/partials/logviewer.html:4 -msgid "Status" -msgstr "Estado" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:3 -msgid "Sub Category" -msgstr "Subcategoría" - -#: client/src/license/license.partial.html:126 -msgid "Submit" -msgstr "Enviar" - -#: client/src/jobs/factories/delete-job.factory.js:109 -msgid "Submit the request to cancel?" -msgstr "¿Enviar la solicitud de cancelación?" - -#: client/src/license/license.partial.html:27 -msgid "Subscription" -msgstr "Subscripción" - -#: client/src/credentials/credentials.form.js:151 -#: client/src/credentials/credentials.form.js:162 -msgid "Subscription ID" -msgstr "ID de suscripción" - -#: client/src/credentials/credentials.form.js:161 -msgid "Subscription ID is an Azure construct, which is mapped to a username." -msgstr "" -"El ID de subscripción es un elemento Azure, el cual está asociado al " -"usuario." - -#: client/src/notifications/notifications.list.js:38 -msgid "Success" -msgstr "Correcto" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:21 -msgid "Success! Click for details" -msgstr "¡Correcto!. Pulse para más información." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:77 -msgid "Successful" -msgstr "Correctos" - -#: client/src/job-submission/job-submission.partial.html:20 -msgid "Survey" -msgstr "Encuesta" - -#: client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js:60 -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:64 -msgid "" -"Surveys allow users to be prompted at job launch with a series of questions " -"related to the job. This allows for variables to be defined that affect the " -"playbook run at time of launch." -msgstr "" -"Las encuestas permiten que los usuarios reciban una serie de preguntas " -"relacionadas a la tarea en el momento de su ejecución. Esto permite que se " -"definan las variables que afectan el playbook ejecutado en el lanzamiento." - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:58 -msgid "Sync all inventory sources" -msgstr "Sincronizar todas las fuentes de inventario" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:29 -msgid "Sync canceled. Click to view log." -msgstr "Sincronización cancelada. Haga clic para ver el registro." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:35 -msgid "Sync completed. Click to view log." -msgstr "Sincronización completada. Haga clic para ver el registro." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:32 -msgid "Sync failed. Click to view log." -msgstr "Error en la sincronización. Haga clic para ver el registro." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "Sync not performed. Click" -msgstr "Sincronización no realizada. Haga clic" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:38 -msgid "Sync pending." -msgstr "Sincronización pendiente." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:45 -msgid "Sync running" -msgstr "Sincronización en ejecución" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:46 -msgid "Sync running. Click to view log." -msgstr "Sincronización en ejecución. Haga clic para ver el registro." - -#: client/src/configuration/configuration.partial.html:17 -msgid "System" -msgstr "Sistema" - -#: client/src/users/add/users-add.controller.js:12 -#: client/src/users/edit/users-edit.controller.js:12 -#: client/src/users/list/users-list.controller.js:12 -msgid "System Administrator" -msgstr "Administrador de sistema" - -#: client/src/users/add/users-add.controller.js:11 -#: client/src/users/edit/users-edit.controller.js:11 -#: client/src/users/list/users-list.controller.js:11 -msgid "System Auditor" -msgstr "Auditor de sistema" - -#: client/src/configuration/configuration.partial.html:3 -msgid "System auditors have read-only permissions in this section." -msgstr "" -"Los auditores de sistema tienen permisos sólo de lectura en esta sección." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:114 -msgid "TACACS+" -msgstr "TACACS+" - -#: client/src/activity-stream/get-target-title.factory.js:23 -#: client/src/organizations/linkout/organizations-linkout.route.js:97 -#: client/src/organizations/list/organizations-list.controller.js:60 -#: client/src/teams/main.js:46 client/src/teams/teams.list.js:14 -#: client/src/teams/teams.list.js:15 -msgid "TEAMS" -msgstr "EQUIPOS" - -#: client/src/activity-stream/get-target-title.factory.js:44 -#: client/src/main-menu/main-menu.partial.html:113 -#: client/src/main-menu/main-menu.partial.html:35 -#: client/src/templates/list/templates-list.route.js:13 -#: client/src/templates/templates.list.js:15 -#: client/src/templates/templates.list.js:16 -msgid "TEMPLATES" -msgstr "PLANTILLAS" - -#: client/src/instance-groups/instance-groups.list.js:8 -msgid "THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED" -msgstr "NO HAY INSTANCIAS DE GRUPOS DEFINIDAS EN ESTE MOMENTO" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:104 -msgid "TIME" -msgstr "DURACIÓN" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:61 -msgid "TOP" -msgstr "SUPERIOR" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:181 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:262 -msgid "Tag None:" -msgstr "Ninguna etiqueta:" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:133 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task." -msgstr "" -"Etiquetas son útiles cuando se tiene un playbook largo y se desea " -"especificar una parte específica de una jugada o tarea." - -#: client/src/templates/job_templates/job-template.form.js:206 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task. Use commas to separate multiple tags. Refer" -" to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"Las etiquetas resultan útiles cuando tiene un manual de gran tamaño y desea " -"omitir partes específicas de la tarea o la reproducción. Utilice comas para " -"separar las distintas etiquetas. Consulte la documentación de Ansible Tower " -"para obtener información detallada sobre el uso de etiquetas." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:179 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "Tags:" -msgstr "Etiquetas:" - -#: client/src/notifications/notificationTemplates.form.js:309 -msgid "Target URL" -msgstr "URL destino" - -#: client/src/job-results/job-results.partial.html:496 -msgid "Tasks" -msgstr "Tareas" - -#: client/features/credentials/legacy.credentials.js:94 -#: client/src/credentials/credentials.form.js:467 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:154 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:155 -#: client/src/projects/projects.form.js:261 -#: client/src/templates/workflows.form.js:144 -msgid "Team Roles" -msgstr "Funciones de equipo" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:34 -#: client/src/organizations/linkout/organizations-linkout.route.js:108 -#: client/src/setup-menu/setup-menu.partial.html:16 -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/users/users.form.js:159 -msgid "Teams" -msgstr "Equipos" - -#: client/src/job-results/job-results.partial.html:135 -#: client/src/templates/templates.list.js:14 -msgid "Template" -msgstr "Plantilla" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:35 -msgid "Templates" -msgstr "Plantillas" - -#: client/src/credentials/credentials.form.js:337 -msgid "Tenant ID" -msgstr "ID inquilino [Tenant]" - -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:79 -msgid "Test" -msgstr "Probar" - -#: client/src/notifications/notificationTemplates.list.js:67 -msgid "Test notification" -msgstr "Probar notificación" - -#: client/src/shared/form-generator.js:1386 -#: client/src/shared/form-generator.js:1392 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" -"El valor no fue encontrado. Por favor introduzca o seleccione un valor " -"válido." - -#: client/lib/components/components.strings.js:43 -msgid "That value was not found. Please enter or select a valid value." -msgstr "No se encontró ese valor. Introduzca o seleccione un valor válido." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:66 -msgid "The Insights Credential for {{inventory.name}} was not found." -msgstr "No se encontró la credencial de Insights para {{inventory.name}}." - -#: client/src/credentials/factories/become-method-change.factory.js:32 -#: client/src/credentials/factories/kind-change.factory.js:89 -msgid "" -"The Project ID is the GCE assigned identification. It is constructed as two " -"words followed by a three digit number. Such as:" -msgstr "" -"El ID del proyecto es el identificador asignado en GCE. Se construye de dos " -"palabras seguidas por tres dígitos. Ejemplo:" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "The SCM update process is running." -msgstr "El proceso de actualización SCM está en ejecución." - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:70 -msgid "The credential used to run this command." -msgstr "El credencial utilizado para ejecutar este comando." - -#: client/src/credentials/credentials.form.js:190 -msgid "" -"The email address assigned to the Google Compute Engine %sservice account." -msgstr "" -"La dirección de correo asignada a la cuenta de servicio Google Compute " -"Engine %s." - -#: client/src/job-results/job-results.partial.html:513 -msgid "The host count will update when the job is complete." -msgstr "El conteo de hosts se actualizará cuando se complete la tarea." - -#: client/src/credentials/factories/become-method-change.factory.js:62 -#: client/src/credentials/factories/kind-change.factory.js:119 -msgid "The host to authenticate with." -msgstr "El servidor al que autentificarse." - -#: client/src/credentials/factories/kind-change.factory.js:60 -msgid "The host value" -msgstr "El valor del servidor" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:61 -msgid "The inventory this command ran on." -msgstr "El inventario en el cual este comando se ejecutará." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:101 -msgid "" -"The inventory will be in a pending status until the final delete is " -"processed." -msgstr "" -"El inventario estará en un estado pendiente hasta que se procese la " -"eliminación final." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:104 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Inputting no value will use the default value from the %sansible " -"configuration file%s." -msgstr "" -"La cantidad de procesos paralelos o simultáneos que se utiliza cuando se " -"ejecuta el playbook. Si no ingresa un valor, se utilizará el valor " -"predeterminado desde el %sfichero de configuración ansible%s." - -#: client/src/templates/job_templates/job-template.form.js:152 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Value defaults to 0. Refer to the Ansible documentation for " -"details about the configuration file." -msgstr "" -"Cantidad de procesos paralelos o simultáneos que se utilizan al ejecutar el " -"manual. Los valores se establecen de manera predeterminada en 0. Consulte la" -" documentación de Ansible Tower para obtener información detallada sobre el " -"archivo de configuración." - -#: client/src/job-results/job-results.controller.js:619 -msgid "The output is too large to display. Please download." -msgstr "La salida es muy larga para ser mostrada. Por favor descárguela." - -#: client/src/credentials/factories/kind-change.factory.js:59 -msgid "The project value" -msgstr "El valor del proyecto" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "" -"The selected project is not configured for SCM. To configure for SCM, edit " -"the project and provide SCM settings, and then run an update." -msgstr "" -"El proyecto seleccionado no está configurado para usar SCM. Para configurar " -"el uso SCM, edita el proyecto y establezca opciones SCM y ejecute una " -"actualización." - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:42 -msgid "" -"The standard output is too large to display. Please specify additional " -"filters to narrow the standard out." -msgstr "" -"La salida estándar es demasiado larga para ser mostrada. Especifique filtros" -" adicionales para limitar la salida estándar." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:52 -msgid "" -"The suggested format for variable names is lowercase and underscore-" -"separated (for example, foo_bar, user_id, host_name, etc.). Variable names " -"with spaces are not allowed." -msgstr "" -"El formato sugerido para los nombres de variables es minúsculas y guiones " -"bajos (por ejemplo, foo_bar, user_id, host_name, etc.). No están permitidos " -"los nombres de variables con espacios." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:124 -msgid "The time must be in HH24:MM:SS format." -msgstr "La hora debe ser en formato HH24:MM:SS" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:79 -msgid "The user who ran this command." -msgstr "El usuario que ejecuta este comando." - -#: client/src/activity-stream/streams.list.js:17 -msgid "There are no events to display at this time" -msgstr "No hay eventos a mostrar por el momento" - -#: client/src/portal-mode/portal-job-templates.list.js:18 -msgid "There are no job templates to display at this time" -msgstr "No hay plantillas de trabajo a mostrar por el momento" - -#: client/src/portal-mode/portal-jobs.list.js:18 -msgid "There are no jobs to display at this time" -msgstr "No hay trabajos a mostrar por el momento" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "" -"There is no SCM update information available for this project. An update has" -" not yet been completed. If you have not already done so, start an update " -"for this project." -msgstr "" -"No hay información disponible de la actualización SCM disponible para este " -"proyecto. Una actualización no ha sido todavía completada." - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:140 -msgid "There was an error deleting inventory source groups. Returned status:" -msgstr "" -"Se produjo un error al eliminar los grupos de la fuente del inventario. " -"Estado devuelto:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:130 -msgid "There was an error deleting inventory source hosts. Returned status:" -msgstr "" -"Se produjo un error al eliminar los hosts de la fuente del inventario. " -"Estado devuelto:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:167 -msgid "There was an error deleting inventory source. Returned status:" -msgstr "" -"Se produjo un error al eliminar la fuente del inventario. Estado devuelto:" - -#: client/src/configuration/configuration.controller.js:349 -msgid "There was an error resetting value. Returned status:" -msgstr "Ha habido un error reiniciando el valor. Estado devuelto:" - -#: client/src/configuration/configuration.controller.js:531 -msgid "There was an error resetting values. Returned status:" -msgstr "Ha habido un error reiniciando valores. Estado devuelto:" - -#: client/src/configuration/system-form/configuration-system.controller.js:232 -msgid "There was an error testing the log aggregator. Returned status:" -msgstr "" -"Se produjo un error al probar el agregador de registros. Estado devuelto:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:29 -msgid "" -"These are the modules that {{BRAND_NAME}} supports running commands against." -msgstr "" -"Estos son los módulos que {{BRAND_NAME}} admite para ejecutar comandos." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:26 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "This group contains" -msgstr "Este grupo contiene" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:168 -msgid "This is not a valid number." -msgstr "Éste no es un número válido." - -#: client/src/credentials/factories/become-method-change.factory.js:59 -#: client/src/credentials/factories/kind-change.factory.js:116 -msgid "" -"This is the tenant name. This value is usually the same as the username." -msgstr "" -"Este es el nombre del inquilino [Tenant]. Este valor normalmente es el mismo" -" que el usuario." - -#: client/src/notifications/notifications.list.js:21 -msgid "" -"This list is populated by notification templates added from the " -"%sNotifications%s section" -msgstr "" -"La lista contiene las plantillas de notificación añadidas desde la sección " -"%sNotificaciones%s" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:4 -msgid "" -"This machine has not checked in with Insights in {{last_check_in}} hours" -msgstr "" -"Esta máquina no se ha registrado con Insights en {{last_check_in}} horas" - -#: client/src/shared/form-generator.js:746 -msgid "" -"This setting has been set manually in a settings file and is now disabled." -msgstr "" -"Este valor ha sido establecido manualmente en el fichero de configuración y " -"ahora está inhabilitado." - -#: client/src/users/users.form.js:164 -msgid "This user is not a member of any teams" -msgstr "Este usuario no es miembro de ningún equipo." - -#: client/src/shared/form-generator.js:856 -#: client/src/shared/form-generator.js:951 -msgid "" -"This value does not match the password you entered previously. Please " -"confirm that password." -msgstr "" -"Este valor no corresponde con la contraseña introducida anteriormente. Por " -"favor confirme la contraseña." - -#: client/src/configuration/configuration.controller.js:556 -msgid "" -"This will reset all configuration values to their factory defaults. Are you " -"sure you want to proceed?" -msgstr "" -"Esta operación reiniciará todos los valores de configuración a los valores " -"por defecto de fábrica. ¿Está seguro de querer continuar?" - -#: client/src/activity-stream/streams.list.js:25 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:14 -#: client/src/notifications/notification-templates-list/list.controller.js:72 -msgid "Time" -msgstr "Duración" - -#: client/src/license/license.partial.html:45 -msgid "Time Remaining" -msgstr "Tiempo restante" - -#: client/src/projects/projects.form.js:196 -msgid "" -"Time in seconds to consider a project to be current. During job runs and " -"callbacks the task system will evaluate the timestamp of the latest project " -"update. If it is older than Cache Timeout, it is not considered current, and" -" a new project update will be performed." -msgstr "" -"Tiempo en segundos a considerar que un proyecto es reciente. Durante la " -"ejecución del trabajo y callbacks la tarea del sistema evaluará la fecha y " -"hora de la última actualización del proyecto. Si es más antigua que el " -"tiempo de expiración de caché, se considera que no es reciente y una nueva " -"actualización del proyecto será llevada a cabo." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:387 -msgid "" -"Time in seconds to consider an inventory sync to be current. During job runs" -" and callbacks the task system will evaluate the timestamp of the latest " -"sync. If it is older than Cache Timeout, it is not considered current, and a" -" new inventory sync will be performed." -msgstr "" -"Tiempo en segundos para que la sincronización del inventario esté " -"actualizada. Durante la ejecución de trabajos y callbacks, el sistema de " -"tareas evaluará la marca de tiempo de la última sincronización. Si es " -"anterior al Tiempo de espera para la ejecución del caché, no se considera " -"actualizada y se llevará a cabo una nueva sincronización del inventario." - -#: client/src/credentials/credentials.form.js:125 -msgid "" -"To learn more about the IAM STS Token, refer to the %sAmazon " -"documentation%s." -msgstr "" -"Para aprender más sobre el token de IAM STS, acuda a la documentación de " -"%sAmazon%s." - -#: client/src/shared/form-generator.js:881 -msgid "Toggle the display of plaintext." -msgstr "Conmutar la visualización en texto plano." - -#: client/src/notifications/shared/type-change.service.js:34 -#: client/src/notifications/shared/type-change.service.js:40 -msgid "Token" -msgstr "Token" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:44 -msgid "Too much previous output to display. Showing running standard output." -msgstr "" -"La salida es demasiado antigua para ser mostrada. Mostrando salida estándar " -"en ejecución." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:10 -msgid "Total Issues" -msgstr "Total de problemas" - -#: client/src/partials/logviewer.html:6 -msgid "Traceback" -msgstr "Traceback" - -#: client/src/credentials/credentials.form.js:60 -#: client/src/credentials/credentials.form.js:84 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:52 -#: client/src/instance-groups/jobs/jobs.list.js:51 -#: client/src/inventories-hosts/inventories/inventory.list.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:52 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:41 -#: client/src/jobs/all-jobs.list.js:59 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:39 -#: client/src/notifications/notifications.list.js:31 -#: client/src/projects/projects.list.js:44 -#: client/src/scheduler/scheduled-jobs.list.js:42 -#: client/src/teams/teams.form.js:130 -#: client/src/templates/completed-jobs.list.js:53 -#: client/src/templates/templates.list.js:31 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:27 -#: client/src/users/users.form.js:200 -msgid "Type" -msgstr "Tipo" - -#: client/features/credentials/credentials.strings.js:18 -#: client/src/credentials/credentials.form.js:23 -#: client/src/notifications/notificationTemplates.form.js:26 -msgid "Type Details" -msgstr "Detalles del tipo" - -#: client/src/projects/add/projects-add.controller.js:169 -#: client/src/projects/edit/projects-edit.controller.js:304 -msgid "URL popover text" -msgstr "Texto 'popover' de la URL" - -#: client/src/login/loginModal/loginModal.partial.html:49 -msgid "USERNAME" -msgstr "NOMBRE DE USUARIO" - -#: client/src/activity-stream/get-target-title.factory.js:20 -#: client/src/organizations/linkout/organizations-linkout.route.js:42 -#: client/src/organizations/list/organizations-list.controller.js:54 -#: client/src/users/main.js:46 client/src/users/users.list.js:18 -#: client/src/users/users.list.js:19 -msgid "USERS" -msgstr "USUARIOS" - -#: client/lib/components/components.strings.js:20 -msgid "Unable to Submit" -msgstr "No se puede enviar" - -#: client/lib/components/components.strings.js:52 -msgid "Unavailable to run jobs." -msgstr "No disponible para ejecutar tareas." - -#: client/lib/components/components.strings.js:22 -msgid "Unexpected Error" -msgstr "Error inesperado" - -#: client/lib/components/components.strings.js:21 -msgid "Unexpected server error. View the console for more information" -msgstr "" -"Error inesperado del servidor. Consulte la consola para obtener más " -"información." - -#: client/lib/components/components.strings.js:34 -msgid "Unsupported display model type" -msgstr "Tipo de modelo de visualización no compatible" - -#: client/lib/components/components.strings.js:26 -msgid "Unsupported input type" -msgstr "Tipo de entrada no compatible" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "Update Not Found" -msgstr "Actualización no encontrada" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:321 -msgid "Update Options" -msgstr "Actualizar opciones" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "Update in Progress" -msgstr "Actualización en curso" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:352 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:357 -#: client/src/projects/projects.form.js:177 -msgid "Update on Launch" -msgstr "Actualizar al ejecutar" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:364 -msgid "Update on Project Change" -msgstr "Actualizar en el cambio de proyecto" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:370 -msgid "Update on Project Update" -msgstr "Actualizar en la actualización del proyecto" - -#: client/src/license/license.partial.html:71 -msgid "Upgrade" -msgstr "Actualizar" - -#: client/src/templates/job_templates/job-template.form.js:299 -#: client/src/templates/job_templates/job-template.form.js:304 -msgid "Use Fact Cache" -msgstr "Usar caché de eventos" - -#: client/src/notifications/notificationTemplates.form.js:395 -msgid "Use SSL" -msgstr "Utilizar SSL" - -#: client/src/notifications/notificationTemplates.form.js:390 -msgid "Use TLS" -msgstr "Utilizar TLS" - -#: client/src/instance-groups/instance-group.partial.html:10 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:10 -#: client/src/instance-groups/instances/instances-list.partial.html:21 -#: client/src/instance-groups/list/instance-groups-list.partial.html:32 -msgid "Used Capacity" -msgstr "Capacidad usada" - -#: client/src/credentials/credentials.form.js:76 -msgid "" -"Used to check out and synchronize playbook repositories with a remote source" -" control management system such as Git, Subversion (svn), or Mercurial (hg)." -" These credentials are used by Projects." -msgstr "" -"Utilizado para verificar y sincronizar los repositorios playbook con sistema" -" remoto de gestión de código fuente como Git, Subversion (svn) o Mercurial " -"(hg). Estos credenciales son utilizados por proyectos." - -#: client/features/credentials/legacy.credentials.js:83 -#: client/src/credentials/credentials.form.js:456 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:143 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:144 -#: client/src/organizations/organizations.form.js:92 -#: client/src/projects/projects.form.js:250 client/src/teams/teams.form.js:93 -#: client/src/templates/workflows.form.js:133 -msgid "User" -msgstr "Usuario" - -#: client/src/configuration/configuration.partial.html:18 -msgid "User Interface" -msgstr "Interfaz de usuario" - -#: client/src/users/users.form.js:95 -msgid "User Type" -msgstr "Tipo de usuario" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:30 -#: client/src/credentials/factories/become-method-change.factory.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:38 -#: client/src/credentials/factories/kind-change.factory.js:17 -#: client/src/credentials/factories/kind-change.factory.js:41 -#: client/src/credentials/factories/kind-change.factory.js:74 -#: client/src/credentials/factories/kind-change.factory.js:95 -#: client/src/notifications/notificationTemplates.form.js:64 -#: client/src/users/users.form.js:58 client/src/users/users.list.js:29 -msgid "Username" -msgstr "Usuario" - -#: client/src/credentials/credentials.form.js:80 -msgid "" -"Usernames, passwords, and access keys for authenticating to the specified " -"cloud or infrastructure provider. These are used for smart inventory sources" -" and for cloud provisioning and deployment in playbook runs." -msgstr "" -"Nombres de usuarios, contraseñas y claves de acceso para la autenticación " -"del proveedor de nube o infraestructura especificado. Estos son utilizados " -"para fuentes de inventario inteligente y para el aprovisionamiento y la " -"implementación de nube cuando se ejecuta un playbook." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:36 -#: client/src/organizations/organizations.form.js:74 -#: client/src/setup-menu/setup-menu.partial.html:10 -#: client/src/teams/teams.form.js:75 -msgid "Users" -msgstr "Usuarios" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:7 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:7 -msgid "VIEW ALL" -msgstr "VER TODO" - -#: client/src/main-menu/main-menu.partial.html:75 -msgid "VIEW DOCUMENTATION" -msgstr "VER DOCUMENTACIÓN" - -#: client/src/shared/paginate/paginate.partial.html:48 -msgid "VIEW PER PAGE" -msgstr "VISTA POR PÁGINA" - -#: client/src/main-menu/main-menu.partial.html:51 -msgid "VIEW USER PAGE FOR {{ $root.current_user.username | uppercase }}" -msgstr "" -"MOSTRAR ṔAGINA DE USUARIO PARA {{ $root.current_user.username | uppercase }}" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:180 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:261 -msgid "VPC ID:" -msgstr "VPC ID:" - -#: client/src/license/license.partial.html:10 -msgid "Valid License" -msgstr "Licencia válida" - -#: client/src/inventories-hosts/hosts/host.form.js:68 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:46 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:67 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:67 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:81 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:88 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:94 -msgid "Variables" -msgstr "Variables" - -#: client/src/job-submission/job-submission.partial.html:364 -msgid "Vault" -msgstr "Vault" - -#: client/src/job-results/job-results.partial.html:321 -msgid "Vault Credential" -msgstr "Credencial de Vault" - -#: client/src/credentials/credentials.form.js:391 -#: client/src/job-submission/job-submission.partial.html:146 -msgid "Vault Password" -msgstr "Contraseña Vault" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:81 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:90 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:307 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:314 -#: client/src/job-results/job-results.partial.html:358 -#: client/src/job-submission/job-submission.partial.html:183 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:99 -#: client/src/templates/job_templates/job-template.form.js:174 -#: client/src/templates/job_templates/job-template.form.js:181 -msgid "Verbosity" -msgstr "Nivel de detalle" - -#: client/src/license/license.partial.html:15 -msgid "Version" -msgstr "Versión" - -#: client/src/activity-stream/streams.list.js:63 -#: client/src/credential-types/credential-types.list.js:64 -#: client/src/credentials/credentials.list.js:75 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:58 -#: client/src/inventories-hosts/inventories/inventory.list.js:104 -#: client/src/inventory-scripts/inventory-scripts.list.js:62 -#: client/src/notifications/notificationTemplates.list.js:82 -#: client/src/scheduler/schedules.list.js:83 client/src/teams/teams.list.js:64 -#: client/src/templates/templates.list.js:112 -#: client/src/users/users.list.js:70 -msgid "View" -msgstr "Mostrar" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "View Activity Stream" -msgstr "Mostrar el flujo de actividad" - -#: client/src/main-menu/main-menu.partial.html:173 -msgid "View Documentation" -msgstr "Mostrar la documentación" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:79 -msgid "View Insights Data" -msgstr "Ver datos de Insights" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:202 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:226 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:250 -msgid "View JSON examples at" -msgstr "Ver ejemplos de JSON en" - -#: client/src/inventories-hosts/hosts/host.form.js:78 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:77 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:77 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:91 -msgid "View JSON examples at %s" -msgstr "Mostrar los ejemplos JSON en %s" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:13 -msgid "View Less" -msgstr "Ver menos" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:11 -msgid "View More" -msgstr "Ver más" - -#: client/src/shared/form-generator.js:1719 -#: client/src/templates/job_templates/job-template.form.js:436 -#: client/src/templates/workflows.form.js:161 -msgid "View Survey" -msgstr "Mostrar la encuesta" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:203 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:227 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:251 -msgid "View YAML examples at" -msgstr "Ver ejemplos de YAML en" - -#: client/src/inventories-hosts/hosts/host.form.js:79 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:78 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:78 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:92 -msgid "View YAML examples at %s" -msgstr "Mostrar los ejemplos YAML en %s" - -#: client/src/setup-menu/setup-menu.partial.html:72 -msgid "View Your License" -msgstr "Mostrar su licencia" - -#: client/src/setup-menu/setup-menu.partial.html:73 -msgid "View and edit your license information." -msgstr "Mostrar y editar su información de licencia." - -#: client/src/credentials/credentials.list.js:77 -msgid "View credential" -msgstr "Mostrar credencial" - -#: client/src/credential-types/credential-types.list.js:66 -msgid "View credential type" -msgstr "Ver tipo de credencial" - -#: client/src/activity-stream/streams.list.js:67 -msgid "View event details" -msgstr "Mostrar detalles del evento" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:93 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:103 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:91 -msgid "View group" -msgstr "Ver grupo" - -#: client/src/inventories-hosts/hosts/host.list.js:89 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:93 -msgid "View host" -msgstr "Ver host" - -#: client/src/setup-menu/setup-menu.partial.html:67 -msgid "View information about this version of Ansible {{BRAND_NAME}}." -msgstr "Ver información acerca de esta versión de Ansible {{BRAND_NAME}}." - -#: client/src/inventories-hosts/inventories/inventory.list.js:106 -msgid "View inventory" -msgstr "Mostrar inventario" - -#: client/src/inventory-scripts/inventory-scripts.list.js:64 -msgid "View inventory script" -msgstr "Mostrar script de inventario" - -#: client/src/setup-menu/setup-menu.partial.html:55 -msgid "View list and capacity of {{BRAND_NAME}} instances." -msgstr "Ver lista y capacidad de las instancias de {{BRAND_NAME}}." - -#: client/src/notifications/notificationTemplates.list.js:84 -msgid "View notification" -msgstr "Mostrar notificación" - -#: client/src/job-results/job-results.partial.html:222 -msgid "View project sync results" -msgstr "Ver resultados de sincronización del proyecto" - -#: client/src/scheduler/schedules.list.js:85 -msgid "View schedule" -msgstr "Mostrar el calendario" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:118 -msgid "View source" -msgstr "Ver fuente" - -#: client/src/teams/teams.list.js:67 -msgid "View team" -msgstr "Mostrar equipo" - -#: client/src/templates/templates.list.js:114 -msgid "View template" -msgstr "Mostrar plantilla" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "View the" -msgstr "Ver" - -#: client/src/jobs/all-jobs.list.js:92 -msgid "View the job" -msgstr "Mostrar el trabajo" - -#: client/src/projects/projects.list.js:111 -msgid "View the project" -msgstr "Mostrar el proyecto" - -#: client/src/scheduler/scheduled-jobs.list.js:74 -msgid "View the schedule" -msgstr "Mostrar el calendario" - -#: client/src/users/users.list.js:73 -msgid "View user" -msgstr "Mostrar usuario" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:42 -#: client/src/instance-groups/jobs/jobs.list.js:41 -#: client/src/job-results/job-results.partial.html:145 -#: client/src/jobs/all-jobs.list.js:49 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:25 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:25 -msgid "View workflow results" -msgstr "Mostrar resultados del flujo de trabajo" - -#: client/src/templates/workflows.form.js:20 -msgid "WORKFLOW" -msgstr "FLUJO DE TRABAJO" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:73 -#: client/src/configuration/configuration.controller.js:200 -#: client/src/configuration/configuration.controller.js:262 -#: client/src/configuration/system-form/configuration-system.controller.js:55 -msgid "Warning: Unsaved Changes" -msgstr "Aviso: modificaciones no guardadas" - -#: client/src/license/license.partial.html:78 -msgid "" -"Welcome to Ansible Tower! Please complete the steps below to acquire a " -"license." -msgstr "" -"¡Bienvenido a Ansible Tower! Por favor complete los siguientes pasos para " -"adquirir una licencia." - -#: client/src/login/loginModal/loginModal.partial.html:17 -msgid "Welcome to Ansible {{BRAND_NAME}}!  Please sign in." -msgstr "¡Bienvenido a Ansible {{BRAND_NAME}}!  Inicie sesión." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:344 -msgid "" -"When not checked, a merge will be performed, combining local variables with " -"those found on the external source." -msgstr "" -"Si la opción no está marcada, se llevará a cabo una fusión y se combinarán " -"las variables locales con las variables halladas en la fuente externa." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:332 -msgid "" -"When not checked, local child hosts and groups not found on the external " -"source will remain untouched by the inventory update process." -msgstr "" -"Si la opción no está marcada, los hosts hijos y los grupos locales que no se" -" encuentren en la fuente externa no se modificarán a partir del proceso de " -"actualización del inventario." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:97 -msgid "" -"When this template is submitted as a job, setting the type to %s will " -"execute the playbook, running tasks on the selected hosts." -msgstr "" -"Cuando una plantilla es lanzada como un trabajo, configurar el tipo a %s " -"ejecutará el playbook, ejecutará las tareas en los servidores seleccionados." - -#: client/src/shared/form-generator.js:1723 -#: client/src/templates/workflows.form.js:187 -msgid "Workflow Editor" -msgstr "Editor de flujo de trabajo" - -#: client/src/templates/templates.list.js:66 -msgid "Workflow Template" -msgstr "Plantilla de flujo de trabajo" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:41 -msgid "Workflow Templates" -msgstr "Plantillas de flujo de trabajo" - -#: client/src/job-submission/job-submission.partial.html:171 -msgid "YAML" -msgstr "YAML" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:200 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:224 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:248 -msgid "YAML:" -msgstr "YAML:" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Yellow" -msgstr "Amarillo" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:56 -msgid "" -"You can create a job template here." -msgstr "" -"Usted puede crear una plantilla de trabajo aquí." - -#: client/src/projects/edit/projects-edit.controller.js:62 -msgid "You do not have access to view this property" -msgstr "Usted no tiene permiso para ver esta propiedad" - -#: client/src/projects/add/projects-add.controller.js:29 -msgid "You do not have permission to add a project." -msgstr "Usted no tiene permiso para añadir un proyecto." - -#: client/src/users/add/users-add.controller.js:43 -msgid "You do not have permission to add a user." -msgstr "Usted no tiene permiso para añadir un usuario." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:28 -msgid "You do not have sufficient permissions to edit the host filter." -msgstr "No tiene permisos suficientes para editar el filtro del host." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:72 -#: client/src/configuration/configuration.controller.js:199 -#: client/src/configuration/configuration.controller.js:261 -#: client/src/configuration/system-form/configuration-system.controller.js:54 -msgid "" -"You have unsaved changes. Would you like to proceed without" -" saving?" -msgstr "" -"Usted tiene modificaciones sin guardar.¿Desea proceder sin " -"guardarlas?" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "Your request to cancel the update was submitted to the task manager." -msgstr "" -"Su solicitud de cancelación de la actualización ha sido enviada al gestor de" -" tareas." - -#: client/src/login/loginModal/loginModal.partial.html:22 -msgid "Your session timed out due to inactivity. Please sign in." -msgstr "Su sesión ha expirado debido a inactividad. Por favor inicie sesión." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/shared/form-generator.js:1193 -msgid "and" -msgstr "y" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "characters long." -msgstr "caracteres." - -#: client/src/shared/smart-search/smart-search.partial.html:53 -msgid "documentation" -msgstr "documentación" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:193 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:275 -msgid "for a complete list of supported filters." -msgstr "para acceder a una lista completa de filtros compatibles." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "from the" -msgstr "del" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -#: client/src/inventories-hosts/inventory-hosts.strings.js:8 -msgid "group" -msgid_plural "groups" -msgstr[0] "grupo" -msgstr[1] "grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "groups" -msgstr "grupos" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -msgid "groups and" -msgstr "grupos y" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:9 -msgid "host" -msgid_plural "hosts" -msgstr[0] "host" -msgstr[1] "hosts" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -msgid "hosts" -msgstr "hosts" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:58 -msgid "hosts with failures. Click for details." -msgstr "hosts con fallos. Haga clic para obtener más información." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:21 -msgid "name" -msgstr "nombre" - -#: client/src/shared/paginate/paginate.partial.html:34 -msgid "of" -msgstr "de" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "of the filters match." -msgstr "de la coincidencia con los filtros." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:24 -msgid "organization" -msgstr "organización" - -#: client/src/shared/form-generator.js:1069 -msgid "playbook" -msgstr "playbook" - -#: client/src/credentials/credentials.form.js:138 -#: client/src/credentials/credentials.form.js:364 -msgid "set in helpers/credentials" -msgstr "definir en helpers/credentials" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:43 -msgid "sources with sync failures. Click for details" -msgstr "" -"fuentes con fallos en la sincronización. Haga clic para obtener más " -"información" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "test" -msgstr "prueba" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "to" -msgstr "para" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "" -"to include all regions. Only Hosts associated with the selected regions will" -" be updated." -msgstr "" -"para incluir todas las regiones. Solo se actualizarán los hosts asociados " -"con las regiones seleccionadas." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "to start it now." -msgstr "para comenzarlo ahora." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "to update." -msgstr "para actualizar." - -#: client/src/credentials/credentials.form.js:381 -msgid "v2 URLs%s - leave blank" -msgstr "v2 URLs%s - dejad en blanco" - -#: client/src/credentials/credentials.form.js:382 -msgid "v3 default%s - set to 'default'" -msgstr "v3 default%s - establecer a 'default'" - -#: client/src/credentials/credentials.form.js:383 -msgid "v3 multi-domain%s - your domain name" -msgstr "v3 multi-domain%s - vuestro nombre de dominio" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:220 -msgid "view ec2.ini in the Ansible github repo." -msgstr "vea ec2.ini en el repositorio github de Ansible." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:244 -msgid "view vmware_inventory.ini in the Ansible github repo." -msgstr "vea vmware_inventory.ini en el repositorio github de Ansible." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "when" -msgstr "cuando" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:171 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:252 -msgid "" -"will create group names similar to the following examples based on the " -"options selected:" -msgstr "" -"se crearán nombres de grupos similares a los de los siguientes ejemplos en " -"función de las opciones seleccionadas:" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:11 -msgid "with failed jobs." -msgstr "con tareas con errores." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs-list.route.js:9 -msgid "{{ breadcrumb.instance_name }}" -msgstr "{{ breadcrumb.instance_name }}" - -#: client/lib/components/input/label.partial.html:5 -msgid "{{::state._hint}}" -msgstr "{{::state._hint}}" - -#: client/src/instance-groups/instances/instances-list.route.js:10 -msgid "{{breadcrumb.instance_group_name}}" -msgstr "{{breadcrumb.instance_group_name}}" - -#: client/src/shared/paginate/paginate.partial.html:55 -msgid "{{pageSize}}" -msgstr "{{pageSize}}" diff --git a/awx/ui/po/fr.po b/awx/ui/po/fr.po deleted file mode 100644 index e88996002865..000000000000 --- a/awx/ui/po/fr.po +++ /dev/null @@ -1,6121 +0,0 @@ -# aude_stoquart , 2017. #zanata -# croe , 2017. #zanata -# mkim , 2017. #zanata -# shanemcd , 2017. #zanata -msgid "" -msgstr "" -"Project-Id-Version: \n" -"PO-Revision-Date: 2017-12-04 04:51+0000\n" -"Last-Translator: croe \n" -"Language-Team: French\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" -"X-Generator: Zanata 4.3.2\n" - -#: client/src/projects/add/projects-add.controller.js:153 -#: client/src/projects/edit/projects-edit.controller.js:288 -msgid "" -"%sNote:%s Mercurial does not support password authentication for SSH. Do not" -" put the username and key in the URL. If using Bitbucket and SSH, do not " -"supply your Bitbucket username." -msgstr "" -"%sRemarque%s : Mercurial ne prend pas en charge l’authentification par mot " -"de passe pour SSH. N’entrez ni le nom d’utilisateur, ni la clé dans l’URL. " -"Si vous utilisez Bitbucket et SSH, ne saisissez pas votre nom d’utilisateur " -"Bitbucket." - -#: client/src/projects/add/projects-add.controller.js:132 -#: client/src/projects/edit/projects-edit.controller.js:267 -msgid "" -"%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key " -"only, do not enter a username (other than git). Additionally, GitHub and " -"Bitbucket do not support password authentication when using SSH. GIT read " -"only protocol (git://) does not use username or password information." -msgstr "" -"%sRemarque%s : Si vous utilisez le protocole SSH pour GitHub ou Bitbucket, " -"entrez uniquement une clé SSH sans nom d’utilisateur (autre que git). De " -"plus, GitHub et Bitbucket ne prennent pas en charge l’authentification par " -"mot de passe lorsque SSH est utilisé. Le protocole GIT en lecture seule " -"(git://) n’utilise pas les informations de nom d’utilisateur ou de mot de " -"passe." - -#: client/src/credentials/credentials.form.js:287 -msgid "(defaults to %s)" -msgstr "(défini par défaut sur %s)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -msgid "(seconds)" -msgstr "(secondes)" - -#: client/src/organizations/list/organizations-list.partial.html:20 -msgid "+ ADD" -msgstr "+ AJOUTER" - -#: client/src/shared/paginate/paginate.partial.html:66 -msgid "100" -msgstr "100" - -#: client/src/shared/paginate/paginate.partial.html:60 -msgid "20" -msgstr "20" - -#: client/src/shared/paginate/paginate.partial.html:63 -msgid "50" -msgstr "50" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:33 -msgid "A schedule name is required." -msgstr "Un intitulé est requis pour la programmation" - -#: client/src/users/add/users-add.controller.js:102 -msgid "A value is required" -msgstr "Entrez une valeur" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:167 -msgid "A value is required." -msgstr "Entrez une valeur." - -#: client/src/about/about.route.js:10 -msgid "ABOUT" -msgstr "À PROPOS" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 -msgid "ACTION" -msgstr "ACTION" - -#: client/src/activity-stream/activity-detail.form.js:23 -msgid "ACTIVITY DETAIL" -msgstr "DÉTAILS ACTIVITÉ" - -#: client/src/activity-stream/activitystream.route.js:28 -#: client/src/activity-stream/streams.list.js:14 -#: client/src/activity-stream/streams.list.js:15 -msgid "ACTIVITY STREAM" -msgstr "FLUX D’ACTIVITÉ" - -#: client/features/credentials/legacy.credentials.js:76 -#: client/src/credential-types/credential-types.list.js:44 -#: client/src/credentials/credentials.form.js:449 -#: client/src/credentials/credentials.list.js:54 -#: client/src/inventories-hosts/inventories/inventory.list.js:77 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:71 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:120 -#: client/src/inventory-scripts/inventory-scripts.list.js:42 -#: client/src/notifications/notificationTemplates.list.js:54 -#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 -#: client/src/organizations/organizations.form.js:84 -#: client/src/projects/projects.form.js:243 -#: client/src/projects/projects.list.js:78 -#: client/src/scheduler/schedules.list.js:68 client/src/teams/teams.form.js:85 -#: client/src/teams/teams.list.js:45 -#: client/src/templates/job_templates/job-template.form.js:397 -#: client/src/templates/templates.list.js:58 -#: client/src/templates/workflows.form.js:125 -#: client/src/users/users.list.js:50 -msgid "ADD" -msgstr "AJOUTER" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:71 -msgid "ADD GROUP" -msgstr "AJOUTER UN GROUPE" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:125 -msgid "ADD HOST" -msgstr "AJOUTER UN HÔTE" - -#: client/src/teams/teams.form.js:157 client/src/users/users.form.js:216 -msgid "ADD PERMISSIONS" -msgstr "AJOUTER PERMISSION" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:70 -msgid "ADD SOURCE" -msgstr "AJOUTER UNE SOURCE" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:16 -msgid "ADD SURVEY PROMPT" -msgstr "AJOUTER UNE INVITE AU QUESTIONNAIRE" - -#: client/src/shared/smart-search/smart-search.partial.html:51 -msgid "ADDITIONAL INFORMATION" -msgstr "INFORMATIONS SUPPLÉMENTAIRES" - -#: client/src/organizations/linkout/organizations-linkout.route.js:330 -#: client/src/organizations/list/organizations-list.controller.js:84 -msgid "ADMINS" -msgstr "ADMINS" - -#: client/src/activity-stream/get-target-title.factory.js:4 -msgid "ALL ACTIVITY" -msgstr "ACTIVITÉS" - -#: client/src/jobs/all-jobs.list.js:14 -msgid "ALL JOBS" -msgstr "TOUTES LES TÂCHES" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "ANY" -msgstr "QUELCONQUE" - -#: client/src/credentials/credentials.form.js:198 -msgid "API Key" -msgstr "Clé API" - -#: client/src/notifications/notificationTemplates.form.js:243 -msgid "API Service/Integration Key" -msgstr "Service API/Clé d’intégration" - -#: client/src/notifications/shared/type-change.service.js:52 -msgid "API Token" -msgstr "Token API" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:71 -msgid "ASSOCIATE GROUP" -msgstr "ASSOCIER UN GROUPE" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js:19 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js:19 -msgid "ASSOCIATED GROUPS" -msgstr "GROUPES ASSOCIÉS" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js:19 -msgid "ASSOCIATED HOSTS" -msgstr "HÔTES ASSOCIÉS" - -#: client/src/setup-menu/setup-menu.partial.html:66 -msgid "About {{BRAND_NAME}}" -msgstr "À propos de {{BRAND_NAME}}" - -#: client/src/credentials/credentials.form.js:91 -msgid "Access Key" -msgstr "Clé d’accès" - -#: client/src/notifications/notificationTemplates.form.js:221 -msgid "Account SID" -msgstr "SID de compte" - -#: client/src/notifications/notificationTemplates.form.js:180 -msgid "Account Token" -msgstr "Token de compte" - -#: client/src/activity-stream/activity-detail.form.js:36 -msgid "Action" -msgstr "Action" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/inventories-hosts/hosts/hosts.partial.html:47 -#: client/src/shared/list-generator/list-generator.factory.js:573 -msgid "Actions" -msgstr "Actions" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:17 -#: client/src/templates/templates.list.js:36 -msgid "Activity" -msgstr "Activité" - -#: client/src/configuration/system-form/configuration-system.controller.js:88 -msgid "Activity Stream" -msgstr "Flux d’activité" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:131 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:132 -#: client/src/organizations/organizations.form.js:81 -#: client/src/teams/teams.form.js:82 -#: client/src/templates/workflows.form.js:122 -msgid "Add" -msgstr "Ajouter" - -#: client/src/credentials/credentials.list.js:14 -msgid "Add Credentials" -msgstr "Ajouter des informations d’identification" - -#: client/src/inventories-hosts/inventories/inventory.list.js:13 -msgid "Add Inventories" -msgstr "Ajouter des inventaires" - -#: client/src/shared/stateDefinitions.factory.js:288 -msgid "Add Permissions" -msgstr "Ajouter les permissions" - -#: client/src/projects/projects.list.js:13 -msgid "Add Project" -msgstr "Ajouter un projet" - -#: client/src/shared/form-generator.js:1711 -#: client/src/templates/job_templates/job-template.form.js:445 -#: client/src/templates/workflows.form.js:170 -msgid "Add Survey" -msgstr "Ajouter un questionnaire" - -#: client/src/teams/teams.list.js:13 -msgid "Add Team" -msgstr "Ajouter une équipe" - -#: client/src/teams/teams.form.js:83 -msgid "Add User" -msgstr "Ajouter un utilisateur" - -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/shared/stateDefinitions.factory.js:578 -#: client/src/users/users.list.js:17 -msgid "Add Users" -msgstr "Ajouter des utilisateurs" - -#: client/src/organizations/organizations.form.js:82 -msgid "Add Users to this organization." -msgstr "Ajouter des utilisateurs à cette organisation." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:69 -msgid "Add a group" -msgstr "Ajouter un groupe" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:118 -msgid "Add a host" -msgstr "Ajouter un hôte" - -#: client/src/scheduler/schedules.list.js:66 -msgid "Add a new schedule" -msgstr "Ajouter une nouvelle programmation" - -#: client/features/credentials/legacy.credentials.js:74 -#: client/src/credentials/credentials.form.js:447 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:133 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:134 -#: client/src/projects/projects.form.js:241 -#: client/src/templates/job_templates/job-template.form.js:395 -#: client/src/templates/workflows.form.js:123 -msgid "Add a permission" -msgstr "Ajouter une permission" - -#: client/src/setup-menu/setup-menu.partial.html:23 -msgid "" -"Add passwords, SSH keys, and other credentials to use when launching jobs " -"against machines, or when syncing inventories or projects." -msgstr "" -"Ajouter des mots de passe, des clés SSH et d'autres informations de " -"connexion afin de les utiliser lors du lancement de tâches sur des machines " -"ou durant la synchronisation d'inventaires ou de projets." - -#: client/src/shared/form-generator.js:1446 -msgid "Admin" -msgstr "Administrateur" - -#: client/src/organizations/linkout/organizations-linkout.route.js:354 -msgid "Admins" -msgstr "Admins" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:367 -msgid "" -"After every project update where the SCM revision changes, refresh the " -"inventory from the selected source before executing job tasks. This is " -"intended for static content, like the Ansible inventory .ini file format." -msgstr "" -"Chaque fois qu’un projet est mis à jour et que la révision SCM est modifiée," -" réalisez une mise à jour de la source sélectionnée avant de lancer la " -"tâche. Le but est le contenu statique, comme le format .ini de fichier " -"d'inventaire Ansible." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:37 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:43 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:65 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:74 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "All" -msgstr "Tous" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 -msgid "All Activity" -msgstr "Activités" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:10 -#: client/src/portal-mode/portal-mode-layout.partial.html:17 -msgid "All Jobs" -msgstr "Toutes les tâches" - -#: client/src/templates/job_templates/job-template.form.js:275 -#: client/src/templates/job_templates/job-template.form.js:282 -msgid "Allow Provisioning Callbacks" -msgstr "Autoriser les rappels d’exécution de Tower job_template" - -#: client/src/setup-menu/setup-menu.partial.html:11 -msgid "" -"Allow others to sign into {{BRAND_NAME}} and own the content they create." -msgstr "" -"Autoriser les autres à se connecter à {{BRAND_NAME}} et à devenir " -"propriétaire du contenu qu'ils créent." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:43 -msgid "Always" -msgstr "Toujours" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "" -"An SCM update does not appear to be running for project: %s. Click the " -"%sRefresh%s button to view the latest status." -msgstr "" -"Une mise à jour SCM ne semble pas s’exécuter pour le projet : %s. Cliquez " -"sur le bouton %sActualiser%s pour voir l’état le plus récent." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:62 -#: client/src/templates/survey-maker/shared/question-definition.form.js:68 -msgid "Answer Type" -msgstr "Type de réponse" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:44 -#: client/src/templates/survey-maker/shared/question-definition.form.js:53 -msgid "Answer Variable Name" -msgstr "Nom de variable de réponse" - -#: client/src/job-results/job-results.service.js:144 -msgid "Are you sure you want to cancel the job below?" -msgstr "Voulez-vous vraiment supprimer la tâche ci-dessous ?" - -#: client/src/credentials/list/credentials-list.controller.js:133 -msgid "Are you sure you want to delete the credential below?" -msgstr "" -"Voulez-vous vraiment supprimer les informations d’identification ci-dessous " -"?" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:100 -msgid "Are you sure you want to delete the inventory below?" -msgstr "Voulez-vous vraiment supprimer l'inventaire ci-dessous ?" - -#: client/src/job-results/job-results.service.js:95 -#: client/src/jobs/factories/delete-job.factory.js:110 -msgid "Are you sure you want to delete the job below?" -msgstr "Voulez-vous vraiment supprimer la tâche ci-dessous ?" - -#: client/src/notifications/notification-templates-list/list.controller.js:190 -msgid "Are you sure you want to delete the notification template below?" -msgstr "Voulez-vous vraiment supprimer le modèle de notification ci-dessous ?" - -#: client/src/organizations/list/organizations-list.controller.js:172 -msgid "Are you sure you want to delete the organization below?" -msgstr "Voulez-vous vraiment supprimer l’organisation ci-dessous ?" - -#: client/src/projects/list/projects-list.controller.js:208 -msgid "Are you sure you want to delete the project below?" -msgstr "Voulez-vous vraiment supprimer le projet ci-dessous ?" - -#: client/src/templates/list/templates-list.controller.js:103 -msgid "Are you sure you want to delete the template below?" -msgstr "Voulez-vous vraiment supprimer le modèle ci-dessous ?" - -#: client/src/users/list/users-list.controller.js:90 -msgid "Are you sure you want to delete the user below?" -msgstr "Voulez-vous vraiment supprimer l’utilisateur ci-dessous ?" - -#: client/src/partials/survey-maker-modal.html:13 -msgid "Are you sure you want to delete this {{deleteMode}}?" -msgstr "Êtes-vous certain de vouloir supprimer ce {{deleteMode}}?" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:25 -msgid "Are you sure you want to disassociate the group below from" -msgstr "Voulez-vous vraiment supprimer le groupe ci-dessous de" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:23 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:26 -msgid "Are you sure you want to disassociate the host below from" -msgstr "Voulez-vous vraiment supprimer l'hôte ci-dessous de" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:47 -msgid "" -"Are you sure you want to permanently delete the group below from the " -"inventory?" -msgstr "" -"Voulez-vous vraiment supprimer définitivement le groupe ci-dessous de " -"l'inventaire ?" - -#: client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js:106 -msgid "" -"Are you sure you want to permanently delete the host below from the " -"inventory?" -msgstr "" -"Voulez-vous vraiment supprimer définitivement l'hôte ci-dessous de " -"l'inventaire ?" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:69 -msgid "" -"Are you sure you want to permanently delete the inventory source below from " -"the inventory?" -msgstr "" -"Voulez-vous vraiment supprimer définitivement la source de l'inventaire ci-" -"dessous ?" - -#: client/src/projects/edit/projects-edit.controller.js:244 -msgid "Are you sure you want to remove the %s below from %s?" -msgstr "Voulez-vous vraiment supprimer le %s ci-dessous de %s ?" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:39 -msgid "Arguments" -msgstr "Arguments" - -#: client/src/credentials/credentials.form.js:232 -#: client/src/credentials/credentials.form.js:271 -#: client/src/credentials/credentials.form.js:311 -#: client/src/credentials/credentials.form.js:397 -msgid "Ask at runtime?" -msgstr "Demander durant l’éxecution ?" - -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:69 -msgid "Associate an existing group" -msgstr "Associer un groupe existant" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:51 -msgid "Associate this host with a new group" -msgstr "Associer cet hôte à un nouveau groupe" - -#: client/src/shared/form-generator.js:1448 -msgid "Auditor" -msgstr "Auditeur" - -#: client/src/configuration/configuration.partial.html:15 -msgid "Authentication" -msgstr "Authentification" - -#: client/src/credentials/credentials.form.js:72 -msgid "" -"Authentication for network device access. This can include SSH keys, " -"usernames, passwords, and authorize information. Network credentials are " -"used when submitting jobs to run playbooks against network devices." -msgstr "" -"Authentification pour l’accès aux périphériques réseau. Il peut s’agir de " -"clés SSH, de noms d’utilisateur, de mots de passe et d’informations " -"d’autorisation. Les informations d’identification réseau sont utilisées au " -"cours de l’envoi de tâches afin d’exécuter des playbooks sur des " -"périphériques réseau." - -#: client/src/credentials/credentials.form.js:68 -msgid "" -"Authentication for remote machine access. This can include SSH keys, " -"usernames, passwords, and sudo information. Machine credentials are used " -"when submitting jobs to run playbooks against remote hosts." -msgstr "" -"Authentification pour l’accès aux machines distantes. Il peut s’agir de clés" -" SSH, de noms d’utilisateur, de mots de passe et d’informations sudo. Les " -"informations d’identification de machine sont utilisées au cours de l’envoi " -"de tâches afin d’exécuter des playbooks sur des hôtes distants." - -#: client/src/credentials/credentials.form.js:343 -msgid "Authorize" -msgstr "Autoriser" - -#: client/src/credentials/credentials.form.js:351 -msgid "Authorize Password" -msgstr "Mot de passe d’autorisation" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:172 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "Availability Zone:" -msgstr "Zone de disponibilité :" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:106 -msgid "Azure AD" -msgstr "Azure AD" - -#: client/src/shared/directives.js:75 -msgid "BROWSE" -msgstr "NAVIGUER" - -#: client/src/projects/projects.form.js:80 -msgid "" -"Base path used for locating playbooks. Directories found inside this path " -"will be listed in the playbook directory drop-down. Together the base path " -"and selected playbook directory provide the full path used to locate " -"playbooks." -msgstr "" -"Chemin de base utilisé pour localiser les playbooks. Les répertoires " -"localisés dans ce chemin sont répertoriés dans la liste déroulante des " -"répertoires de playbooks. Le chemin de base et le répertoire de playbook " -"sélectionnés fournissent ensemble le chemin complet servant à localiser les " -"playbooks." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:128 -msgid "Become Privilege Escalation" -msgstr "Activer l’élévation des privilèges" - -#: client/src/license/license.partial.html:107 -msgid "Browse" -msgstr "Parcourir" - -#: client/lib/services/base-string.service.js:61 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:28 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:73 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:16 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:16 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:16 -#: client/src/job-submission/job-submission.partial.html:370 -#: client/src/partials/survey-maker-modal.html:17 -#: client/src/partials/survey-maker-modal.html:85 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:17 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:65 -msgid "CANCEL" -msgstr "ANNULER" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 -msgid "CHANGES" -msgstr "MODIFICATIONS" - -#: client/src/shared/smart-search/smart-search.partial.html:30 -msgid "CLEAR ALL" -msgstr "TOUT EFFACER" - -#: client/src/partials/survey-maker-modal.html:86 -msgid "CLOSE" -msgstr "FERMER" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:19 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js:19 -#: client/src/templates/completed-jobs.list.js:20 -msgid "COMPLETED JOBS" -msgstr "JOBS TERMINÉS" - -#: client/src/configuration/configuration.partial.html:10 -msgid "CONFIGURE {{BRAND_NAME}}" -msgstr "CONFIGURER {{BRAND_NAME}}" - -#: client/src/shared/stateDefinitions.factory.js:157 -msgid "CREATE %s" -msgstr "CRÉER %s" - -#: client/features/credentials/credentials.strings.js:8 -#: client/src/credentials/credentials.form.js:16 -msgid "CREATE CREDENTIAL" -msgstr "CRÉER IDENTIFIANTS" - -#: client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:16 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:16 -msgid "CREATE GROUP" -msgstr "CRÉER UN GROUPE" - -#: client/src/inventories-hosts/hosts/host.form.js:17 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:17 -#: client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:17 -msgid "CREATE HOST" -msgstr "CRÉER HOTE" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js:8 -msgid "CREATE INVENTORY SOURCE" -msgstr "CRÉER UNE SOURCE D'INVENTAIRE" - -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js:8 -#: client/src/scheduler/main.js:113 client/src/scheduler/main.js:206 -#: client/src/scheduler/main.js:290 -msgid "CREATE SCHEDULE" -msgstr "CRÉER UNE PROGRAMMATION" - -#: client/src/management-jobs/scheduler/main.js:81 -msgid "CREATE SCHEDULED JOB" -msgstr "CRÉER UNE TÂCHE PROGRAMMÉE" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:32 -msgid "CREATE SOURCE" -msgstr "CRÉER UNE SOURCE" - -#: client/src/job-submission/job-submission.partial.html:351 -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:93 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:82 -msgid "CREDENTIAL" -msgstr "INFORMATIONS D’IDENTIFICATION" - -#: client/src/credential-types/credential-types.form.js:21 -msgid "CREDENTIAL TYPE" -msgstr "TYPE D'INFORMATIONS D'IDENTIFICATION" - -#: client/src/job-submission/job-submission.partial.html:92 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:56 -msgid "CREDENTIAL TYPE:" -msgstr "TYPE D'INFORMATIONS D'IDENTIFICATION :" - -#: client/src/activity-stream/get-target-title.factory.js:11 -#: client/src/credential-types/credential-types.list.js:12 -#: client/src/credential-types/main.js:45 -msgid "CREDENTIAL TYPES" -msgstr "TYPES D'INFORMATIONS D'IDENTIFICATION" - -#: client/features/credentials/legacy.credentials.js:14 -#: client/src/activity-stream/get-target-title.factory.js:17 -#: client/src/credentials/credentials.list.js:15 -#: client/src/credentials/credentials.list.js:16 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:5 -msgid "CREDENTIALS" -msgstr "INFORMATIONS D’IDENTIFICATION" - -#: client/features/credentials/credentials.strings.js:28 -msgid "CREDENTIALS PERMISSIONS" -msgstr "PERMISSIONS LIÉES AUX INFORMATIONS D'IDENTIFICATION" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:390 -#: client/src/projects/projects.form.js:199 -msgid "Cache Timeout" -msgstr "Expiration du délai d’attente du cache" - -#: client/src/projects/projects.form.js:188 -msgid "Cache Timeout%s (seconds)%s" -msgstr "Expiration du délai d’attente du cache%s (secondes)%s" - -#: client/src/projects/list/projects-list.controller.js:199 -#: client/src/users/list/users-list.controller.js:83 -msgid "Call to %s failed. DELETE returned status:" -msgstr "Échec de l’appel de %s. État DELETE renvoyé :" - -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:263 -msgid "Call to %s failed. GET status:" -msgstr "Échec de l’appel de %s. État GET :" - -#: client/src/projects/edit/projects-edit.controller.js:238 -msgid "Call to %s failed. POST returned status:" -msgstr "Échec de l’appel de %s. État POST renvoyé :" - -#: client/src/projects/list/projects-list.controller.js:225 -msgid "Call to %s failed. POST status:" -msgstr "Échec de l’appel de %s. État POST :" - -#: client/src/management-jobs/card/card.controller.js:29 -msgid "Call to %s failed. Return status: %d" -msgstr "Échec de l’appel de %s. État du renvoie : %d" - -#: client/src/projects/list/projects-list.controller.js:272 -msgid "Call to get project failed. GET status:" -msgstr "Échec de l’appel du projet en GET. État GET :" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:105 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:188 -#: client/src/configuration/configuration.controller.js:541 -#: client/src/job-results/job-results.partial.html:42 -#: client/src/jobs/factories/delete-job.factory.js:33 -#: client/src/shared/form-generator.js:1699 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:12 -#: client/src/workflow-results/workflow-results.partial.html:42 -msgid "Cancel" -msgstr "Annuler" - -#: client/src/job-results/job-results.service.js:142 -msgid "Cancel Job" -msgstr "Annuler la tâche" - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "Cancel Not Allowed" -msgstr "Annulation non autorisée" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:93 -msgid "Cancel sync process" -msgstr "Annuler le processus de synchronisation" - -#: client/src/projects/projects.list.js:124 -msgid "Cancel the SCM update" -msgstr "Annuler la mise à jour SCM" - -#: client/src/jobs/all-jobs.list.js:106 -msgid "Cancel the job" -msgstr "Annulation de la tâche" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:30 -#: client/src/projects/list/projects-list.controller.js:79 -msgid "Canceled. Click for details" -msgstr "Annulé. Cliquez pour connaître les détails." - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:91 -msgid "Cannot search running job" -msgstr "Impossible de rechercher les tâches en cours" - -#: client/src/instance-groups/instance-groups.list.js:22 -#: client/src/instance-groups/instances/instances.list.js:20 -msgid "Capacity" -msgstr "Capacité" - -#: client/src/projects/projects.form.js:82 -msgid "Change %s under \"Configure {{BRAND_NAME}}\" to change this location." -msgstr "Modifiez %s sous \"Configure {{BRAND_NAME}}\" pour changer d'emplacement." - -#: client/src/activity-stream/activity-detail.form.js:41 -msgid "Changes" -msgstr "Modifications" - -#: client/src/shared/form-generator.js:1071 -msgid "Choose a %s" -msgstr "Choisir un %s" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:64 -msgid "Choose an answer type" -msgstr "Choisissez un type de réponse" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:67 -msgid "" -"Choose an answer type or format you want as the prompt for the user. Refer " -"to the Ansible Tower Documentation for more additional information about " -"each option." -msgstr "" -"Spécifiez le type de format ou de type de réponse que vous souhaitez pour " -"interroger l'utilisateur. Consultez la documentation d’Ansible Tower pour en" -" savoir plus sur chaque option." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:112 -msgid "Choose an inventory file" -msgstr "Sélectionner un fichier d'inventaire" - -#: client/src/shared/directives.js:76 -msgid "Choose file" -msgstr "Choisir un fichier" - -#: client/src/license/license.partial.html:97 -msgid "" -"Choose your license file, agree to the End User License Agreement, and click" -" submit." -msgstr "" -"Choisissez votre fichier de licence, acceptez le Contrat de licence de " -"l’utilisateur final et validez." - -#: client/src/projects/projects.form.js:156 -msgid "Clean" -msgstr "Nettoyer" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:299 -msgid "Clear" -msgstr "Effacer" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:64 -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Click for details" -msgstr "Cliquez pour obtenir plus d’informations" - -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:63 -msgid "Click here to open the workflow graph editor." -msgstr "Cliquez ici pour ouvrir l'éditeur de graphique du flux de travail." - -#: client/src/inventories-hosts/inventories/inventory.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new inventory." -msgstr "" -"Cliquez sur une ligne pour la sélectionner, puis sur Terminé lorsque vous " -"avez fini. Cliquez sur le bouton %s pour créer un inventaire." - -#: client/src/teams/teams.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new team." -msgstr "" -"Cliquez sur une ligne pour la sélectionner, puis sur Terminé lorsque vous " -"avez fini. Cliquez sur le bouton %s pour créer une équipe." - -#: client/src/templates/templates.list.js:17 -msgid "" -"Click on a row to select it, and click Finished when done. Use the %s button" -" to create a new job template." -msgstr "" -"Cliquez sur une ligne pour la sélectionner, puis sur Terminé lorsque vous " -"avez fini. Cliquez sur le bouton %s pour créer un modèle de tâche." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:138 -msgid "" -"Click on the regions field to see a list of regions for your cloud provider." -" You can select multiple regions, or choose" -msgstr "" -"Cliquez sur le champ régions pour voir la liste des régions associées à " -"votre fournisseur cloud. Vous pouvez choisir plusieurs régions ou l'option" - -#: client/src/credentials/credentials.form.js:321 -msgid "Client ID" -msgstr "ID du client" - -#: client/src/notifications/notificationTemplates.form.js:254 -msgid "Client Identifier" -msgstr "Identifiant client" - -#: client/src/credentials/credentials.form.js:330 -msgid "Client Secret" -msgstr "Question secrète du client" - -#: client/src/shared/form-generator.js:1703 -msgid "Close" -msgstr "Fermer" - -#: client/src/job-results/job-results.partial.html:291 -msgid "Cloud Credential" -msgstr "Informations d’identification cloud" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:26 -msgid "Cloud source not configured." -msgstr "Source cloud non configurée." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "Cloud source not configured. Click" -msgstr "Source cloud non configurée. Cliquez sur" - -#: client/src/credentials/factories/become-method-change.factory.js:80 -#: client/src/credentials/factories/kind-change.factory.js:137 -msgid "CloudForms URL" -msgstr "URL CloudForms" - -#: client/src/job-results/job-results.controller.js:226 -#: client/src/standard-out/standard-out.controller.js:243 -#: client/src/workflow-results/workflow-results.controller.js:118 -msgid "Collapse Output" -msgstr "Tout réduire" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:13 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:21 -msgid "Completed Jobs" -msgstr "Tâches terminées" - -#: client/src/management-jobs/card/card.partial.html:34 -msgid "Configure Notifications" -msgstr "Configurer les notifications" - -#: client/src/setup-menu/setup-menu.partial.html:60 -msgid "Configure {{BRAND_NAME}}" -msgstr "Configurer {{BRAND_NAME}}" - -#: client/src/users/users.form.js:81 -msgid "Confirm Password" -msgstr "Confirmer le mot de passe" - -#: client/src/configuration/configuration.controller.js:548 -msgid "Confirm Reset" -msgstr "Confirmer la réinitialisation" - -#: client/src/configuration/configuration.controller.js:557 -msgid "Confirm factory reset" -msgstr "Confirmer la réinitialisation usine" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:120 -msgid "" -"Confirm that you want to permanently delete the inventory source below from " -"the inventory. Deleting this inventory source also deletes its associated " -"groups and hosts." -msgstr "" -"Voulez-vous vraiment supprimer définitivement la source de l'inventaire ci-" -"dessous ? Supprimer cette source d'inventaire supprimera aussi tous ses " -"groupes et hôtes associés." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "Confirm the removal of the" -msgstr "Confirmer la suppression du" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:134 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:149 -msgid "" -"Consult the Ansible documentation for further details on the usage of tags." -msgstr "" -"Consultez la documentation d’Ansible pour en savoir plus sur l’utilisation " -"des balises." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:18 -msgid "Contains 0 hosts." -msgstr "Contient 0 hôtes." - -#: client/src/templates/job_templates/job-template.form.js:180 -msgid "" -"Control the level of output ansible will produce as the playbook executes." -msgstr "" -"Contrôlez le niveau de sortie qu’Ansible génère lors de l’exécution du " -"playbook." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:313 -msgid "" -"Control the level of output ansible will produce for inventory source update" -" jobs." -msgstr "" -"Contrôlez le niveau de sortie produit par Ansible pour les tâches " -"d'actualisation de source d'inventaire." - -#: client/lib/components/components.strings.js:48 -msgid "Copied to clipboard." -msgstr "Copié dans le Presse-papiers." - -#: client/src/templates/templates.list.js:95 -msgid "Copy" -msgstr "Copier" - -#: client/lib/components/components.strings.js:47 -msgid "Copy full revision to clipboard." -msgstr "Copier la révision complète dans le Presse-papiers." - -#: client/src/templates/templates.list.js:98 -msgid "Copy template" -msgstr "Copier le modèle" - -#: client/src/about/about.partial.html:27 -msgid "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Visit Ansible.com for more information.
" -msgstr "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Consulter Ansible.com pour plus d'informations.
" - -#: client/src/users/users.list.js:44 -msgid "Create New" -msgstr "Créer" - -#: client/src/credentials/credentials.list.js:52 -msgid "Create a new credential" -msgstr "Créer de nouvelles informations d’identification" - -#: client/src/credential-types/credential-types.list.js:42 -msgid "Create a new credential type" -msgstr "Créer un nouveau type d'informations d'identification." - -#: client/src/inventory-scripts/inventory-scripts.list.js:40 -msgid "Create a new custom inventory" -msgstr "Créer un inventaire personnalisé" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:69 -msgid "Create a new group" -msgstr "Créer un groupe" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:123 -msgid "Create a new host" -msgstr "Créer un hôte" - -#: client/src/inventories-hosts/inventories/inventory.list.js:75 -msgid "Create a new inventory" -msgstr "Créer un inventaire" - -#: client/src/notifications/notificationTemplates.list.js:52 -msgid "Create a new notification template" -msgstr "Créer un modèle de notification" - -#: client/src/organizations/list/organizations-list.partial.html:21 -msgid "Create a new organization" -msgstr "Créer une organisation" - -#: client/src/projects/projects.list.js:76 -msgid "Create a new project" -msgstr "Créer un projet" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:68 -msgid "Create a new source" -msgstr "Créer une source" - -#: client/src/teams/teams.list.js:43 -msgid "Create a new team" -msgstr "Créer une équipe" - -#: client/src/templates/templates.list.js:56 -msgid "Create a new template" -msgstr "Créer un modèle" - -#: client/src/users/users.list.js:48 -msgid "Create a new user" -msgstr "Créer un utilisateur" - -#: client/src/setup-menu/setup-menu.partial.html:42 -msgid "Create and edit scripts to dynamically load hosts from any source." -msgstr "" -"Créez et modifiez des scripts pour charger dynamiquement des hôtes à partir " -"de n’importe quelle source." - -#: client/src/setup-menu/setup-menu.partial.html:30 -msgid "" -"Create custom credential types to be used for authenticating to network " -"hosts and cloud sources" -msgstr "" -"Créez les types d'informations d'identification à utiliser pour " -"l'authentification aux hôtes réseaux et aux sources cloud" - -#: client/src/setup-menu/setup-menu.partial.html:49 -msgid "" -"Create templates for sending notifications with Email, HipChat, Slack, and " -"SMS." -msgstr "" -"Créer des modèles pour envoyer des notifications via email, HipChat, Slack, " -"et SMS." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:72 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:74 -#: client/src/job-submission/job-submission.partial.html:18 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:67 -#: client/src/templates/job_templates/job-template.form.js:121 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:53 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:62 -msgid "Credential" -msgstr "Information d’identification" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:32 -#: client/src/setup-menu/setup-menu.partial.html:29 -msgid "Credential Types" -msgstr "Types d'informations d'identification" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:129 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:58 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 -#: client/src/setup-menu/setup-menu.partial.html:22 -#: client/src/templates/job_templates/job-template.form.js:134 -msgid "Credentials" -msgstr "Informations d’identification" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:17 -msgid "Critical" -msgstr "Critique" - -#: client/src/shared/directives.js:77 -msgid "Current Image:" -msgstr "Image actuelle :" - -#: client/src/job-results/job-results.controller.js:271 -msgid "Currently following standard out as it comes in. Click to unfollow." -msgstr "" -"Suit le standard à mesure qu'il vient. Cliquez pour annuler l'abonnement." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:171 -msgid "Custom Inventory Script" -msgstr "Script d'inventaire personnalisé" - -#: client/src/inventory-scripts/inventory-scripts.form.js:50 -#: client/src/inventory-scripts/inventory-scripts.form.js:60 -msgid "Custom Script" -msgstr "Script personnalisé" - -#: client/src/home/home.route.js:21 -msgid "DASHBOARD" -msgstr "TABLEAU DE BORD" - -#: client/src/credentials/list/credentials-list.controller.js:135 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:103 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:52 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:74 -#: client/src/job-results/job-results.service.js:119 -#: client/src/jobs/factories/delete-job.factory.js:115 -#: client/src/notifications/notification-templates-list/list.controller.js:195 -#: client/src/organizations/list/organizations-list.controller.js:174 -#: client/src/partials/survey-maker-modal.html:18 -#: client/src/projects/edit/projects-edit.controller.js:246 -#: client/src/templates/list/templates-list.controller.js:154 -#: client/src/users/list/users-list.controller.js:92 -msgid "DELETE" -msgstr "SUPPRIMER" - -#: client/src/partials/survey-maker-modal.html:84 -msgid "DELETE SURVEY" -msgstr "SUPPRIMER QUESTIONNAIRE" - -#: client/src/job-results/job-results.partial.html:16 -msgid "DETAILS" -msgstr "DÉTAILS" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:31 -msgid "DISASSOCIATE" -msgstr "DISSOCIER" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:5 -msgid "DYNAMIC HOSTS" -msgstr "HÔTES DYNAMIQUES" - -#: client/src/credential-types/credential-types.list.js:73 -#: client/src/credentials/credentials.list.js:85 -#: client/src/credentials/list/credentials-list.controller.js:132 -#: client/src/inventories-hosts/inventories/inventory.list.js:111 -#: client/src/inventory-scripts/inventory-scripts.list.js:71 -#: client/src/job-results/job-results.partial.html:54 -#: client/src/jobs/factories/delete-job.factory.js:37 -#: client/src/notifications/notification-templates-list/list.controller.js:192 -#: client/src/notifications/notificationTemplates.list.js:91 -#: client/src/organizations/list/organizations-list.controller.js:171 -#: client/src/projects/edit/projects-edit.controller.js:243 -#: client/src/projects/list/projects-list.controller.js:207 -#: client/src/scheduler/schedules.list.js:90 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:13 -#: client/src/teams/teams.list.js:72 -#: client/src/templates/list/templates-list.controller.js:102 -#: client/src/templates/templates.list.js:120 -#: client/src/users/list/users-list.controller.js:89 -#: client/src/users/users.list.js:79 -#: client/src/workflow-results/workflow-results.partial.html:54 -msgid "Delete" -msgstr "Supprimer" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:6 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:6 -msgid "Delete Group" -msgstr "Supprimer le groupe" - -#: client/src/job-results/job-results.service.js:93 -msgid "Delete Job" -msgstr "Supprimer Tâche" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:175 -msgid "Delete Source" -msgstr "Supprimer la source" - -#: client/src/credentials/credentials.list.js:87 -msgid "Delete credential" -msgstr "Supprimer les informations d’identification" - -#: client/src/credential-types/credential-types.list.js:75 -msgid "Delete credential type" -msgstr "Supprimer le type d'informations d’identification" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:101 -#: client/src/inventories-hosts/inventory-hosts.strings.js:19 -msgid "Delete group" -msgid_plural "Delete groups" -msgstr[0] "Supprimer le groupe" -msgstr[1] "Supprimer les groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:48 -msgid "Delete groups" -msgstr "Supprimer les groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:37 -msgid "Delete groups and hosts" -msgstr "Supprimer les groupes et les hôtes" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:100 -#: client/src/inventories-hosts/inventory-hosts.strings.js:21 -msgid "Delete host" -msgid_plural "Delete hosts" -msgstr[0] "Supprimer l'hôte" -msgstr[1] "Supprimer les hôtes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:59 -msgid "Delete hosts" -msgstr "Supprimer les hôtes" - -#: client/src/inventories-hosts/inventories/inventory.list.js:113 -msgid "Delete inventory" -msgstr "Supprimer l’inventaire" - -#: client/src/inventory-scripts/inventory-scripts.list.js:73 -msgid "Delete inventory script" -msgstr "Supprimer le script d’inventaire" - -#: client/src/notifications/notificationTemplates.list.js:93 -msgid "Delete notification" -msgstr "Supprimer la notification" - -#: client/src/projects/projects.form.js:166 -msgid "Delete on Update" -msgstr "Supprimer lors de la mise à jour" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:27 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:27 -msgid "Delete or promote the group's children?" -msgstr "Supprimer ou promouvoir les enfants du groupe ?" - -#: client/src/scheduler/schedules.list.js:93 -msgid "Delete schedule" -msgstr "Supprimer la programmation" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:125 -msgid "Delete source" -msgstr "Supprimer la source" - -#: client/src/teams/teams.list.js:76 -msgid "Delete team" -msgstr "Supprimer l’équipe" - -#: client/src/templates/templates.list.js:123 -msgid "Delete template" -msgstr "Supprimer le modèle" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:84 -#: client/src/jobs/all-jobs.list.js:113 -#: client/src/templates/completed-jobs.list.js:85 -msgid "Delete the job" -msgstr "Supprimer la tâche" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Delete the local repository in its entirety prior to performing an update." -msgstr "" -"Supprimer le référentiel local dans son intégralité avant de lancer la mise " -"à jour." - -#: client/src/projects/projects.list.js:118 -msgid "Delete the project" -msgstr "Supprimer le projet" - -#: client/src/scheduler/scheduled-jobs.list.js:81 -msgid "Delete the schedule" -msgstr "Supprimer la planification" - -#: client/src/users/users.list.js:83 -msgid "Delete user" -msgstr "Supprimer l’utilisateur" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:14 -msgid "Delete {{ group }} and {{ host }}" -msgstr "Supprimer {{ group }} et {{ host }}" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:23 -msgid "Deleting group" -msgstr "Suppression du groupe" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Depending on the size of the repository this may significantly increase the " -"amount of time required to complete an update." -msgstr "" -"Selon la taille du référentiel, cette opération risque d’augmenter " -"considérablement le délai d’exécution de la mise à jour." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "Describe Instances documentation" -msgstr "Décrire la documentation des instances" - -#: client/src/credential-types/credential-types.form.js:34 -#: client/src/credentials/credentials.form.js:39 -#: client/src/inventories-hosts/hosts/host.form.js:63 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:39 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:62 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:62 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:58 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:46 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:53 -#: client/src/inventory-scripts/inventory-scripts.form.js:35 -#: client/src/notifications/notificationTemplates.form.js:39 -#: client/src/organizations/organizations.form.js:33 -#: client/src/projects/projects.form.js:36 client/src/teams/teams.form.js:32 -#: client/src/templates/job_templates/job-template.form.js:41 -#: client/src/templates/survey-maker/shared/question-definition.form.js:36 -#: client/src/templates/workflows.form.js:39 -#: client/src/users/users.form.js:145 client/src/users/users.form.js:171 -msgid "Description" -msgstr "Description" - -#: client/src/notifications/notificationTemplates.form.js:136 -#: client/src/notifications/notificationTemplates.form.js:140 -#: client/src/notifications/notificationTemplates.form.js:152 -#: client/src/notifications/notificationTemplates.form.js:156 -msgid "Destination Channels" -msgstr "Canaux de destination" - -#: client/src/notifications/notificationTemplates.form.js:359 -#: client/src/notifications/notificationTemplates.form.js:363 -msgid "Destination Channels or Users" -msgstr "Canaux de destination pour les utilisateurs" - -#: client/src/notifications/notificationTemplates.form.js:205 -#: client/src/notifications/notificationTemplates.form.js:206 -msgid "Destination SMS Number" -msgstr "Numéro SMS de destination" - -#: client/features/credentials/credentials.strings.js:13 -#: client/src/license/license.partial.html:5 -#: client/src/shared/form-generator.js:1481 -msgid "Details" -msgstr "Détails" - -#: client/src/job-submission/job-submission.partial.html:263 -msgid "Diff Mode" -msgstr "Mode diff" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Group From Group" -msgstr "Dissocier Groupe du Groupe" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:6 -msgid "Disassociate Host" -msgstr "Dissocier l'hôte" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:6 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Host From Group" -msgstr "Dissocier Hôte du Groupe" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:65 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:110 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:98 -msgid "Disassociate group" -msgstr "Dissocier le groupe" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:87 -msgid "Disassociate host" -msgstr "Dissocier l'hôte" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:75 -#: client/src/configuration/configuration.controller.js:202 -#: client/src/configuration/configuration.controller.js:264 -#: client/src/configuration/system-form/configuration-system.controller.js:57 -msgid "Discard changes" -msgstr "Ignorer les modifications" - -#: client/src/teams/teams.form.js:146 -msgid "Dissasociate permission from team" -msgstr "Dissocier la permission de l’équipe" - -#: client/src/users/users.form.js:225 -msgid "Dissasociate permission from user" -msgstr "Dissocier la permission de l’utilisateur" - -#: client/src/credentials/credentials.form.js:384 -#: client/src/credentials/factories/become-method-change.factory.js:54 -#: client/src/credentials/factories/kind-change.factory.js:111 -msgid "Domain Name" -msgstr "Nom de domaine" - -#: client/src/job-results/job-results.controller.js:15 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:134 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:141 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:102 -msgid "Download Output" -msgstr "Télécharger la sortie" - -#: client/src/inventory-scripts/inventory-scripts.form.js:59 -msgid "" -"Drag and drop your custom inventory script file here or create one in the " -"field to import your custom inventory. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Faites glisser votre script d’inventaire personnalisé et déposez-le ici ou " -"créez-en un dans le champ pour importer votre inventaire personnalisé. Voir " -"la documentation Ansible Tower pour obtenir des exemples de syntaxe." - -#: client/src/partials/survey-maker-modal.html:77 -msgid "Drop question here to reorder" -msgstr "Mettez la question ici pour réordonnancer" - -#: client/src/configuration/configuration.route.js:30 -msgid "EDIT CONFIGURATION" -msgstr "MODIFIER CONFIGURATION" - -#: client/features/credentials/credentials.strings.js:9 -msgid "EDIT CREDENTIAL" -msgstr "MODIFIER LES INFORMATIONS D'IDENTIFICATION" - -#: client/src/management-jobs/scheduler/main.js:95 -msgid "EDIT SCHEDULED JOB" -msgstr "MODIFIER UNE TÂCHE PROGRAMMÉE" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:17 -msgid "EDIT SURVEY PROMPT" -msgstr "MODIFIER L'INVITE DU QUESTIONNAIRE" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:46 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:79 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:59 -msgid "ELAPSED" -msgstr "TEMPS ÉCOULÉ" - -#: client/lib/components/components.strings.js:9 -msgid "ENCRYPTED" -msgstr "CHIFFRÉ" - -#: client/src/shared/smart-search/smart-search.partial.html:39 -msgid "EXAMPLES:" -msgstr "EXEMPLES :" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:15 -msgid "EXECUTE COMMAND" -msgstr "EXÉCUTER LA COMMANDE" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:46 -msgid "EXPLANATION" -msgstr "EXPLICATION" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:355 -msgid "" -"Each time a job runs using this inventory, refresh the inventory from the " -"selected source before executing job tasks." -msgstr "" -"Chaque fois qu’une tâche s’exécute avec cet inventaire, réalisez une mise à " -"jour de la source sélectionnée avant de lancer la tâche." - -#: client/src/projects/projects.form.js:179 -msgid "" -"Each time a job runs using this project, perform an update to the local " -"repository prior to starting the job." -msgstr "" -"Chaque fois qu’une tâche s’exécute avec ce projet, réalisez une mise à jour " -"dans le référentiel local avant de lancer la tâche." - -#: client/src/credential-types/credential-types.list.js:56 -#: client/src/credentials/credentials.list.js:66 -#: client/src/inventories-hosts/inventories/inventory.list.js:97 -#: client/src/inventory-scripts/inventory-scripts.list.js:54 -#: client/src/notifications/notificationTemplates.list.js:65 -#: client/src/notifications/notificationTemplates.list.js:74 -#: client/src/scheduler/schedules.list.js:75 client/src/teams/teams.list.js:55 -#: client/src/templates/templates.list.js:103 -#: client/src/users/users.list.js:60 -msgid "Edit" -msgstr "Modifier" - -#: client/src/shared/form-generator.js:1715 -#: client/src/templates/job_templates/job-template.form.js:452 -#: client/src/templates/workflows.form.js:177 -msgid "Edit Survey" -msgstr "Modifier le questionnaire" - -#: client/src/credential-types/credential-types.list.js:58 -msgid "Edit credenital type" -msgstr "Modifier le type d'information d'identification" - -#: client/src/credentials/credentials.list.js:68 -msgid "Edit credential" -msgstr "Modifier les informations d’identification" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:85 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:96 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:84 -msgid "Edit group" -msgstr "Modifier le groupe" - -#: client/src/inventories-hosts/hosts/host.list.js:83 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:73 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:87 -msgid "Edit host" -msgstr "Modifier l’hôte" - -#: client/src/inventories-hosts/inventories/inventory.list.js:99 -msgid "Edit inventory" -msgstr "Modifier l’inventaire" - -#: client/src/inventory-scripts/inventory-scripts.list.js:56 -msgid "Edit inventory script" -msgstr "Modifier le script d’inventaire" - -#: client/src/notifications/notificationTemplates.list.js:76 -msgid "Edit notification" -msgstr "Modifier la notification" - -#: client/src/scheduler/schedules.list.js:78 -msgid "Edit schedule" -msgstr "Modifier la programmation" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:111 -msgid "Edit source" -msgstr "Modifier la source" - -#: client/src/teams/teams.list.js:59 -msgid "Edit team" -msgstr "Modifier l’équipe" - -#: client/src/templates/templates.list.js:105 -msgid "Edit template" -msgstr "Modifier le modèle" - -#: client/src/job-results/job-results.partial.html:191 -msgid "Edit the Schedule" -msgstr "Modifier la planification" - -#: client/src/job-results/job-results.partial.html:175 -#: client/src/workflow-results/workflow-results.partial.html:124 -msgid "Edit the User" -msgstr "Modifier l’Utilisateur" - -#: client/src/job-results/job-results.partial.html:265 -#: client/src/job-results/job-results.partial.html:280 -#: client/src/job-results/job-results.partial.html:296 -#: client/src/job-results/job-results.partial.html:311 -#: client/src/job-results/job-results.partial.html:326 -msgid "Edit the credential" -msgstr "Modifier l'information d’identification" - -#: client/src/job-results/job-results.partial.html:206 -msgid "Edit the inventory" -msgstr "Modifier l’inventaire" - -#: client/src/job-results/job-results.partial.html:140 -msgid "Edit the job template" -msgstr "Modifier le modèle de tâche" - -#: client/src/job-results/job-results.partial.html:229 -#: client/src/projects/projects.list.js:105 -msgid "Edit the project" -msgstr "Modifier le projet" - -#: client/src/scheduler/scheduled-jobs.list.js:67 -msgid "Edit the schedule" -msgstr "Modifier la planification" - -#: client/src/users/users.list.js:64 -msgid "Edit user" -msgstr "Modifier l’utilisateur" - -#: client/src/setup-menu/setup-menu.partial.html:61 -msgid "Edit {{BRAND_NAME}}'s configuration." -msgstr "Modifier la configuration de {{BRAND_NAME}}." - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "" -"Either you do not have access or the SCM update process completed. Click the" -" %sRefresh%s button to view the latest status." -msgstr "" -"Vous n’avez pas accès, ou la mise à jour SCM est terminée. Cliquez sur le " -"bouton %sActualiser%s pour voir l’état le plus récent." - -#: client/src/job-results/job-results.partial.html:520 -msgid "Elapsed" -msgstr "Temps écoulé" - -#: client/src/credentials/credentials.form.js:191 -#: client/src/users/users.form.js:51 -msgid "Email" -msgstr "Email" - -#: client/src/templates/job_templates/job-template.form.js:288 -#: client/src/templates/job_templates/job-template.form.js:293 -msgid "Enable Concurrent Jobs" -msgstr "Activer les tâches parallèles" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:123 -#: client/src/templates/job_templates/job-template.form.js:264 -#: client/src/templates/job_templates/job-template.form.js:269 -msgid "Enable Privilege Escalation" -msgstr "Activer l’élévation des privilèges" - -#: client/src/templates/job_templates/job-template.form.js:279 -msgid "" -"Enables creation of a provisioning callback URL. Using the URL a host can " -"contact {{BRAND_NAME}} and request a configuration update using this job " -"template." -msgstr "" -"Active la création d'une URL de rappel. Avec cette URL, un hôte peut " -"contacter {{BRAND_NAME}} et demander une mise à jour de la configuration à " -"l'aide de ce modèle de tâche." - -#: client/src/credentials/factories/credential-form-save.factory.js:73 -msgid "Encrypted credentials are not supported." -msgstr "" -"Les informations d’identification chiffrées ne sont pas prises en charge." - -#: client/src/license/license.partial.html:113 -msgid "End User License Agreement" -msgstr "Contrat de licence de l’utilisateur final" - -#: client/src/inventories-hosts/hosts/host.form.js:73 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:72 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:86 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two." -msgstr "" -"Entrez les variables d’inventaire avec la syntaxe JSON ou YAML. Utilisez le " -"bouton radio pour basculer entre les deux." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:93 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two. Refer to the Ansible Tower documentation " -"for example syntax." -msgstr "" -"Entrez les variables d’inventaire avec la syntaxe JSON ou YAML. Utilisez le " -"bouton radio pour basculer entre les deux. Consultez la documentation " -"d’Ansible Tower pour avoir un exemple de syntaxe." - -#: client/src/notifications/notificationTemplates.form.js:155 -msgid "" -"Enter one HipChat channel per line. The pound symbol (#) is not required." -msgstr "" -"Saisir un canal HipChat par ligne. Le symbole dièse (#) n’est pas " -"nécessaire." - -#: client/src/notifications/notificationTemplates.form.js:362 -msgid "" -"Enter one IRC channel or username per line. The pound symbol (#) for " -"channels, and the at (@) symbol for users, are not required." -msgstr "" -"Saisir un canal IRC ou un nom d'utilisateur par ligne. Le symbole dièse (#) " -"pour les canaux et (@) pour le utilisateurs, ne sont pas nécessaires." - -#: client/src/notifications/notificationTemplates.form.js:139 -msgid "" -"Enter one Slack channel per line. The pound symbol (#) is not required." -msgstr "" -"Saisir un canal Slack par ligne. Le symbole dièse (#) n’est pas nécessaire." - -#: client/src/notifications/notificationTemplates.form.js:97 -msgid "" -"Enter one email address per line to create a recipient list for this type of" -" notification." -msgstr "" -"Saisir une adresse email par ligne pour créer une liste des destinataires " -"pour ce type de notification." - -#: client/src/notifications/notificationTemplates.form.js:209 -msgid "" -"Enter one phone number per line to specify where to route SMS messages." -msgstr "" -"Saisir un numéro de téléphone par ligne pour spécifier où envoyer les " -"messages SMS." - -#: client/src/credentials/factories/become-method-change.factory.js:81 -#: client/src/credentials/factories/kind-change.factory.js:138 -msgid "" -"Enter the URL for the virtual machine which %scorresponds to your CloudForm " -"instance. %sFor example, %s" -msgstr "" -"Veuillez saisir l’URL de la machine virtuelle qui correspond à votre " -"instance de CloudForm. %sPar exemple, %s" - -#: client/src/credentials/factories/become-method-change.factory.js:71 -#: client/src/credentials/factories/kind-change.factory.js:128 -msgid "" -"Enter the URL which corresponds to your %sRed Hat Satellite 6 server. %sFor " -"example, %s" -msgstr "" -"Veuillez saisir l’URL qui correspond à votre serveur %sRed Hat Satellite 6. " -"%sPar exemple, %s" - -#: client/src/credentials/factories/become-method-change.factory.js:49 -#: client/src/credentials/factories/kind-change.factory.js:106 -msgid "" -"Enter the hostname or IP address which corresponds to your VMware vCenter." -msgstr "" -"Entrez le nom d’hôte ou l’adresse IP qui correspond à votre VMware vCenter." - -#: client/src/notifications/notificationTemplates.form.js:195 -msgid "" -"Enter the number associated with the \"Messaging Service\" in Twilio in the " -"format +18005550199." -msgstr "" -"Numéro associé au \"Service de messagerie\" de Twilio sous le format " -"+18005550199." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:197 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:221 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:245 -msgid "" -"Enter variables using either JSON or YAML syntax. Use the radio button to " -"toggle between the two." -msgstr "" -"Entrez les variables avec la syntaxe JSON ou YAML. Utilisez le bouton radio " -"pour basculer entre les deux." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:187 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:194 -msgid "Environment Variables" -msgstr "Variables d'environnement" - -#: client/src/configuration/configuration.controller.js:348 -#: client/src/configuration/configuration.controller.js:449 -#: client/src/configuration/configuration.controller.js:483 -#: client/src/configuration/configuration.controller.js:530 -#: client/src/configuration/system-form/configuration-system.controller.js:231 -#: client/src/credentials/factories/credential-form-save.factory.js:77 -#: client/src/credentials/factories/credential-form-save.factory.js:93 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:129 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:139 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:166 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:194 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:213 -#: client/src/management-jobs/card/card.controller.js:140 -#: client/src/management-jobs/card/card.controller.js:230 -#: client/src/management-jobs/card/card.controller.js:28 -#: client/src/projects/add/projects-add.controller.js:108 -#: client/src/projects/edit/projects-edit.controller.js:156 -#: client/src/projects/edit/projects-edit.controller.js:222 -#: client/src/projects/edit/projects-edit.controller.js:238 -#: client/src/projects/list/projects-list.controller.js:169 -#: client/src/projects/list/projects-list.controller.js:198 -#: client/src/projects/list/projects-list.controller.js:225 -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:262 -#: client/src/projects/list/projects-list.controller.js:271 -#: client/src/users/add/users-add.controller.js:99 -#: client/src/users/edit/users-edit.controller.js:180 -#: client/src/users/edit/users-edit.controller.js:80 -#: client/src/users/list/users-list.controller.js:82 -msgid "Error!" -msgstr "Erreur !" - -#: client/src/activity-stream/streams.list.js:40 -msgid "Event" -msgstr "Événement" - -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Event ID" -msgstr "ID d'événement" - -#: client/src/activity-stream/factories/build-description.factory.js:120 -msgid "Event summary not available" -msgstr "Récapitulatif de l’événement non disponible" - -#: client/src/projects/add/projects-add.controller.js:129 -#: client/src/projects/edit/projects-edit.controller.js:265 -msgid "Example URLs for GIT SCM include:" -msgstr "Exemples d’URL pour le SCM GIT :" - -#: client/src/projects/add/projects-add.controller.js:150 -#: client/src/projects/edit/projects-edit.controller.js:285 -msgid "Example URLs for Mercurial SCM include:" -msgstr "Exemples d’URL pour le SCM Mercurial :" - -#: client/src/projects/add/projects-add.controller.js:141 -#: client/src/projects/edit/projects-edit.controller.js:276 -msgid "Example URLs for Subversion SCM include:" -msgstr "Exemples d’URL pour le SCM Subversion :" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Example: ansible_facts.ansible_distribution:\"RedHat\"" -msgstr "Exemple : ansible_facts.ansible_distribution:\"RedHat\"" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:76 -msgid "Existing Group" -msgstr "Groupe existant" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:125 -msgid "Existing Host" -msgstr "Hôte existant" - -#: client/src/job-results/job-results.controller.js:18 -#: client/src/job-results/job-results.controller.js:228 -#: client/src/standard-out/standard-out.controller.js:24 -#: client/src/standard-out/standard-out.controller.js:245 -#: client/src/workflow-results/workflow-results.controller.js:120 -#: client/src/workflow-results/workflow-results.controller.js:76 -msgid "Expand Output" -msgstr "Tout agrandir" - -#: client/src/license/license.partial.html:39 -msgid "Expires On" -msgstr "Arrive à expiration le" - -#: client/src/job-results/job-results.partial.html:81 -msgid "Explanation" -msgstr "Explication" - -#: client/src/job-results/job-results.partial.html:275 -msgid "Extra Credentials" -msgstr "Informations d’identification supplémentaires" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:132 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:144 -#: client/src/job-results/job-results.partial.html:409 -#: client/src/job-submission/job-submission.partial.html:165 -#: client/src/partials/logviewer.html:8 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:105 -#: client/src/templates/job_templates/job-template.form.js:342 -#: client/src/templates/job_templates/job-template.form.js:349 -#: client/src/templates/workflows.form.js:74 -#: client/src/templates/workflows.form.js:81 -msgid "Extra Variables" -msgstr "Variables supplémentaires" - -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html:4 -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js:7 -msgid "FACTS" -msgstr "FAITS" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:64 -msgid "FAILED" -msgstr "ÉCHEC" - -#: client/src/shared/smart-search/smart-search.partial.html:45 -msgid "FIELDS:" -msgstr "CHAMPS :" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:39 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:72 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:52 -msgid "FINISHED" -msgstr "TERMINÉ" - -#: client/src/inventories-hosts/hosts/host.form.js:107 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:106 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:107 -msgid "Facts" -msgstr "Faits" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:80 -msgid "Failed" -msgstr "Échec" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:44 -msgid "Failed Hosts" -msgstr "Échec des hôtes" - -#: client/src/users/add/users-add.controller.js:99 -msgid "Failed to add new user. POST returned status:" -msgstr "L’ajout de l’utilisateur a échoué. État POST renvoyé :" - -#: client/src/credentials/factories/credential-form-save.factory.js:78 -msgid "Failed to create new Credential. POST status:" -msgstr "La création des informations d’identification a échoué. État POST :" - -#: client/src/projects/add/projects-add.controller.js:109 -msgid "Failed to create new project. POST returned status:" -msgstr "La création du projet a échoué. État POST renvoyé :" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:214 -msgid "Failed to retrieve job template extra variables." -msgstr "" -"N’a pas pu extraire les variables supplémentaires du modèle de la tâche." - -#: client/src/projects/edit/projects-edit.controller.js:157 -msgid "Failed to retrieve project: %s. GET status:" -msgstr "La récupération du projet a échoué : %s. État GET :" - -#: client/src/users/edit/users-edit.controller.js:181 -#: client/src/users/edit/users-edit.controller.js:81 -msgid "Failed to retrieve user: %s. GET status:" -msgstr "La récupération de l’utilisateur a échoué : %s. État GET :" - -#: client/src/configuration/configuration.controller.js:450 -msgid "Failed to save settings. Returned status:" -msgstr "L’enregistrement des paramètres a échoué. État renvoyé :" - -#: client/src/configuration/configuration.controller.js:484 -msgid "Failed to save toggle settings. Returned status:" -msgstr "" -"L’enregistrement des paramètres d’activation/désactivation a échoué. État " -"renvoyé :" - -#: client/src/credentials/factories/credential-form-save.factory.js:94 -msgid "Failed to update Credential. PUT status:" -msgstr "La mise à jour des informations d’identification a échoué. État PUT :" - -#: client/src/projects/edit/projects-edit.controller.js:222 -msgid "Failed to update project: %s. PUT status:" -msgstr "La mise à jour du projet a échoué : %s. État PUT :" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:195 -#: client/src/management-jobs/card/card.controller.js:141 -#: client/src/management-jobs/card/card.controller.js:231 -msgid "Failed updating job %s with variables. POST returned: %d" -msgstr "" -"N’a pas pu mettre à jour la tâche %s avec les variables. Retour POST : %d" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:24 -msgid "Failed. Click for details" -msgstr "Échec. Cliquer pour obtenir davantage d’informations" - -#: client/src/notifications/notifications.list.js:48 -msgid "Failure" -msgstr "Défaillance" - -#: client/src/scheduler/schedules.list.js:48 -msgid "Final Run" -msgstr "Dernière exécution" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:59 -#: client/src/instance-groups/jobs/jobs.list.js:57 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:54 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:58 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:44 -#: client/src/job-results/job-results.partial.html:111 -#: client/src/jobs/all-jobs.list.js:66 -#: client/src/portal-mode/portal-jobs.list.js:40 -#: client/src/templates/completed-jobs.list.js:59 -msgid "Finished" -msgstr "Terminé" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:21 -#: client/src/users/users.form.js:26 client/src/users/users.list.js:33 -msgid "First Name" -msgstr "Prénom" - -#: client/src/scheduler/schedules.list.js:38 -msgid "First Run" -msgstr "Première exécution" - -#: client/src/shared/smart-search/smart-search.partial.html:52 -msgid "" -"For additional information on advanced search search syntax please see the " -"Ansible Tower" -msgstr "" -"Pour obtenir des informations supplémentaires sur la syntaxe de recherche " -"avancée, consulter la documentation Ansible Tower." - -#: client/src/credentials/factories/become-method-change.factory.js:63 -#: client/src/credentials/factories/kind-change.factory.js:120 -msgid "For example, %s" -msgstr "Par exemple, %s" - -#: client/src/inventories-hosts/hosts/host.form.js:36 -#: client/src/inventories-hosts/hosts/host.list.js:36 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:35 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:32 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:35 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:31 -msgid "" -"For hosts that are part of an external inventory, this flag cannot be " -"changed. It will be set by the inventory sync process." -msgstr "" -"Pour les hôtes qui font partie d’un inventaire externe, ce marqueur ne peut " -"pas être modifié. Il sera défini par le processus de synchronisation des " -"inventaires." - -#: client/src/templates/job_templates/job-template.form.js:54 -msgid "" -"For job templates, select run to execute the playbook. Select check to only " -"check playbook syntax, test environment setup, and report problems without " -"executing the playbook." -msgstr "" -"Pour les modèles de tâches, sélectionner «run» (exécuter) pour exécuter le " -"playbook. Sélectionner «check» (vérifier) uniquement pour vérifier la " -"syntaxe du playbook, tester la configuration de l’environnement et signaler " -"les problèmes." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:118 -msgid "" -"For more information and examples see %sthe Patterns topic at " -"docs.ansible.com%s." -msgstr "" -"Pour obtenir plus d’informations et voir des exemples, reportez-vous à la " -"rubrique %sPatterns sur docs.ansible.com%s." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:109 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:96 -#: client/src/job-results/job-results.partial.html:336 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:87 -#: client/src/templates/job_templates/job-template.form.js:144 -#: client/src/templates/job_templates/job-template.form.js:154 -msgid "Forks" -msgstr "Forks" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:172 -msgid "Frequency Details" -msgstr "Informations sur la fréquence" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js:45 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js:46 -msgid "GROUPS" -msgstr "GROUPES" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:107 -msgid "GitHub" -msgstr "GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:108 -msgid "GitHub Org" -msgstr "GitHub Org" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:109 -msgid "GitHub Team" -msgstr "Équipe GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:110 -msgid "Google OAuth2" -msgstr "Google OAuth2" - -#: client/src/teams/teams.form.js:155 client/src/users/users.form.js:214 -msgid "Grant Permission" -msgstr "Donner Permission" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Gray" -msgstr "Gris" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Green" -msgstr "Vert" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:52 -msgid "Group Variables" -msgstr "Grouper des variables" - -#: client/src/setup-menu/setup-menu.partial.html:5 -msgid "" -"Group all of your content to manage permissions across departments in your " -"company." -msgstr "" -"Regroupez l’ensemble du contenu pour gérer les permissions entre les " -"différents services de votre entreprise." - -#: client/src/inventories-hosts/hosts/host.form.js:115 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:31 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:89 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:88 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:115 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:167 -msgid "Groups" -msgstr "Groupes" - -#: client/lib/components/components.strings.js:12 -msgid "HIDE" -msgstr "MASQUER" - -#: client/lib/components/components.strings.js:39 -msgid "HINT: Drag and drop an SSH private key file on the field below." -msgstr "" -"INDICE : glissez-déposez un fichier de clé privé SSH dans le champ ci-" -"dessous." - -#: client/src/activity-stream/get-target-title.factory.js:41 -#: client/src/inventories-hosts/hosts/hosts.partial.html:9 -#: client/src/inventories-hosts/hosts/main.js:80 -#: client/src/inventories-hosts/inventories/inventories.partial.html:14 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.route.js:18 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js:17 -msgid "HOSTS" -msgstr "HÔTES " - -#: client/src/notifications/notificationTemplates.form.js:320 -#: client/src/notifications/notificationTemplates.form.js:321 -msgid "HTTP Headers" -msgstr "En-têtes HTTP" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "Hide Activity Stream" -msgstr "Cacher le flux d’activité" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:23 -msgid "High" -msgstr "Élevée" - -#: client/src/credentials/credentials.form.js:139 -#: client/src/notifications/notificationTemplates.form.js:83 -msgid "Host" -msgstr "Hôte" - -#: client/src/credentials/factories/become-method-change.factory.js:52 -#: client/src/credentials/factories/kind-change.factory.js:109 -msgid "Host (Authentication URL)" -msgstr "Hôte (URL d’authentification)" - -#: client/src/templates/job_templates/job-template.form.js:324 -#: client/src/templates/job_templates/job-template.form.js:333 -msgid "Host Config Key" -msgstr "Clé de configuration de l’hôte" - -#: client/src/inventories-hosts/hosts/host.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:39 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:39 -msgid "Host Enabled" -msgstr "Hôte activé" - -#: client/src/inventories-hosts/hosts/host.form.js:46 -#: client/src/inventories-hosts/hosts/host.form.js:57 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:45 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:56 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:45 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:56 -msgid "Host Name" -msgstr "Nom d'hôte" - -#: client/src/inventories-hosts/hosts/host.form.js:80 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:79 -msgid "Host Variables" -msgstr "Variables d'hôte" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is available" -msgstr "Hôte disponible" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is available. Click to toggle." -msgstr "Hôte disponible. Cliquez pour activer ou désactiver." - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is not available" -msgstr "Hôte indisponible." - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is not available. Click to toggle." -msgstr "Hôte indisponible. Cliquez pour activer ou désactiver." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:39 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:98 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:57 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:56 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:167 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:176 -#: client/src/job-results/job-results.partial.html:504 -msgid "Hosts" -msgstr "Hôtes" - -#: client/src/license/license.partial.html:52 -msgid "Hosts Available" -msgstr "Hôtes disponibles" - -#: client/src/license/license.partial.html:64 -msgid "Hosts Remaining" -msgstr "Hôtes restants" - -#: client/src/license/license.partial.html:58 -msgid "Hosts Used" -msgstr "Hôtes utilisés" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "Hosts are imported to" -msgstr "Hôtes importés dans" - -#: client/src/license/license.partial.html:121 -msgid "I agree to the End User License Agreement" -msgstr "J’accepte le Contrat de licence de l’utilisateur final" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:27 -#: client/src/instance-groups/jobs/jobs.list.js:26 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:38 -msgid "ID" -msgstr "ID" - -#: client/src/partials/job-template-details.html:2 -msgid "INFO" -msgstr "INFO" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 -msgid "INITIATED BY" -msgstr "INITIÉ PAR" - -#: client/src/inventories-hosts/inventories/insights/insights.route.js:7 -msgid "INSIGHTS" -msgstr "INSIGHTS" - -#: client/src/instance-groups/instance-groups.list.js:6 -#: client/src/instance-groups/instance-groups.list.js:7 -#: client/src/instance-groups/instance-groups.route.js:10 -#: client/src/instance-groups/list/instance-groups-list.partial.html:3 -msgid "INSTANCE GROUPS" -msgstr "GROUPES D'INSTANCES" - -#: client/src/instance-groups/instance-group.partial.html:27 -msgid "INSTANCES" -msgstr "INSTANCES" - -#: client/src/activity-stream/get-target-title.factory.js:14 -#: client/src/inventories-hosts/hosts/hosts.partial.html:8 -#: client/src/inventories-hosts/inventories/inventories.partial.html:13 -#: client/src/inventories-hosts/inventories/inventories.route.js:8 -#: client/src/inventories-hosts/inventories/inventory.list.js:14 -#: client/src/inventories-hosts/inventories/inventory.list.js:15 -#: client/src/main-menu/main-menu.partial.html:104 -#: client/src/main-menu/main-menu.partial.html:27 -#: client/src/organizations/linkout/organizations-linkout.route.js:143 -#: client/src/organizations/list/organizations-list.controller.js:66 -msgid "INVENTORIES" -msgstr "INVENTAIRES" - -#: client/src/job-submission/job-submission.partial.html:346 -#: client/src/partials/job-template-details.html:2 -msgid "INVENTORY" -msgstr "INVENTAIRE" - -#: client/src/inventory-scripts/inventory-scripts.form.js:23 -msgid "INVENTORY SCRIPT" -msgstr "SCRIPT D’INVENTAIRE" - -#: client/src/activity-stream/get-target-title.factory.js:35 -#: client/src/inventory-scripts/inventory-scripts.list.js:12 -#: client/src/inventory-scripts/main.js:66 -msgid "INVENTORY SCRIPTS" -msgstr "SCRIPTS D’INVENTAIRE" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js:8 -msgid "INVENTORY SOURCES" -msgstr "SOURCES D'INVENTAIRE" - -#: client/src/notifications/notificationTemplates.form.js:348 -msgid "IRC Nick" -msgstr "Surnom IRC" - -#: client/src/notifications/notificationTemplates.form.js:337 -msgid "IRC Server Address" -msgstr "Adresse du serveur IRC" - -#: client/src/notifications/shared/type-change.service.js:58 -msgid "IRC Server Password" -msgstr "Mot de passe du serveur IRC" - -#: client/src/notifications/shared/type-change.service.js:57 -msgid "IRC Server Port" -msgstr "Port du serveur IRC" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:79 -msgid "ISSUE: {{report.rule.description}}" -msgstr "PROBLÈME : {{report.rule.description}}" - -#: client/src/shared/paginate/paginate.partial.html:43 -msgid "ITEMS" -msgstr "ÉLÉMENTS" - -#: client/src/login/authenticationServices/timer.factory.js:157 -msgid "Idle Session" -msgstr "Session inactive" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "If blank, all groups above are created except" -msgstr "" -"Si resté vide, cela indique que tous les groupes ci-dessus sont créés sauf" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:343 -msgid "" -"If checked, all variables for child groups and hosts will be removed and " -"replaced by those found on the external source." -msgstr "" -"Si cochées, toutes les variables des groupes et hôtes dépendants seront " -"supprimées et remplacées par celles qui se trouvent dans la source externe." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:331 -msgid "" -"If checked, any hosts and groups that were previously present on the " -"external source but are now removed will be removed from the Tower " -"inventory. Hosts and groups that were not managed by the inventory source " -"will be promoted to the next manually created group or if there is no " -"manually created group to promote them into, they will be left in the " -"\"all\" default group for the inventory." -msgstr "" -"Si cochés, tous les hôtes et groupes qui étaient présent auparavant sur la " -"source externe, mais qui sont maintenant supprimés, seront supprimés de " -"l'inventaire de Tower. Les hôtes et les groupes qui n'étaient pas gérés par " -"la source de l'inventaire seront promus au prochain groupe créé manuellement" -" ou s'il n'y a pas de groupe créé manuellement dans lequel les promouvoir, " -"ils devront rester dans le groupe \"all\" par défaut de cet inventaire." - -#: client/src/templates/job_templates/job-template.form.js:267 -msgid "If enabled, run this playbook as an administrator." -msgstr "Si activé, exécuter ce playbook en tant qu'administrateur." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:120 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Si activé, afficher les changements faits par les tâches Ansible, si " -"supporté. C'est équivalent au mode Ansible’s -diff ." - -#: client/src/templates/job_templates/job-template.form.js:251 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Si activé, afficher les changements faits par les tâches Ansible, si " -"supporté. C'est équivalent au mode Ansible’s --diff." - -#: client/src/templates/job_templates/job-template.form.js:291 -msgid "If enabled, simultaneous runs of this job template will be allowed." -msgstr "" -"Si activé, il sera possible d’avoir des exécutions de ce modèle de tâche en " -"simultané." - -#: client/src/templates/job_templates/job-template.form.js:302 -msgid "" -"If enabled, use cached facts if available and store discovered facts in the " -"cache." -msgstr "" -"Si cette option est activée, utilisez les faits en cache le cas échéant et " -"les faits découverts par le magasin dans le cache." - -#: client/src/credentials/credentials.form.js:52 -msgid "" -"If no organization is given, the credential can only be used by the user " -"that creates the credential. Organization admins and system administrators " -"can assign an organization so that roles for the credential can be assigned " -"to users and teams in that organization." -msgstr "" -"Si aucune organisation n’est renseignée, les informations d’identification " -"ne peuvent être utilisées que par l’utilisateur qui les crée. Les " -"administrateurs d’organisation et les administrateurs système peuvent " -"assigner une organisation pour que les rôles liés aux informations " -"d’identification puissent être associés aux utilisateurs et aux équipes de " -"cette organisation." - -#: client/src/license/license.partial.html:70 -msgid "" -"If you are ready to upgrade, please contact us by clicking the button below" -msgstr "" -"Si vous êtes prêt à effectuer une mise à niveau, contactez-nous en cliquant " -"sur le bouton ci-dessous" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:173 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:254 -msgid "Image ID:" -msgstr "ID d'image :" - -#: client/src/inventories-hosts/hosts/host.form.js:34 -#: client/src/inventories-hosts/hosts/host.list.js:34 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:33 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:30 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:33 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:29 -msgid "" -"Indicates if a host is available and should be included in running jobs." -msgstr "" -"Indique si un hôte est disponible et doit être ajouté aux tâches en cours " -"d’exécution." - -#: client/src/activity-stream/activity-detail.form.js:31 -#: client/src/activity-stream/streams.list.js:33 -msgid "Initiated by" -msgstr "Initié par" - -#: client/src/credential-types/credential-types.form.js:53 -#: client/src/credential-types/credential-types.form.js:61 -msgid "Injector Configuration" -msgstr "Configuration d'Injector" - -#: client/src/credential-types/credential-types.form.js:39 -#: client/src/credential-types/credential-types.form.js:47 -msgid "Input Configuration" -msgstr "Configuration de l'entrée" - -#: client/src/inventories-hosts/hosts/host.form.js:123 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:122 -msgid "Insights" -msgstr "Insights" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:69 -msgid "Insights Credential" -msgstr "Information d’identification à Insights" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:145 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:148 -msgid "Instance Filters" -msgstr "Filtres de l'instance" - -#: client/src/job-results/job-results.partial.html:369 -msgid "Instance Group" -msgstr "Groupe d'instance" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:75 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:78 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:81 -#: client/src/organizations/organizations.form.js:38 -#: client/src/organizations/organizations.form.js:41 -#: client/src/setup-menu/setup-menu.partial.html:54 -#: client/src/templates/job_templates/job-template.form.js:191 -#: client/src/templates/job_templates/job-template.form.js:194 -msgid "Instance Groups" -msgstr "Groupes d'instances" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "Instance ID" -msgstr "ID d'instance" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:174 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:255 -msgid "Instance ID:" -msgstr "ID d'instance :" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:175 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:256 -msgid "Instance Type:" -msgstr "Type d'instance" - -#: client/src/license/license.partial.html:11 -msgid "Invalid License" -msgstr "Licence non valide" - -#: client/src/license/license.controller.js:63 -#: client/src/license/license.controller.js:70 -msgid "Invalid file format. Please upload valid JSON." -msgstr "Format de fichier non valide. Chargez un fichier JSON valide." - -#: client/lib/components/components.strings.js:16 -msgid "Invalid input for this type." -msgstr "Entrée non valide pour ce type." - -#: client/src/login/loginModal/loginModal.partial.html:34 -msgid "Invalid username and/or password. Please try again." -msgstr "Nom d’utilisateur et/ou mot de passe non valide. Veuillez réessayer." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:122 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:52 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:50 -#: client/src/organizations/linkout/organizations-linkout.route.js:155 -msgid "Inventories" -msgstr "Inventaires" - -#: client/src/inventories-hosts/hosts/host.list.js:69 -#: client/src/inventories-hosts/inventories/inventory.list.js:80 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/job-results/job-results.partial.html:201 -#: client/src/job-submission/job-submission.partial.html:17 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:58 -#: client/src/templates/job_templates/job-template.form.js:66 -#: client/src/templates/job_templates/job-template.form.js:80 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:72 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:82 -msgid "Inventory" -msgstr "Inventaire" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:110 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:124 -msgid "Inventory File" -msgstr "Fichier d'inventaire" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 -#: client/src/setup-menu/setup-menu.partial.html:41 -msgid "Inventory Scripts" -msgstr "Scripts d’inventaire" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:46 -msgid "Inventory Sync" -msgstr "Synchronisation des inventaires" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:55 -msgid "Inventory Sync Failures" -msgstr "Erreurs de synchronisation des inventaires" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:93 -msgid "Inventory Variables" -msgstr "Variables d’inventaire" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:66 -msgid "Inventory contains 0 hosts." -msgstr "L'inventaire contient 0 hôtes." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:4 -msgid "JOB STATUS" -msgstr "ÉTAT DE LA TÂCHE" - -#: client/src/templates/job_templates/job-template.form.js:22 -msgid "JOB TEMPLATE" -msgstr "MODÈLES DE TÂCHE" - -#: client/src/organizations/linkout/organizations-linkout.route.js:256 -#: client/src/organizations/list/organizations-list.controller.js:78 -#: client/src/portal-mode/portal-job-templates.list.js:13 -#: client/src/portal-mode/portal-job-templates.list.js:14 -msgid "JOB TEMPLATES" -msgstr "MODÈLES DE TÂCHE " - -#: client/src/activity-stream/get-target-title.factory.js:32 -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:118 -#: client/src/instance-groups/instance-group.partial.html:28 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:27 -#: client/src/instance-groups/jobs/jobs-list.route.js:9 -#: client/src/jobs/jobs.route.js:15 -#: client/src/main-menu/main-menu.partial.html:122 -#: client/src/main-menu/main-menu.partial.html:43 -#: client/src/portal-mode/portal-jobs.list.js:13 -#: client/src/portal-mode/portal-jobs.list.js:17 -msgid "JOBS" -msgstr "TÂCHES" - -#: client/src/job-submission/job-submission.partial.html:173 -msgid "JSON" -msgstr "JSON" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:198 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:222 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:246 -msgid "JSON:" -msgstr "JSON :" - -#: client/src/job-results/job-results.partial.html:384 -#: client/src/job-submission/job-submission.partial.html:228 -#: client/src/templates/job_templates/job-template.form.js:200 -#: client/src/templates/job_templates/job-template.form.js:207 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:127 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:135 -msgid "Job Tags" -msgstr "Balises de tâche" - -#: client/src/templates/templates.list.js:61 -msgid "Job Template" -msgstr "Modèle de tâche" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:36 -#: client/src/organizations/linkout/organizations-linkout.route.js:268 -msgid "Job Templates" -msgstr "Modèles de tâche" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:32 -#: client/src/job-results/job-results.partial.html:159 -#: client/src/job-submission/job-submission.partial.html:202 -#: client/src/templates/job_templates/job-template.form.js:47 -#: client/src/templates/job_templates/job-template.form.js:55 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:103 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:92 -msgid "Job Type" -msgstr "Type de tâche" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:46 -msgid "" -"Job details are not available for this job. Please download to view " -"standard out." -msgstr "" -"Informations sur cette tâche indisponibles. Téléchargez pour afficher la " -"sortie standard out." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 -#: client/src/configuration/configuration.partial.html:16 -#: client/src/jobs/jobs.partial.html:7 -msgid "Jobs" -msgstr "Tâches" - -#: client/src/job-results/job-results.controller.js:269 -#: client/src/job-results/job-results.controller.js:366 -msgid "Jump to last line of standard out." -msgstr "Passez à la dernière ligne de la sortie standard out." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:61 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:154 -#: client/src/shared/smart-search/smart-search.partial.html:14 -msgid "Key" -msgstr "Clé" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:176 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:257 -msgid "Key Name:" -msgstr "Nom de la clé :" - -#: client/src/credential-types/credential-types.list.js:31 -#: client/src/credentials/credentials.list.js:33 -msgid "Kind" -msgstr "Genre" - -#: client/src/job-submission/job-submission.partial.html:6 -msgid "LAUNCH JOB" -msgstr "TÂCHE DE LANCEMENT" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:86 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:66 -msgid "LAUNCH TYPE" -msgstr "TYPE LANCEMENT" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:111 -msgid "LDAP" -msgstr "LDAP" - -#: client/src/license/license.route.js:19 -msgid "LICENSE" -msgstr "LICENCE" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:58 -msgid "LICENSE ERROR" -msgstr "ERREUR DE LICENCE" - -#: client/src/main-menu/main-menu.partial.html:83 -msgid "LOG OUT" -msgstr "SE DÉCONNECTER" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:68 -#: client/src/instance-groups/jobs/jobs.list.js:66 -#: client/src/job-results/job-results.partial.html:434 -#: client/src/job-results/job-results.partial.html:443 -#: client/src/jobs/all-jobs.list.js:74 -#: client/src/templates/job_templates/job-template.form.js:234 -#: client/src/templates/job_templates/job-template.form.js:238 -#: client/src/templates/templates.list.js:43 -#: client/src/templates/workflows.form.js:62 -#: client/src/templates/workflows.form.js:67 -msgid "Labels" -msgstr "Libellés" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:25 -#: client/src/users/users.form.js:33 client/src/users/users.list.js:37 -msgid "Last Name" -msgstr "Nom" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:56 -msgid "Last Sync" -msgstr "Dernière synchronisation" - -#: client/src/projects/projects.list.js:56 -msgid "Last Updated" -msgstr "Dernière mise à jour" - -#: client/src/portal-mode/portal-job-templates.list.js:36 -#: client/src/shared/form-generator.js:1707 -#: client/src/templates/templates.list.js:80 -msgid "Launch" -msgstr "Lancer" - -#: client/src/management-jobs/card/card.partial.html:23 -msgid "Launch Management Job" -msgstr "Lancer la tâche de gestion" - -#: client/src/job-results/job-results.partial.html:170 -#: client/src/job-results/job-results.partial.html:185 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:76 -msgid "Launched By" -msgstr "Lancé par" - -#: client/src/job-submission/job-submission.partial.html:99 -msgid "" -"Launching this job requires the passwords listed below. Enter and confirm " -"each password before continuing." -msgstr "" -"Le lancement de cette tâche requiert les mots de passe figurant ci-dessous. " -"Saisissez et confirmez chaque mot de passe avant de continuer." - -#: client/features/credentials/legacy.credentials.js:357 -msgid "Legacy state configuration for does not exist" -msgstr "Configuration inexistante de l'état hérité pour." - -#: client/src/license/license.controller.js:40 -#: client/src/license/license.partial.html:8 -msgid "License" -msgstr "Licence" - -#: client/src/license/license.partial.html:104 -msgid "License File" -msgstr "Fichier de licence" - -#: client/src/license/license.partial.html:33 -msgid "License Key" -msgstr "Clé de licence" - -#: client/src/license/license.controller.js:40 -msgid "License Management" -msgstr "Gestion des licences" - -#: client/src/license/license.partial.html:21 -msgid "License Type" -msgstr "Type de licence" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:55 -#: client/src/job-results/job-results.partial.html:347 -#: client/src/job-submission/job-submission.partial.html:220 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:92 -#: client/src/templates/job_templates/job-template.form.js:160 -#: client/src/templates/job_templates/job-template.form.js:164 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:113 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:120 -msgid "Limit" -msgstr "Limite" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:186 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:268 -msgid "Limit to hosts having a tag:" -msgstr "Limite Hôtes qui ont une balise :" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:188 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:270 -msgid "Limit to hosts using either key pair:" -msgstr "Limite Hôtes qui ont n'importe paire de clés :" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "Limit to hosts where the Name tag begins with" -msgstr "Limite Hôtes qui ont une balise de nom commençant par" - -#: client/src/shared/socket/socket.service.js:168 -msgid "Live events: attempting to connect to the server." -msgstr "Événements en direct : tentative de connexion au serveur." - -#: client/src/shared/socket/socket.service.js:172 -msgid "" -"Live events: connected. Pages containing job status information will " -"automatically update in real-time." -msgstr "" -"Événements en direct : connecté. Les pages contenant des informations sur " -"l’état de la tâche seront automatiquement mises à jour en temps réel." - -#: client/src/shared/socket/socket.service.js:176 -msgid "Live events: error connecting to the server." -msgstr "Événements en direct : erreur de connexion au serveur." - -#: client/src/shared/form-generator.js:1983 -msgid "Loading..." -msgstr "Chargement en cours..." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:133 -msgid "Local Time Zone" -msgstr "Fuseau horaire local" - -#: client/src/main-menu/main-menu.partial.html:188 -msgid "Log Out" -msgstr "Se déconnecter" - -#: client/src/configuration/system-form/configuration-system.controller.js:225 -msgid "Log aggregator test failed.
Detail:" -msgstr "Échec du test de l'agrégateur de journalisation.
Détails :" - -#: client/src/configuration/system-form/configuration-system.controller.js:218 -msgid "Log aggregator test successful." -msgstr "Test de l'agrégateur de journalisation réussi." - -#: client/src/configuration/system-form/configuration-system.controller.js:89 -msgid "Logging" -msgstr "Journalisation" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:35 -msgid "Low" -msgstr "Basse" - -#: client/src/management-jobs/card/card.partial.html:6 -#: client/src/management-jobs/card/card.route.js:21 -msgid "MANAGEMENT JOBS" -msgstr "TÂCHES DE GESTION" - -#: client/src/portal-mode/portal-mode.route.js:12 -msgid "MY VIEW" -msgstr "MON ÉCRAN" - -#: client/src/credentials/credentials.form.js:67 -#: client/src/job-submission/job-submission.partial.html:356 -msgid "Machine" -msgstr "Machine" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:60 -#: client/src/job-results/job-results.partial.html:260 -msgid "Machine Credential" -msgstr "Informations d’identification de la machine" - -#: client/src/setup-menu/setup-menu.partial.html:36 -msgid "" -"Manage the cleanup of old job history, activity streams, data marked for " -"deletion, and system tracking info." -msgstr "" -"Gérez le nettoyage de l’historique des anciennes tâches, des flux " -"d’activité, des données marquées pour suppression et des informations de " -"suivi du système." - -#: client/src/setup-menu/setup-menu.partial.html:35 -msgid "Management Jobs" -msgstr "Tâches de gestion" - -#: client/src/projects/list/projects-list.controller.js:89 -msgid "Manual projects do not require a schedule" -msgstr "Les projets manuels ne nécessitent pas de planification" - -#: client/src/projects/edit/projects-edit.controller.js:141 -#: client/src/projects/list/projects-list.controller.js:88 -msgid "Manual projects do not require an SCM update" -msgstr "Les projets manuels ne nécessitent pas de mise à jour SCM" - -#: client/src/login/loginModal/loginModal.partial.html:28 -msgid "Maximum per-user sessions reached. Please sign in." -msgstr "" -"Nombre maximum de sessions par utilisateur atteintes. Veuillez vous " -"connecter." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:29 -msgid "Medium" -msgstr "Moyenne" - -#: client/src/configuration/system-form/configuration-system.controller.js:90 -msgid "Misc. System" -msgstr "Système divers" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:27 -msgid "Missing. Click for details" -msgstr "Manquant. Cliquer pour obtenir davantage d’informations" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:22 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:30 -msgid "Module" -msgstr "Module" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:53 -msgid "Module Args" -msgstr "Args de module" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:25 -msgid "Most recent job failed. Click to view jobs." -msgstr "Échec de la dernière tâche. Cliquez pour afficher les tâches." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:29 -msgid "Most recent job successful. Click to view jobs." -msgstr "Réussite de la dernière tâche. Cliquez pour afficher les tâches." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:77 -msgid "Multiple Choice Options" -msgstr "Options à choix multiples." - -#: client/src/portal-mode/portal-mode-jobs.partial.html:4 -#: client/src/portal-mode/portal-mode-layout.partial.html:11 -msgid "My Jobs" -msgstr "Mes tâches" - -#: client/src/main-menu/main-menu.partial.html:160 -msgid "My View" -msgstr "Ma vue" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:19 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:19 -msgid "NAME" -msgstr "NOM" - -#: client/features/credentials/credentials.strings.js:24 -msgid "NEW CREDENTIAL" -msgstr "NOUVELLE INFORMATION D'IDENTIFICATION" - -#: client/src/credential-types/credential-types.form.js:16 -msgid "NEW CREDENTIAL TYPE" -msgstr "NOUVEAU TYPE D'INFORMATION D'IDENTIFICATION" - -#: client/src/inventory-scripts/inventory-scripts.form.js:16 -msgid "NEW CUSTOM INVENTORY" -msgstr "NOUVEL INVENTAIRE PERSONNALISÉ" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:34 -msgid "NEW INVENTORY" -msgstr "NOUVEL INVENTAIRE" - -#: client/src/templates/job_templates/job-template.form.js:19 -msgid "NEW JOB TEMPLATE" -msgstr "NOUVEAU MODÈLE DE TÂCHE" - -#: client/src/notifications/notificationTemplates.form.js:16 -msgid "NEW NOTIFICATION TEMPLATE" -msgstr "NOUVEAU MODÈLE DE NOTIFICATION" - -#: client/src/organizations/organizations.form.js:18 -msgid "NEW ORGANIZATION" -msgstr "NOUVELLE ORGANISATION" - -#: client/src/projects/projects.form.js:16 -msgid "NEW PROJECT" -msgstr "NOUVEAU PROJET" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:28 -msgid "NEW SMART INVENTORY" -msgstr "NOUVEL INVENTAIRE SMART" - -#: client/src/teams/teams.form.js:16 -msgid "NEW TEAM" -msgstr "NOUVELLE ÉQUIPE" - -#: client/src/users/users.form.js:16 -msgid "NEW USER" -msgstr "NOUVEL UTILISATEUR" - -#: client/src/templates/workflows.form.js:17 -msgid "NEW WORKFLOW JOB TEMPLATE" -msgstr "MODÈLE DE NOUVEAU FLUX DE TRAVAIL" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:38 -msgid "NO HOSTS HAVE BEEN CREATED" -msgstr "AUCUN HÔTE CRÉÉ" - -#: client/lib/components/components.strings.js:35 -msgid "NO OPTIONS AVAILABLE" -msgstr "AUCUNE OPTION DISPONIBLE" - -#: client/src/login/loginModal/loginModal.partial.html:89 -msgid "NOTICE" -msgstr "ENVOI D’INFOS" - -#: client/src/notifications/notificationTemplates.form.js:21 -msgid "NOTIFICATION TEMPLATE" -msgstr "MODÈLE DE NOTIFICATION" - -#: client/src/activity-stream/get-target-title.factory.js:26 -#: client/src/notifications/notificationTemplates.list.js:14 -msgid "NOTIFICATION TEMPLATES" -msgstr "MODÈLES DE NOTIFICATION" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js:9 -#: client/src/management-jobs/notifications/notification.route.js:46 -#: client/src/notifications/main.js:43 client/src/notifications/main.js:91 -msgid "NOTIFICATIONS" -msgstr "NOTIFICATIONS" - -#: client/src/credential-types/credential-types.form.js:27 -#: client/src/credential-types/credential-types.list.js:24 -#: client/src/credentials/credentials.form.js:32 -#: client/src/credentials/credentials.list.js:26 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:14 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:13 -#: client/src/instance-groups/instance-groups.list.js:15 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:35 -#: client/src/instance-groups/instances/instances-list.partial.html:15 -#: client/src/instance-groups/instances/instances.list.js:14 -#: client/src/instance-groups/jobs/jobs.list.js:34 -#: client/src/instance-groups/list/instance-groups-list.partial.html:26 -#: client/src/inventories-hosts/hosts/host.list.js:61 -#: client/src/inventories-hosts/inventories/inventory.list.js:47 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:45 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:33 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:51 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:39 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:45 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:45 -#: client/src/inventory-scripts/inventory-scripts.form.js:28 -#: client/src/inventory-scripts/inventory-scripts.list.js:20 -#: client/src/jobs/all-jobs.list.js:43 -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 -#: client/src/notifications/notificationTemplates.form.js:32 -#: client/src/notifications/notificationTemplates.list.js:32 -#: client/src/notifications/notifications.list.js:26 -#: client/src/organizations/organizations.form.js:26 -#: client/src/portal-mode/portal-job-templates.list.js:23 -#: client/src/portal-mode/portal-jobs.list.js:35 -#: client/src/projects/projects.form.js:29 -#: client/src/projects/projects.list.js:37 -#: client/src/scheduler/scheduled-jobs.list.js:31 -#: client/src/scheduler/schedules.list.js:33 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:19 -#: client/src/teams/teams.form.js:124 client/src/teams/teams.form.js:25 -#: client/src/teams/teams.list.js:23 -#: client/src/templates/completed-jobs.list.js:46 -#: client/src/templates/job_templates/job-template.form.js:34 -#: client/src/templates/templates.list.js:24 -#: client/src/templates/workflows.form.js:32 -#: client/src/users/users.form.js:142 client/src/users/users.form.js:168 -#: client/src/users/users.form.js:194 -msgid "Name" -msgstr "Nom" - -#: client/src/credentials/credentials.form.js:71 -msgid "Network" -msgstr "Réseau" - -#: client/src/job-results/job-results.partial.html:306 -msgid "Network Credential" -msgstr "Informations d’identification réseau" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:81 -msgid "New Group" -msgstr "Nouveau groupe" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:130 -msgid "New Host" -msgstr "Nouvel hôte" - -#: client/src/users/add/users-add.controller.js:91 -msgid "New user successfully created!" -msgstr "Création de l’utilisateur réussie" - -#: client/src/scheduler/scheduled-jobs.list.js:51 -#: client/src/scheduler/schedules.list.js:43 -msgid "Next Run" -msgstr "Exécution suivante" - -#: client/src/credentials/credentials.list.js:21 -msgid "No Credentials Have Been Created" -msgstr "Informations d’identification non créées" - -#: client/src/job-submission/lists/credential/job-sub-cred-list.controller.js:44 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:140 -msgid "No Credentials Matching This Type Have Been Created" -msgstr "" -"Aucune information d'identification correspondant à ce type n'a été créée" - -#: client/src/job-results/host-event/host-event-codemirror.partial.html:3 -msgid "No JSON data returned by the module" -msgstr "Aucune donnée JSON retournée par ce module" - -#: client/src/projects/projects.list.js:20 -msgid "No Projects Have Been Created" -msgstr "Projets non créés" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:50 -msgid "No Remediation Playbook Available" -msgstr "Playbook de remédiation indisponible" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "No SCM Configuration" -msgstr "Aucune configuration SCM" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:9 -msgid "No SCM updates have run for this project" -msgstr "Aucune mise à jour SCM n’a été exécutée pour ce projet" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:17 -msgid "No Teams exist" -msgstr "Aucune équipe existante" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "No Updates Available" -msgstr "Aucune mise à jour disponible" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:18 -msgid "No Users exist" -msgstr "Aucun utilisateur existant" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:23 -#: client/src/templates/completed-jobs.list.js:24 -msgid "No completed jobs" -msgstr "Aucune tâche terminée" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:63 -msgid "No data is available. There are no issues to report." -msgstr "Aucune donnée disponible : aucun problème à signaler." - -#: client/src/license/license.controller.js:39 -msgid "No file selected." -msgstr "Aucun fichier sélectionné." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:62 -msgid "No hosts with failures. Click for details." -msgstr "Aucun hôte avec des échecs. Cliquez pour obtenir plus d'informations." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:47 -msgid "No inventory sync failures. Click for details." -msgstr "" -"Aucun échec de synchronisation d'inventaire. Cliquez pour obtenir plus " -"d'informations." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:16 -msgid "No job data" -msgstr "Aucune donnée de tâche" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:75 -msgid "No job data available." -msgstr "Aucune donnée de tâche disponible." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:22 -msgid "No job failures" -msgstr "Aucun échec de tâche" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:54 -msgid "No job templates were recently used." -msgstr "Aucun modèle de tâche utilisé récemment." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:9 -#: client/src/instance-groups/jobs/jobs.list.js:9 -#: client/src/jobs/all-jobs.list.js:18 -msgid "No jobs have yet run." -msgstr "Aucune tâche exécutée pour l’instant." - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:44 -msgid "No jobs were recently run." -msgstr "Aucune tâche récemment exécutée." - -#: client/src/teams/teams.form.js:121 client/src/users/users.form.js:191 -msgid "No permissions have been granted" -msgstr "Aucune permission accordée" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:17 -msgid "No recent job data available for this host." -msgstr "Aucune donnée de tâche récente n'est disponible pour cet hôte." - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:75 -msgid "No recent job data available for this inventory." -msgstr "Aucune donnée de tâche récente n'est disponible pour cet inventaire." - -#: client/src/notifications/notification-templates-list/list.controller.js:86 -msgid "No recent notifications." -msgstr "Aucun notification récente." - -#: client/src/inventories-hosts/hosts/hosts.partial.html:36 -#: client/src/shared/form-generator.js:1879 -#: client/src/shared/list-generator/list-generator.factory.js:240 -msgid "No records matched your search." -msgstr "Aucun enregistrement ne correspond à votre demande." - -#: client/src/scheduler/scheduled-jobs.list.js:16 -msgid "No schedules exist" -msgstr "Aucune planification existante" - -#: client/src/job-submission/job-submission.partial.html:348 -#: client/src/job-submission/job-submission.partial.html:353 -msgid "None selected" -msgstr "Aucune sélectionnée" - -#: client/src/users/add/users-add.controller.js:10 -#: client/src/users/edit/users-edit.controller.js:10 -#: client/src/users/list/users-list.controller.js:10 -msgid "Normal User" -msgstr "Utilisateur normal" - -#: client/src/projects/list/projects-list.controller.js:91 -msgid "Not configured for SCM" -msgstr "Non configuré pour le SCM" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:52 -msgid "Not configured for inventory sync." -msgstr "Non configuré pour la synchronisation de l'inventaire." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -msgid "" -"Note that only hosts directly in this group can be disassociated. Hosts in " -"sub-groups must be disassociated directly from the sub-group level that they" -" belong." -msgstr "" -"Notez que seuls les hôtes qui sont directement dans ce groupe peuvent être " -"dissociés. Les hôtes qui se trouvent dans les sous-groupes doivent être " -"dissociés directement au niveau du sous-groupe auquel ils appartiennent." - -#: client/src/notifications/notificationTemplates.form.js:288 -#: client/src/notifications/notificationTemplates.form.js:289 -msgid "Notification Color" -msgstr "Couleur des notifications" - -#: client/src/notifications/notification-templates-list/list.controller.js:113 -msgid "Notification Failed." -msgstr "Échec de notification" - -#: client/src/notifications/notificationTemplates.form.js:277 -msgid "Notification Label" -msgstr "Étiquette de notification" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 -msgid "Notification Templates" -msgstr "Modèles de notification" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:20 -#: client/src/management-jobs/notifications/notification.route.js:21 -#: client/src/notifications/notifications.list.js:17 -#: client/src/setup-menu/setup-menu.partial.html:48 -msgid "Notifications" -msgstr "Notifications" - -#: client/src/notifications/notificationTemplates.form.js:302 -msgid "Notify Channel" -msgstr "Canal de notification" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:55 -#: client/src/job-submission/job-submission.partial.html:269 -#: client/src/partials/survey-maker-modal.html:27 -#: client/src/shared/form-generator.js:542 -#: client/src/shared/form-generator.js:773 -#: client/src/shared/generator-helpers.js:551 -msgid "OFF" -msgstr "DÉSACTIVÉ" - -#: client/lib/services/base-string.service.js:63 -#: client/src/jobs/factories/delete-job.factory.js:115 -msgid "OK" -msgstr "OK" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:54 -#: client/src/job-submission/job-submission.partial.html:267 -#: client/src/partials/survey-maker-modal.html:26 -#: client/src/shared/form-generator.js:538 -#: client/src/shared/form-generator.js:771 -#: client/src/shared/generator-helpers.js:547 -msgid "ON" -msgstr "ACTIVÉ" - -#: client/lib/components/components.strings.js:10 -msgid "OPTIONS" -msgstr "OPTIONS" - -#: client/src/activity-stream/get-target-title.factory.js:29 -#: client/src/organizations/list/organizations-list.partial.html:6 -#: client/src/organizations/main.js:52 -msgid "ORGANIZATIONS" -msgstr "ORGANISATIONS" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:116 -msgid "OVERWRITE" -msgstr "REMPLACER" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:123 -msgid "OVERWRITE VARS" -msgstr "REMPLACER VARS" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:38 -msgid "On Failure" -msgstr "Lors d’un échec" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:33 -msgid "On Success" -msgstr "Lors d’une réussite" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:157 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:162 -msgid "Only Group By" -msgstr "Grouper seulement par" - -#: client/src/credentials/credentials.form.js:379 -msgid "" -"OpenStack domains define administrative boundaries. It is only needed for " -"Keystone v3 authentication URLs. Common scenarios include:" -msgstr "" -"Les domaines OpenStack définissent les limites administratives. Ils sont " -"nécessaires seulement pour les URL d’authentification Keystone v3. Les " -"scénarios courants incluent :" - -#: client/src/templates/job_templates/job-template.form.js:240 -#: client/src/templates/workflows.form.js:69 -msgid "" -"Optional labels that describe this job template, such as 'dev' or 'test'. " -"Labels can be used to group and filter job templates and completed jobs." -msgstr "" -"Libellés facultatifs décrivant ce modèle de tâche, par exemple 'dev' ou " -"'test'. Les libellés peuvent être utilisés pour regrouper et filtrer les " -"modèles de tâche et les tâches terminées." - -#: client/src/notifications/notificationTemplates.form.js:382 -#: client/src/partials/logviewer.html:7 -#: client/src/templates/job_templates/job-template.form.js:259 -msgid "Options" -msgstr "Options" - -#: client/src/credentials/credentials.form.js:46 -#: client/src/credentials/credentials.form.js:53 -#: client/src/inventories-hosts/inventories/inventory.list.js:60 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:51 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:58 -#: client/src/inventory-scripts/inventory-scripts.form.js:40 -#: client/src/inventory-scripts/inventory-scripts.list.js:27 -#: client/src/notifications/notificationTemplates.form.js:44 -#: client/src/projects/projects.form.js:41 -#: client/src/projects/projects.form.js:47 client/src/teams/teams.form.js:37 -#: client/src/teams/teams.list.js:30 client/src/templates/workflows.form.js:45 -#: client/src/templates/workflows.form.js:51 client/src/users/users.form.js:40 -msgid "Organization" -msgstr "Organisation" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:136 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:64 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:30 -#: client/src/setup-menu/setup-menu.partial.html:4 -#: client/src/users/users.form.js:132 -msgid "Organizations" -msgstr "Organisations" - -#: client/src/job-submission/job-submission.partial.html:19 -msgid "Other Prompts" -msgstr "Autres invites" - -#: client/src/credentials/credentials.form.js:79 -msgid "Others (Cloud Providers)" -msgstr "Autres (fournisseurs cloud)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:283 -msgid "" -"Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Remplacer les variables qui se trouvent dans cloudforms.ini et qui sont utilisées par le script de mise à jour de l'inventaire. Voici un exemple de configuration de variable\n" -" \n" -" view cloudforms.ini in the Ansible github repo.\n" -"Entrez les variables d’inventaire avec la syntaxe JSON ou YAML. Utilisez le bouton radio pour basculer entre les deux. Consultez la documentation d’Ansible Tower pour avoir un exemple de syntaxe." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:218 -msgid "" -"Override variables found in ec2.ini and used by the inventory update script." -" For a detailed description of these variables" -msgstr "" -"Remplacer les variables qui se trouvent dans ec2.ini et qui sont utilisées " -"par le script de mise à jour de l'inventaire. Pour obtenir une description " -"détaillée de ces variables" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:300 -msgid "" -"Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Remplacer les variables qui se trouvent dans foreman.ini et qui sont utilisées par le script de mise à jour de l'inventaire. Voici un exemple de configuration de variable\n" -" \n" -" view foreman.ini in the Ansible github repo.\n" -"Entrez les variables d’inventaire avec la syntaxe JSON ou YAML. Utilisez le bouton radio pour basculer entre les deux. Consultez la documentation d’Ansible Tower pour avoir un exemple de syntaxe." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:266 -msgid "" -"Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration\n" -" \n" -" view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Remplacer les variables qui se trouvent dans openstack.yml et qui sont utilisées par le script de mise à jour de l'inventaire. Voici un exemple de configuration de variable\n" -" \n" -" view openstack.yml in the Ansible github repo.\n" -"Entrez les variables d’inventaire avec la syntaxe JSON ou YAML. Utilisez le bouton radio pour basculer entre les deux. Consultez la documentation d’Ansible Tower pour avoir un exemple de syntaxe." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:242 -msgid "" -"Override variables found in vmware.ini and used by the inventory update " -"script. For a detailed description of these variables" -msgstr "" -"Remplacer les variables qui se trouvent dans vmware.ini et qui sont " -"utilisées par le script de mise à jour de l'inventaire. Pour obtenir une " -"description détaillée de ces variables" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:328 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:333 -msgid "Overwrite" -msgstr "Remplacer" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:340 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:345 -msgid "Overwrite Variables" -msgstr "Remplacer les variables" - -#: client/src/credentials/credentials.list.js:40 -msgid "Owners" -msgstr "Propriétaires" - -#: client/src/login/loginModal/loginModal.partial.html:68 -msgid "PASSWORD" -msgstr "MOT DE PASSE" - -#: client/features/credentials/legacy.credentials.js:122 -msgid "PERMISSIONS" -msgstr "PERMISSIONS" - -#: client/src/partials/job-template-details.html:2 -msgid "PLAYBOOK" -msgstr "PLAYBOOK" - -#: client/src/partials/survey-maker-modal.html:45 -msgid "PLEASE ADD A SURVEY PROMPT." -msgstr "VEUILLEZ AJOUTER UNE INVITE AU QUESTIONNAIRE." - -#: client/src/instance-groups/instances/instances-list.partial.html:6 -#: client/src/instance-groups/list/instance-groups-list.partial.html:16 -#: client/src/organizations/list/organizations-list.partial.html:47 -#: client/src/shared/form-generator.js:1885 -#: client/src/shared/list-generator/list-generator.factory.js:248 -msgid "PLEASE ADD ITEMS TO THIS LIST" -msgstr "AJOUTEZ DES ÉLÉMENTS À CETTE LISTE" - -#: client/src/main-menu/main-menu.partial.html:67 -msgid "PORTAL MODE" -msgstr "MODE PORTAIL" - -#: client/src/partials/survey-maker-modal.html:43 -msgid "PREVIEW" -msgstr "PRÉVISUALISATION" - -#: client/src/job-results/job-results.service.js:166 -msgid "PROCEED" -msgstr "CONTINUER" - -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:73 -msgid "PROJECT" -msgstr "PROJET" - -#: client/src/activity-stream/get-target-title.factory.js:8 -#: client/src/main-menu/main-menu.partial.html:19 -#: client/src/main-menu/main-menu.partial.html:95 -#: client/src/organizations/linkout/organizations-linkout.route.js:195 -#: client/src/organizations/list/organizations-list.controller.js:72 -#: client/src/projects/main.js:73 client/src/projects/projects.list.js:14 -#: client/src/projects/projects.list.js:15 -msgid "PROJECTS" -msgstr "PROJETS" - -#: client/src/shared/paginate/paginate.partial.html:33 -msgid "Page" -msgstr "Page" - -#: client/src/notifications/notificationTemplates.form.js:232 -msgid "Pagerduty subdomain" -msgstr "Sous-domaine Pagerduty" - -#: client/src/templates/job_templates/job-template.form.js:348 -msgid "" -"Pass extra command line variables to the playbook. Provide key/value pairs " -"using either YAML or JSON. Refer to the Ansible Tower documentation for " -"example syntax." -msgstr "" -"Transmettez des variables de ligne de commandes supplémentaires au playbook." -" Fournir la paire clé/valeur en utilisant YAML ou JSON. Consulter la " -"documentation Ansible Tower pour obtenir des exemples de syntaxe." - -#: client/src/templates/workflows.form.js:80 -msgid "" -"Pass extra command line variables to the playbook. This is the -e or " -"--extra-vars command line parameter for ansible-playbook. Provide key/value " -"pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for" -" example syntax." -msgstr "" -"Transmettez des variables de ligne de commandes supplémentaires au playbook." -" Voici le paramètre de ligne de commande -e or --extra-vars pour ansible-" -"playbook. Fournir la paire clé/valeur en utilisant YAML ou JSON. Consulter " -"la documentation Ansible Tower pour obtenir des exemples de syntaxe." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:138 -msgid "" -"Pass extra command line variables. This is the %s or %s command line " -"parameter for %s. Provide key/value pairs using either YAML or JSON." -msgstr "" -"Transmettez des variables de ligne de commande supplémentaires. Il s'agit du" -" paramètre de ligne de commande %s ou %s pour %s. Entrez des paires " -"clé/valeur avec la syntaxe YAML ou JSON." - -#: client/src/credentials/credentials.form.js:226 -#: client/src/credentials/factories/become-method-change.factory.js:21 -#: client/src/credentials/factories/become-method-change.factory.js:40 -#: client/src/credentials/factories/become-method-change.factory.js:48 -#: client/src/credentials/factories/become-method-change.factory.js:68 -#: client/src/credentials/factories/become-method-change.factory.js:78 -#: client/src/credentials/factories/become-method-change.factory.js:88 -#: client/src/credentials/factories/kind-change.factory.js:105 -#: client/src/credentials/factories/kind-change.factory.js:125 -#: client/src/credentials/factories/kind-change.factory.js:135 -#: client/src/credentials/factories/kind-change.factory.js:145 -#: client/src/credentials/factories/kind-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:78 -#: client/src/credentials/factories/kind-change.factory.js:97 -#: client/src/job-submission/job-submission.partial.html:104 -#: client/src/notifications/shared/type-change.service.js:28 -#: client/src/users/users.form.js:68 -msgid "Password" -msgstr "Mot de passe" - -#: client/src/credentials/factories/kind-change.factory.js:58 -msgid "Password (API Key)" -msgstr "Mot de passe (clé API)" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:20 -msgid "Past 24 Hours" -msgstr "Après 24 heures" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:15 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:26 -msgid "Past Month" -msgstr "Le mois dernier" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:23 -msgid "Past Week" -msgstr "La semaine dernière" - -#: client/src/credentials/factories/become-method-change.factory.js:29 -#: client/src/credentials/factories/kind-change.factory.js:86 -msgid "" -"Paste the contents of the PEM file associated with the service account " -"email." -msgstr "" -"Collez le contenu du fichier PEM associé à l’adresse électronique du compte " -"de service." - -#: client/src/credentials/factories/kind-change.factory.js:51 -msgid "Paste the contents of the SSH private key file." -msgstr "Collez le contenu du fichier de clé privée SSH." - -#: client/src/credentials/factories/kind-change.factory.js:26 -msgid "Paste the contents of the SSH private key file.%s or click to close%s" -msgstr "" -"Collez le contenu du fichier de clé privée SSH.%s ou cliquez pour fermer%s" - -#: client/src/inventories-hosts/inventories/inventory.list.js:119 -msgid "Pending Delete" -msgstr "En attente de suppression" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:8 -msgid "Period" -msgstr "Période" - -#: client/src/projects/add/projects-add.controller.js:29 -#: client/src/users/add/users-add.controller.js:43 -msgid "Permission Error" -msgstr "Erreur de permission" - -#: client/features/credentials/credentials.strings.js:14 -#: client/features/credentials/legacy.credentials.js:66 -#: client/src/credentials/credentials.form.js:439 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:122 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:123 -#: client/src/projects/projects.form.js:233 client/src/teams/teams.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:386 -#: client/src/templates/workflows.form.js:114 -#: client/src/users/users.form.js:187 -msgid "Permissions" -msgstr "Permissions" - -#: client/src/job-results/job-results.partial.html:249 -#: client/src/shared/form-generator.js:1069 -#: client/src/templates/job_templates/job-template.form.js:107 -#: client/src/templates/job_templates/job-template.form.js:115 -msgid "Playbook" -msgstr "Playbook" - -#: client/src/projects/projects.form.js:89 -msgid "Playbook Directory" -msgstr "Répertoire de playbooks" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:52 -msgid "Playbook Run" -msgstr "Exécution du playbook" - -#: client/src/job-results/job-results.partial.html:488 -msgid "Plays" -msgstr "Lancements" - -#: client/src/users/users.form.js:126 -msgid "Please add user to an Organization." -msgstr "Veuillez ajouter un utilisateur à votre organisation." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:100 -msgid "Please assign roles to the selected resources" -msgstr "Veuillez allouer des rôles aux ressources sélectionnées" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:60 -msgid "Please assign roles to the selected users/teams" -msgstr "Veuillez allouer des rôles aux utilisateurs / équipes sélectionnées" - -#: client/src/license/license.partial.html:84 -msgid "" -"Please click the button below to visit Ansible's website to get a Tower " -"license key." -msgstr "" -"Cliquez sur le bouton ci-dessous pour visiter le site Web d'Ansible afin " -"d'obtenir une clé de licence Tower." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:27 -msgid "Please click the icon to edit the host filter." -msgstr "Cliquez sur l'icône pour modifier le filtre de l'hôte." - -#: client/src/shared/form-generator.js:861 -#: client/src/shared/form-generator.js:956 -msgid "" -"Please enter a URL that begins with ssh, http or https. The URL may not " -"contain the '@' character." -msgstr "" -"Veuillez saisir une URL commençant par ssh, http ou https. L’URL ne doit pas" -" contenir le caractère '@'." - -#: client/src/shared/form-generator.js:1158 -msgid "Please enter a number greater than %d and less than %d." -msgstr "Entrez un nombre supérieur à %d et inférieur à %d." - -#: client/src/shared/form-generator.js:1160 -msgid "Please enter a number greater than %d." -msgstr "Entrez un nombre supérieur à %d." - -#: client/src/shared/form-generator.js:1152 -msgid "Please enter a number." -msgstr "Entrez un nombre." - -#: client/src/job-submission/job-submission.partial.html:112 -#: client/src/job-submission/job-submission.partial.html:126 -#: client/src/job-submission/job-submission.partial.html:140 -#: client/src/job-submission/job-submission.partial.html:154 -#: client/src/login/loginModal/loginModal.partial.html:78 -msgid "Please enter a password." -msgstr "Entrez un mot de passe." - -#: client/src/login/loginModal/loginModal.partial.html:58 -msgid "Please enter a username." -msgstr "Entrez un nom d’utilisateur." - -#: client/src/shared/form-generator.js:851 -#: client/src/shared/form-generator.js:946 -msgid "Please enter a valid email address." -msgstr "Entrez une adresse électronique valide." - -#: client/lib/components/components.strings.js:15 -#: client/src/shared/form-generator.js:1016 -#: client/src/shared/form-generator.js:846 -#: client/src/shared/form-generator.js:941 -msgid "Please enter a value." -msgstr "Entrez une valeur." - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/job-submission/job-submission.partial.html:311 -#: client/src/job-submission/job-submission.partial.html:317 -msgid "Please enter an answer between" -msgstr "Veuillez saisir une réponse entre" - -#: client/src/job-submission/job-submission.partial.html:316 -msgid "Please enter an answer that is a decimal number." -msgstr "Veuillez saisir une réponse qui est un chiffre décimal." - -#: client/src/job-submission/job-submission.partial.html:310 -msgid "Please enter an answer that is a valid integer." -msgstr "Veuillez saisir une réponse qui est un entier valide." - -#: client/src/job-submission/job-submission.partial.html:288 -#: client/src/job-submission/job-submission.partial.html:293 -#: client/src/job-submission/job-submission.partial.html:304 -#: client/src/job-submission/job-submission.partial.html:309 -#: client/src/job-submission/job-submission.partial.html:315 -msgid "Please enter an answer." -msgstr "Veuillez saisir une réponse." - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:11 -#: client/src/templates/completed-jobs.list.js:11 -msgid "Please save and run a job to view." -msgstr "Veuillez enregistrer et exécuter une tâche à afficher" - -#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:50 -msgid "Please save before adding a survey to this job template." -msgstr "" -"Veuillez enregistrer avant d'ajouter un questionnaire à ce modèle de tâche." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:46 -msgid "Please save before adding a survey to this workflow." -msgstr "" -"Veuillez enregistrer avant d'ajouter un questionnaire à ce flux de travail." - -#: client/src/notifications/notifications.list.js:15 -msgid "Please save before adding notifications." -msgstr "Veuillez enregistrer avant d'ajouter des notifications." - -#: client/src/organizations/organizations.form.js:68 -#: client/src/teams/teams.form.js:69 -msgid "Please save before adding users." -msgstr "Veuillez enregistrer avant d'ajouter des utilisateurs" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:118 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:119 -#: client/src/projects/projects.form.js:225 client/src/teams/teams.form.js:113 -#: client/src/templates/job_templates/job-template.form.js:379 -#: client/src/templates/workflows.form.js:107 -msgid "Please save before assigning permissions." -msgstr "Veuillez enregistrer avant d'attribuer des permissions." - -#: client/src/users/users.form.js:124 client/src/users/users.form.js:183 -msgid "Please save before assigning to organizations." -msgstr "Veuillez enregistrer avant l'attribution à des organisations." - -#: client/src/users/users.form.js:152 -msgid "Please save before assigning to teams." -msgstr "Veuillez enregistrer avant l'attribution à des équipes." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:164 -msgid "Please save before creating groups." -msgstr "Veuillez enregistrer avant la création de groupes." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:173 -msgid "Please save before creating hosts." -msgstr "Veuillez enregistrer avant la création d'hôtes." - -#: client/src/inventories-hosts/hosts/host.form.js:112 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:86 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:111 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:112 -msgid "Please save before defining groups." -msgstr "Veuillez enregistrer avant de définir des groupes." - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:94 -msgid "Please save before defining hosts." -msgstr "Veuillez enregistrer avant de définir des hôtes." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:182 -msgid "Please save before defining inventory sources." -msgstr "Veuillez enregistrer avant de définir des sources d'inventaire." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:45 -msgid "Please save before defining the workflow graph." -msgstr "" -"Veuillez enregistrer avant de définir le graphique du flux de travail." - -#: client/src/inventories-hosts/hosts/host.form.js:121 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:120 -msgid "Please save before viewing Insights." -msgstr "Veuillez enregistrer avant d'afficher Insights." - -#: client/src/inventories-hosts/hosts/host.form.js:105 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:104 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:105 -msgid "Please save before viewing facts." -msgstr "Veuillez enregistrer avant d'afficher des facts." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:164 -msgid "Please save before viewing hosts." -msgstr "Veuillez enregistrer avant d'afficher le hôtes." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 -msgid "Please select Users / Teams from the lists below." -msgstr "" -"Veuillez sélectionner des utilisateurs / équipes dans les listes ci-dessous." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 -msgid "Please select Users from the list below." -msgstr "Veuillez sélectionner des utilisateurs dans la liste ci-dessous." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:58 -msgid "Please select a Credential." -msgstr "Sélectionnez des informations d’identification." - -#: client/src/templates/job_templates/multi-credential/multi-credential.partial.html:46 -msgid "" -"Please select a machine (SSH) credential or check the \"Prompt on launch\" " -"option." -msgstr "" -"Sélectionnez les informations d'identification de la machine (SSH) ou cochez" -" l'option Me le demander au lancement." - -#: client/src/shared/form-generator.js:1193 -msgid "Please select a number between" -msgstr "Sélectionnez un nombre compris entre" - -#: client/src/shared/form-generator.js:1189 -msgid "Please select a number." -msgstr "Sélectionnez un nombre." - -#: client/src/shared/form-generator.js:1081 -#: client/src/shared/form-generator.js:1149 -#: client/src/shared/form-generator.js:1270 -#: client/src/shared/form-generator.js:1378 -msgid "Please select a value." -msgstr "Sélectionnez une valeur." - -#: client/src/templates/job_templates/job-template.form.js:77 -msgid "Please select an Inventory or check the Prompt on launch option." -msgstr "" -"Sélectionnez un inventaire ou cochez l’option Me le demander au lancement." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:79 -msgid "Please select an Inventory." -msgstr "Sélectionnez un inventaire." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:26 -msgid "Please select an organization before editing the host filter." -msgstr "" -"Veuillez sélectionner une organisation avant d'éditer le filtre de l'hôte." - -#: client/src/shared/form-generator.js:1186 -msgid "Please select at least one value." -msgstr "Sélectionnez une valeur au moins." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:30 -msgid "Please select resources from the lists below." -msgstr "Veuillez sélectionner des ressources dans les listes ci-dessous." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Populate the hosts for this inventory by using a search filter." -msgstr "" -"Remplir les hôtes de cet inventaire en utilisant un filtre de recherche." - -#: client/src/notifications/shared/type-change.service.js:27 -msgid "Port" -msgstr "Port" - -#: client/src/credentials/credentials.form.js:257 -#: client/src/credentials/factories/kind-change.factory.js:21 -#: client/src/credentials/factories/kind-change.factory.js:45 -msgid "Private Key" -msgstr "Clé privée" - -#: client/src/credentials/credentials.form.js:264 -#: client/src/job-submission/job-submission.partial.html:118 -msgid "Private Key Passphrase" -msgstr "Phrase de passe pour la clé privée" - -#: client/src/credentials/credentials.form.js:279 -#: client/src/credentials/credentials.form.js:283 -msgid "Privilege Escalation" -msgstr "Élévation des privilèges" - -#: client/src/credentials/credentials.form.js:305 -#: client/src/job-submission/job-submission.partial.html:132 -msgid "Privilege Escalation Password" -msgstr "Mot de passe pour l’élévation des privilèges" - -#: client/src/credentials/credentials.form.js:295 -msgid "Privilege Escalation Username" -msgstr "Nom d’utilisateur pour l’élévation des privilèges" - -#: client/src/credentials/factories/become-method-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:87 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:93 -#: client/src/job-results/job-results.partial.html:216 -#: client/src/templates/job_templates/job-template.form.js:100 -#: client/src/templates/job_templates/job-template.form.js:91 -msgid "Project" -msgstr "Projet" - -#: client/src/credentials/factories/become-method-change.factory.js:53 -#: client/src/credentials/factories/kind-change.factory.js:110 -msgid "Project (Tenant Name)" -msgstr "Projet (nom du client)" - -#: client/src/projects/projects.form.js:75 -#: client/src/projects/projects.form.js:83 -msgid "Project Base Path" -msgstr "Chemin de base du projet" - -#: client/src/credentials/credentials.form.js:365 -msgid "Project Name" -msgstr "Nom du projet" - -#: client/src/projects/projects.form.js:100 -msgid "Project Path" -msgstr "Chemin du projet" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:66 -msgid "Project Sync Failures" -msgstr "Erreurs de synchronisation du projet" - -#: client/src/projects/list/projects-list.controller.js:170 -msgid "Project lookup failed. GET returned:" -msgstr "La recherche de projet n’a pas abouti. GET renvoyé :" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:115 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:47 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:31 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:61 -#: client/src/organizations/linkout/organizations-linkout.route.js:206 -msgid "Projects" -msgstr "Projets" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:18 -msgid "Promote group" -msgid_plural "Promote groups" -msgstr[0] "Promouvoir Groupe" -msgstr[1] "Promouvoir Groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:43 -msgid "Promote groups" -msgstr "Promouvoir des groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:32 -msgid "Promote groups and hosts" -msgstr "Promouvoir des groupes et des hôtes" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:20 -msgid "Promote host" -msgid_plural "Promote hosts" -msgstr[0] "Promouvoir Hôte" -msgstr[1] "Promouvoir Hôtes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:54 -msgid "Promote hosts" -msgstr "Promouvoir des hôtes" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:10 -msgid "Promote {{ group }} and {{ host }}" -msgstr "Promouvoir {{ group }} et {{ host }}" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:27 -msgid "Prompt" -msgstr "Invite" - -#: client/lib/components/components.strings.js:30 -#: client/src/templates/job_templates/job-template.form.js:139 -#: client/src/templates/job_templates/job-template.form.js:169 -#: client/src/templates/job_templates/job-template.form.js:186 -#: client/src/templates/job_templates/job-template.form.js:212 -#: client/src/templates/job_templates/job-template.form.js:229 -#: client/src/templates/job_templates/job-template.form.js:254 -#: client/src/templates/job_templates/job-template.form.js:354 -#: client/src/templates/job_templates/job-template.form.js:60 -#: client/src/templates/job_templates/job-template.form.js:86 -msgid "Prompt on launch" -msgstr "Me le demander au lancement" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:132 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:147 -msgid "Provide a comma separated list of tags." -msgstr "Entrez une liste de balises séparées par des virgules." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:184 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:266 -msgid "Provide a comma-separated list of filter expressions." -msgstr "Fournir une liste d'expressions de filtre séparées par des virgules." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:200 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:284 -msgid "" -"Provide a comma-separated list of filter expressions. Hosts are imported " -"when all of the filters match. Refer to Ansible Tower documentation for more" -" detail." -msgstr "" -"Fournir une liste séparée par des virgules d'expressions de filtre. Les " -"hôtes sont importés lorsque tous les filtres correspondent. Reportez-vous à " -"la documentation de Ansible Tower pour plus de détails." - -#: client/src/inventories-hosts/hosts/host.form.js:50 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:49 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:49 -msgid "Provide a host name, ip address, or ip address:port. Examples include:" -msgstr "Fournir un nom d'hôte, une adresse ip ou ip address:port. Exemples :" - -#: client/src/templates/job_templates/job-template.form.js:163 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns are allowed. Refer to" -" Ansible documentation for more information and examples on patterns." -msgstr "" -"Entrez un modèle d’hôte pour limiter davantage la liste des hôtes qui seront" -" gérés ou attribués par le playbook. Plusieurs modèles sont autorisés. Voir " -"la documentation Ansible pour plus d'informations et pour obtenir des " -"exemples de modèles." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:116 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns can be separated by " -"%s %s or %s" -msgstr "" -"Entrez un modèle d’hôte pour limiter davantage la liste des hôtes qui seront" -" gérés ou attribués par le playbook. Plusieurs modèles peuvent être séparés " -"par des %s %s ou des %s" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:196 -msgid "Provide environment variables to pass to the custom inventory script." -msgstr "" -"Fournir des variables d'environnement à transmettre au script de " -"l'inventaire personnalisé." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:203 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:287 -msgid "" -"Provide the named URL encoded name or id of the remote Tower inventory to be" -" imported." -msgstr "" -"Fournir le nom encodé de l'URL ou d'id de l'inventaire distant de Tower à " -"importer." - -#: client/src/templates/job_templates/job-template.form.js:311 -#: client/src/templates/job_templates/job-template.form.js:319 -msgid "Provisioning Callback URL" -msgstr "URL de rappel d’exécution de Tower job_template" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Purple" -msgstr "Violet" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:14 -msgid "Queued. Click for details" -msgstr "En file d’attente. Cliquer pour obtenir davantage d’informations" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:112 -msgid "RADIUS" -msgstr "RADIUS" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:4 -msgid "RECENT JOB RUNS" -msgstr "RÉCENTES EXÉCUTIONS DE TÂCHE" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:40 -msgid "RECENTLY RUN JOBS" -msgstr "TÂCHES RÉCEMMENT EXÉCUTÉES" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:50 -msgid "RECENTLY USED JOB TEMPLATES" -msgstr "MODÈLES DE TÂCHE RÉCEMMENT UTILISÉS" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:4 -msgid "RECENTLY USED TEMPLATES" -msgstr "MODÈLES RÉCEMMENT UTILISÉS" - -#: client/src/activity-stream/streams.list.js:54 -#: client/src/inventories-hosts/hosts/host.list.js:102 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:46 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:113 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:54 -#: client/src/jobs/jobs.partial.html:15 -#: client/src/portal-mode/portal-mode-jobs.partial.html:20 -#: client/src/projects/projects.list.js:71 -#: client/src/scheduler/schedules.list.js:61 -msgid "REFRESH" -msgstr "ACTUALISER" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:109 -msgid "REGIONS" -msgstr "RÉGIONS" - -#: client/src/shared/smart-search/smart-search.partial.html:48 -msgid "RELATED FIELDS:" -msgstr "CHAMPS ASSOCIÉS :" - -#: client/src/shared/directives.js:78 -msgid "REMOVE" -msgstr "SUPPRIMER" - -#: client/lib/components/components.strings.js:7 -msgid "REPLACE" -msgstr "REMPLACER" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:7 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:7 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:7 -msgid "RESULTS" -msgstr "RÉSULTATS" - -#: client/lib/components/components.strings.js:8 -#: client/src/job-submission/job-submission.partial.html:44 -#: client/src/job-submission/job-submission.partial.html:87 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:52 -msgid "REVERT" -msgstr "RÉTABLIR" - -#: client/src/credentials/factories/become-method-change.factory.js:25 -#: client/src/credentials/factories/kind-change.factory.js:82 -msgid "RSA Private Key" -msgstr "Clé privée RSA" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.route.js:28 -msgid "RUN COMMAND" -msgstr "EXÉCUTER COMMANDE" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:101 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:56 -msgid "RUN COMMANDS" -msgstr "EXÉCUTER DES COMMANDES" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Random" -msgstr "Aléatoire" - -#: client/src/job-results/job-results.partial.html:411 -msgid "Read only view of extra variables added to the job template." -msgstr "" -"Affichage en lecture seule de variables supplémentaires ajoutées au modèle " -"de tâche." - -#: client/src/workflow-results/workflow-results.partial.html:155 -msgid "Read only view of extra variables added to the workflow." -msgstr "" -"Affichage en lecture seule de variables supplémentaires ajoutées au flux de " -"travail." - -#: client/src/notifications/notificationTemplates.list.js:26 -msgid "Recent Notifications" -msgstr "Notifications récentes" - -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:98 -msgid "Recipient List" -msgstr "Liste de destinataires" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Red" -msgstr "Rouge" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "" -"Refer to the Ansible Tower documentation for further syntax and examples." -msgstr "" -"Consultez la documentation d’Ansible Tower pour obtenir des exemples de " -"syntaxe." - -#: client/src/activity-stream/streams.list.js:51 -#: client/src/bread-crumb/bread-crumb.partial.html:6 -#: client/src/inventories-hosts/hosts/host.list.js:98 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:42 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:109 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:50 -#: client/src/projects/projects.list.js:67 -#: client/src/scheduler/schedules.list.js:57 -msgid "Refresh the page" -msgstr "Actualiser la page" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:177 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "Region:" -msgstr "Région :" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:131 -msgid "Regions" -msgstr "Régions" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:65 -msgid "Related Groups" -msgstr "Groupes liés" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:77 -#: client/src/job-results/job-results.partial.html:29 -#: client/src/jobs/all-jobs.list.js:99 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:11 -#: client/src/templates/completed-jobs.list.js:78 -#: client/src/workflow-results/workflow-results.partial.html:29 -msgid "Relaunch using the same parameters" -msgstr "Relancer en utilisant les mêmes paramètres" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:194 -msgid "Remediate Inventory" -msgstr "Remédier à l'inventaire" - -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:96 -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:97 -#: client/src/teams/teams.form.js:142 client/src/users/users.form.js:222 -msgid "Remove" -msgstr "Supprimer" - -#: client/src/projects/projects.form.js:158 -msgid "Remove any local modifications prior to performing an update." -msgstr "" -"Supprimez toutes les modifications locales avant d’effectuer une mise à " -"jour." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:149 -msgid "Repeat frequency" -msgstr "Fréquence de répétition" - -#: client/src/license/license.partial.html:89 -msgid "Request License" -msgstr "Demander une licence" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:291 -msgid "Required" -msgstr "Obligatoire" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:153 -msgid "Reset" -msgstr "Réinitialisation" - -#: client/src/job-results/job-results.partial.html:123 -msgid "Results Traceback" -msgstr "Traceback Résultats" - -#: client/src/shared/form-generator.js:690 -msgid "Revert" -msgstr "Revenir" - -#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:59 -#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:95 -#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:34 -#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:87 -#: client/src/configuration/auth-form/sub-forms/auth-tacacs.form.js:47 -#: client/src/configuration/jobs-form/configuration-jobs.form.js:73 -#: client/src/configuration/system-form/sub-forms/system-activity-stream.form.js:26 -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:74 -#: client/src/configuration/system-form/sub-forms/system-misc.form.js:50 -#: client/src/configuration/ui-form/configuration-ui.form.js:36 -msgid "Revert all to default" -msgstr "Revenir aux valeurs par défaut" - -#: client/src/job-results/job-results.partial.html:239 -#: client/src/projects/projects.list.js:50 -msgid "Revision" -msgstr "Révision" - -#: client/src/projects/add/projects-add.controller.js:146 -#: client/src/projects/edit/projects-edit.controller.js:281 -msgid "Revision #" -msgstr "Révision n°" - -#: client/features/credentials/legacy.credentials.js:88 -#: client/src/credentials/credentials.form.js:461 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:148 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:149 -#: client/src/organizations/organizations.form.js:97 -#: client/src/projects/projects.form.js:255 client/src/teams/teams.form.js:135 -#: client/src/teams/teams.form.js:98 -#: client/src/templates/workflows.form.js:138 -#: client/src/users/users.form.js:205 -msgid "Role" -msgstr "Rôle" - -#: client/src/instance-groups/instance-group.partial.html:14 -#: client/src/instance-groups/instance-groups.list.js:26 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:14 -#: client/src/instance-groups/instances/instances-list.partial.html:18 -#: client/src/instance-groups/instances/instances.list.js:24 -#: client/src/instance-groups/list/instance-groups-list.partial.html:29 -msgid "Running Jobs" -msgstr "Tâches en cours d'exécution" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:18 -msgid "Running! Click for details" -msgstr "En cours d’exécution. Cliquer pour obtenir davantage d’informations" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:113 -msgid "SAML" -msgstr "SAML" - -#: client/lib/services/base-string.service.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:17 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:17 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:17 -#: client/src/partials/survey-maker-modal.html:87 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:18 -msgid "SAVE" -msgstr "ENREGISTRER" - -#: client/src/scheduler/main.js:331 -msgid "SCHEDULED" -msgstr "PROGRAMMÉ" - -#: client/src/scheduler/scheduled-jobs.list.js:13 -msgid "SCHEDULED JOBS" -msgstr "TÂCHES PROGRAMMÉES" - -#: client/src/activity-stream/get-target-title.factory.js:38 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:49 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:8 -#: client/src/management-jobs/scheduler/main.js:26 -#: client/src/management-jobs/scheduler/main.js:32 -#: client/src/scheduler/main.js:145 client/src/scheduler/main.js:183 -#: client/src/scheduler/main.js:235 client/src/scheduler/main.js:273 -#: client/src/scheduler/main.js:52 client/src/scheduler/main.js:90 -msgid "SCHEDULES" -msgstr "PROGRAMMATIONS" - -#: client/src/projects/add/projects-add.controller.js:118 -#: client/src/projects/edit/projects-edit.controller.js:254 -msgid "SCM Branch" -msgstr "Branche SCM" - -#: client/src/projects/add/projects-add.controller.js:137 -#: client/src/projects/edit/projects-edit.controller.js:272 -msgid "SCM Branch/Tag/Commit" -msgstr "Branche SCM/Balise/Validation" - -#: client/src/projects/add/projects-add.controller.js:158 -#: client/src/projects/edit/projects-edit.controller.js:293 -msgid "SCM Branch/Tag/Revision" -msgstr "Branche SCM/Balise/Révision" - -#: client/src/projects/projects.form.js:159 -msgid "SCM Clean" -msgstr "Nettoyage SCM" - -#: client/src/projects/projects.form.js:170 -msgid "SCM Delete" -msgstr "Suppression SCM" - -#: client/src/credentials/factories/become-method-change.factory.js:20 -#: client/src/credentials/factories/kind-change.factory.js:77 -msgid "SCM Private Key" -msgstr "Clé privée SCM" - -#: client/src/projects/projects.form.js:55 -msgid "SCM Type" -msgstr "Type SCM" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:49 -#: client/src/projects/projects.form.js:180 -msgid "SCM Update" -msgstr "Mise à jour SCM" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "SCM Update Cancel" -msgstr "Annulation de la mise à jour SCM" - -#: client/src/projects/projects.form.js:150 -msgid "SCM Update Options" -msgstr "Options de mise à jour SCM" - -#: client/src/projects/edit/projects-edit.controller.js:137 -#: client/src/projects/list/projects-list.controller.js:84 -msgid "SCM update currently running" -msgstr "Mise à jour SCM en cours" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js:35 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:70 -msgid "SELECT" -msgstr "SÉLECTIONNER" - -#: client/features/credentials/credentials.strings.js:20 -msgid "SELECT A CREDENTIAL TYPE" -msgstr "SÉLECTIONNER UN TYPE D'INFORMATION D'IDENTIFICATION" - -#: client/features/credentials/credentials.strings.js:19 -msgid "SELECT AN ORGANIZATION" -msgstr "SÉLECTIONNER UNE ORGANISATION" - -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:6 -msgid "SELECT GROUPS" -msgstr "SÉLECTIONNER DES GROUPES" - -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:6 -msgid "SELECT HOSTS" -msgstr "SÉLECTIONNER DES HÔTES" - -#: client/src/job-submission/job-submission.partial.html:29 -#: client/src/job-submission/job-submission.partial.html:56 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:20 -msgid "SELECTED:" -msgstr "SÉLECTIONNÉ :" - -#: client/src/main-menu/main-menu.partial.html:59 -#: client/src/setup-menu/setup.route.js:9 -msgid "SETTINGS" -msgstr "PARAMÈTRES" - -#: client/lib/components/components.strings.js:11 -msgid "SHOW" -msgstr "AFFICHER" - -#: client/src/login/loginModal/loginModal.partial.html:97 -msgid "SIGN IN" -msgstr "SE CONNECTER" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html:2 -msgid "SIGN IN WITH" -msgstr "SE CONNECTER AVEC" - -#: client/src/inventories-hosts/hosts/host.list.js:110 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:32 -msgid "SMART INVENTORY" -msgstr "INVENTAIRE SMART" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:102 -msgid "SOURCE" -msgstr "SOURCE" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js:26 -msgid "SOURCES" -msgstr "SOURCES" - -#: client/src/credentials/factories/become-method-change.factory.js:89 -#: client/src/credentials/factories/kind-change.factory.js:146 -msgid "SSH Key" -msgstr "Clé SSH" - -#: client/src/credentials/credentials.form.js:255 -msgid "SSH key description" -msgstr "Description de la clé SSH" - -#: client/src/notifications/notificationTemplates.form.js:375 -msgid "SSL Connection" -msgstr "Connexion SSL" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:128 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:135 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:96 -msgid "STANDARD OUT" -msgstr "STANDARD OUT" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:32 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:65 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:45 -msgid "STARTED" -msgstr "DÉMARRÉ" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:24 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:37 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:37 -msgid "STATUS" -msgstr "STATUT" - -#: client/src/credentials/credentials.form.js:119 -#: client/src/credentials/credentials.form.js:127 -msgid "STS Token" -msgstr "Token STS" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:61 -msgid "SUCCESSFUL" -msgstr "RÉUSSI" - -#: client/src/partials/survey-maker-modal.html:24 -msgid "SURVEY" -msgstr "QUESTIONNAIRE" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:62 -msgid "SYNC ALL" -msgstr "SYNCHRONISER TOUT" - -#: client/src/system-tracking/system-tracking.route.js:18 -msgid "SYSTEM TRACKING" -msgstr "SUIVI DU SYSTÈME" - -#: client/src/credentials/factories/become-method-change.factory.js:70 -#: client/src/credentials/factories/kind-change.factory.js:127 -msgid "Satellite 6 URL" -msgstr "URL Satellite 6" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:110 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:193 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:157 -#: client/src/shared/form-generator.js:1691 -msgid "Save" -msgstr "Enregistrer" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:86 -#: client/src/configuration/configuration.controller.js:213 -#: client/src/configuration/configuration.controller.js:272 -#: client/src/configuration/system-form/configuration-system.controller.js:68 -msgid "Save changes" -msgstr "Enregistrer les modifications" - -#: client/src/license/license.partial.html:127 -msgid "Save successful!" -msgstr "Enregistrement réussi" - -#: client/src/templates/templates.list.js:88 -msgid "Schedule" -msgstr "Planifier" - -#: client/src/management-jobs/card/card.partial.html:28 -msgid "Schedule Management Job" -msgstr "Planifier la tâche de gestion" - -#: client/src/projects/list/projects-list.controller.js:75 -msgid "Schedule future SCM updates" -msgstr "Planifier les prochaines mises à jour SCM" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:7 -msgid "Schedule future inventory syncs" -msgstr "Planifier des synchronisations d'inventaire futures" - -#: client/src/templates/templates.list.js:91 -msgid "Schedule future job template runs" -msgstr "Planifier les prochaines exécutions de modèle de tâche" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:33 -#: client/src/jobs/jobs.partial.html:10 -msgid "Schedules" -msgstr "Calendriers" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:94 -msgid "Search" -msgstr "Rechercher" - -#: client/src/credentials/credentials.form.js:104 -msgid "Secret Key" -msgstr "Clé secrète" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:259 -msgid "Security Group:" -msgstr "Groupe de sécurité :" - -#: client/src/credentials/credentials.form.js:124 -msgid "" -"Security Token Service (STS) is a web service that enables you to request " -"temporary, limited-privilege credentials for AWS Identity and Access " -"Management (IAM) users." -msgstr "" -"Le service de jeton de sécurité (STS) est un service Web qui permet de " -"demander des informations d’identification provisoires avec des privilèges " -"limités pour les utilisateurs d’AWS Identity and Access Management (IAM)." - -#: client/src/shared/form-generator.js:1695 -msgid "Select" -msgstr "Sélectionner" - -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:5 -msgid "Select Instance Groups" -msgstr "Sélectionner des groupes d'instance" - -#: client/src/job-submission/job-submission.directive.js:64 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:46 -msgid "Select a credential" -msgstr "Sélectionner une information d'identification" - -#: client/src/access/add-rbac-user-team/rbac-user-team.controller.js:68 -msgid "Select a role" -msgstr "Sélectionner un rôle" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or a selection of multiple groups." -msgstr "" -"Sélectionner une source d'inventaire en cliquant sur la case correspondante." -" La source de l'inventaire peut être un seul groupe ou une sélection de " -"plusieurs groupes." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:98 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or host, a selection of multiple " -"hosts, or a selection of multiple groups." -msgstr "" -"Sélectionner une source d'inventaire en cliquant sur la case correspondante." -" La source de l'inventaire peut être un seul groupe ou hôte, une sélection " -"de plusieurs hôtes ou une sélection de plusieurs groupes." - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:111 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single host or a selection of multiple hosts." -msgstr "" -"Sélectionner une source d'inventaire en cliquant sur la case correspondante." -" La source de l'inventaire peut être un seul hôte ou une sélection de " -"plusieurs hôtes." - -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:109 -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:134 -#: client/src/configuration/ui-form/configuration-ui.controller.js:95 -msgid "Select commands" -msgstr "Sélectionner des commandes" - -#: client/src/templates/job_templates/job-template.form.js:133 -msgid "" -"Select credentials that allow Tower to access the nodes this job will be ran" -" against. You can only select one credential of each type. For machine " -"credentials (SSH), checking \"Prompt on launch\" without selecting " -"credentials will require you to select a machine credential at run time. If " -"you select credentials and check \"Prompt on launch\", the selected " -"credential(s) become the defaults that can be updated at run time." -msgstr "" -"Sélectionnez les informations d'identification permettant à Tower d'accéder " -"aux noeuds selon qui déterminent l'exécution de cette tâche. Vous pouvez " -"uniquement sélectionner une information d'identification de chaque type. " -"Pour les informations d'identification machine (SSH), cocher la case \"Me " -"demander au lancement\" requiert la sélection des informations " -"d'identification de la machine lors de l'exécution. Si vous sélectionnez des" -" informations d'identification ET que vous cochez la case \"Me demander au " -"lancement\", les informations d'identification sélectionnées deviennent les " -"informations d'identification par défaut qui peuvent être mises à jour au " -"moment de l'exécution." - -#: client/src/projects/projects.form.js:98 -msgid "" -"Select from the list of directories found in the Project Base Path. Together" -" the base path and the playbook directory provide the full path used to " -"locate playbooks." -msgstr "" -"Faites une sélection à partir de la liste des répertoires trouvés dans le " -"chemin de base du projet. Le chemin de base et le répertoire de playbook " -"fournissent ensemble le chemin complet servant à localiser les playbooks." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:263 -#: client/src/configuration/auth-form/configuration-auth.controller.js:282 -msgid "Select group types" -msgstr "Sélectionner des types de groupe" - -#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:24 -msgid "Select roles" -msgstr "Sélectionner des rôles" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:74 -msgid "Select the Instance Groups for this Inventory to run on." -msgstr "" -"Sélectionnez les groupes d'instances sur lesquels exécuter cet inventaire." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:80 -msgid "" -"Select the Instance Groups for this Inventory to run on. Refer to the " -"Ansible Tower documentation for more detail." -msgstr "" -"Sélectionnez les groupes d'instances sur lesquels exécuter cet inventaire. " -"Voir la documentation Ansible Tower pour obtenir plus d'informations." - -#: client/src/templates/job_templates/job-template.form.js:193 -msgid "Select the Instance Groups for this Job Template to run on." -msgstr "" -"Sélectionnez les groupes d'instances sur lesquels exécuter ce modèle de " -"tâche." - -#: client/src/organizations/organizations.form.js:40 -msgid "Select the Instance Groups for this Organization to run on." -msgstr "" -"Sélectionnez les groupes d'instances sur lesquels exécuter cette " -"organisation." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:60 -msgid "" -"Select the credential you want the job to use when accessing the remote " -"hosts. Choose the credential containing the username and SSH key or " -"password that Ansible will need to log into the remote hosts." -msgstr "" -"Sélectionnez les informations d’identification que la tâche doit utiliser " -"lors de l’accès à des hôtes distants. Choisissez les informations " -"d’identification contenant le nom d’utilisateur et la clé SSH ou le mot de " -"passe dont Ansible aura besoin pour se connecter aux hôtes distants." - -#: client/src/templates/job_templates/job-template.form.js:79 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:81 -msgid "Select the inventory containing the hosts you want this job to manage." -msgstr "" -"Sélectionnez l’inventaire contenant les hôtes que vous souhaitez gérer." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:122 -msgid "" -"Select the inventory file to be synced by this source. You can select from " -"the dropdown or enter a file within the input." -msgstr "" -"Sélectionnez le fichier d'inventaire à synchroniser par cette source. Vous " -"pouvez le choisir dans le menu déroulant ou saisir un fichier dans l'entrée." - -#: client/src/templates/job_templates/job-template.form.js:114 -msgid "Select the playbook to be executed by this job." -msgstr "Sélectionnez le playbook qui devra être exécuté par cette tâche." - -#: client/src/templates/job_templates/job-template.form.js:99 -msgid "" -"Select the project containing the playbook you want this job to execute." -msgstr "" -"Sélectionnez le projet contenant le playbook que cette tâche devra exécuter." - -#: client/src/configuration/system-form/configuration-system.controller.js:197 -msgid "Select types" -msgstr "Sélectionner des types" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:170 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:251 -msgid "Select which groups to create automatically." -msgstr "Sélectionner quels groupes créer automatiquement." - -#: client/src/notifications/notificationTemplates.form.js:110 -msgid "Sender Email" -msgstr "Adresse électronique de l’expéditeur" - -#: client/src/credentials/factories/become-method-change.factory.js:24 -#: client/src/credentials/factories/kind-change.factory.js:81 -msgid "Service Account Email Address" -msgstr "Adresse électronique du compte de service" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:101 -msgid "" -"Setting the type to %s will execute the playbook and store any scanned " -"facts for use with 's System Tracking feature." -msgstr "" -"La définition du type sur %s exécute le playbook et stocke tous les faits " -"scannés à utiliser avec la fonctionnalité de suivi System Tracking." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:99 -msgid "" -"Setting the type to %s will not execute the playbook. Instead, %s will check" -" playbook syntax, test environment setup and report problems." -msgstr "" -"La définition du type sur %s n’exécute pas le playbook. À la place, %s " -"vérifie la syntaxe du playbook, teste la configuration de l’environnement et" -" signale les problèmes." - -#: client/src/main-menu/main-menu.partial.html:147 -msgid "Settings" -msgstr "Paramètres" - -#: client/src/job-submission/job-submission.partial.html:108 -#: client/src/job-submission/job-submission.partial.html:122 -#: client/src/job-submission/job-submission.partial.html:136 -#: client/src/job-submission/job-submission.partial.html:150 -#: client/src/job-submission/job-submission.partial.html:299 -#: client/src/shared/form-generator.js:876 -msgid "Show" -msgstr "Afficher" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:114 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:245 -#: client/src/templates/job_templates/job-template.form.js:248 -msgid "Show Changes" -msgstr "Afficher les modifications" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:33 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:44 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:55 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:76 -msgid "Sign in with %s" -msgstr "Se connecter avec %s" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:63 -msgid "Sign in with %s Organizations" -msgstr "Se connecter avec des organisations %s" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:61 -msgid "Sign in with %s Teams" -msgstr "Se connecter avec des équipes %s" - -#: client/src/job-results/job-results.partial.html:395 -#: client/src/job-submission/job-submission.partial.html:245 -#: client/src/templates/job_templates/job-template.form.js:217 -#: client/src/templates/job_templates/job-template.form.js:224 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:142 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:150 -msgid "Skip Tags" -msgstr "Balises de saut" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:148 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task." -msgstr "" -"Les balises de saut sont utiles si votre playbook est important et que vous " -"souhaitez ignorer certaines parties d’une scène ou d’une tâche." - -#: client/src/templates/job_templates/job-template.form.js:223 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task. Use commas to separate multiple tags. " -"Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"Les balises de saut sont utiles si votre playbook est important et que vous " -"souhaitez ignorer certaines parties d’une scène ou d’une tâche. Utiliser des" -" virgules pour séparer plusieurs balises. Consulter la documentation Ansible" -" Tower pour obtenir des détails sur l'utilisation des balises." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:66 -msgid "Smart Host Filter" -msgstr "Filtre d'hôte smart" - -#: client/src/inventories-hosts/inventories/inventory.list.js:85 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/shared/form-generator.js:1456 -msgid "Smart Inventory" -msgstr "Inventaire smart" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:44 -msgid "Solvable With Playbook" -msgstr "Solvable avec playbook" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:57 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:64 -msgid "Source" -msgstr "Source" - -#: client/src/credentials/credentials.form.js:75 -msgid "Source Control" -msgstr "Contrôle de la source" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:47 -#: client/src/projects/projects.form.js:25 -msgid "Source Details" -msgstr "Détails de la source" - -#: client/src/notifications/notificationTemplates.form.js:192 -#: client/src/notifications/notificationTemplates.form.js:193 -msgid "Source Phone Number" -msgstr "Numéro de téléphone de la source" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:136 -msgid "Source Regions" -msgstr "Régions sources" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:209 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:216 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:233 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:240 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:257 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:264 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:274 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:281 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:291 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:298 -msgid "Source Variables" -msgstr "Variables sources" - -#: client/src/partials/logviewer.html:9 -msgid "Source Vars" -msgstr "Vars Source" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:34 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:184 -msgid "Sources" -msgstr "Sources" - -#: client/src/notifications/notificationTemplates.form.js:330 -msgid "" -"Specify HTTP Headers in JSON format. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Spécifier les En-têtes HTTP en format JSON. Voir la documentation Ansible " -"Tower pour obtenir des exemples de syntaxe." - -#: client/src/credentials/credentials.form.js:285 -msgid "" -"Specify a method for %s operations. This is equivalent to specifying the %s " -"parameter, where %s could be %s" -msgstr "" -"Spécifiez une méthode pour les opérations %s. Cela équivaut à définir le " -"paramètre %s, où %s peut être %s" - -#: client/src/notifications/notificationTemplates.form.js:292 -msgid "" -"Specify a notification color. Acceptable colors are: yellow, green, red " -"purple, gray or random." -msgstr "" -"Spécifier une couleur de notification. Les couleurs acceptées sont : jaune, " -"vert, rouge, violet, gris, ou au hasard." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:199 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:283 -msgid "" -"Specify which groups to create automatically. Group names will be created " -"similar to the options selected. If blank, all groups above are created. " -"Refer to Ansible Tower documentation for more detail." -msgstr "" -"Spécifier quels groupes créer automatiquement. Les noms de groupe seront " -"créés de la même façon que les options sélectionnées. Si vide, tous les " -"groupes au-dessus seront créés. Voir la documentation Ansible Tower pour " -"obtenir plus d'informations." - -#: client/src/setup-menu/setup-menu.partial.html:17 -msgid "" -"Split up your organization to associate content and control permissions for " -"groups." -msgstr "" -"Divisez votre organisation afin d’associer du contenu et des permissions de " -"contrôle pour les groupes." - -#: client/src/partials/logviewer.html:5 -msgid "Standard Out" -msgstr "Standard Out" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:41 -msgid "Start Date" -msgstr "Date Début" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:56 -msgid "Start Time" -msgstr "Heure Début" - -#: client/src/portal-mode/portal-job-templates.list.js:39 -#: client/src/templates/templates.list.js:83 -msgid "Start a job using this template" -msgstr "Démarrer une tâche avec ce modèle" - -#: client/src/projects/edit/projects-edit.controller.js:134 -#: client/src/projects/list/projects-list.controller.js:74 -msgid "Start an SCM update" -msgstr "Démarrer une mise à jour SCM" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:6 -msgid "Start sync process" -msgstr "Démarrer le processus de synchronisation" - -#: client/src/job-results/job-results.partial.html:100 -msgid "Started" -msgstr "Démarré" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:53 -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:55 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:43 -#: client/src/job-results/job-results.partial.html:67 -#: client/src/job-results/parse-stdout.service.js:68 -#: client/src/notifications/notification-templates-list/list.controller.js:71 -#: client/src/partials/logviewer.html:4 -msgid "Status" -msgstr "État" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:3 -msgid "Sub Category" -msgstr "Sous-catégorie" - -#: client/src/license/license.partial.html:126 -msgid "Submit" -msgstr "Valider" - -#: client/src/jobs/factories/delete-job.factory.js:109 -msgid "Submit the request to cancel?" -msgstr "Demander l’annulation de la demande ?" - -#: client/src/license/license.partial.html:27 -msgid "Subscription" -msgstr "Abonnement" - -#: client/src/credentials/credentials.form.js:151 -#: client/src/credentials/credentials.form.js:162 -msgid "Subscription ID" -msgstr "ID d’abonnement" - -#: client/src/credentials/credentials.form.js:161 -msgid "Subscription ID is an Azure construct, which is mapped to a username." -msgstr "" -"L’ID d’abonnement est une construction Azure mappée à un nom d’utilisateur." - -#: client/src/notifications/notifications.list.js:38 -msgid "Success" -msgstr "Réussite" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:21 -msgid "Success! Click for details" -msgstr "Réussi. Cliquer pour obtenir davantage d’informations" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:77 -msgid "Successful" -msgstr "Réussi" - -#: client/src/job-submission/job-submission.partial.html:20 -msgid "Survey" -msgstr "Questionnaire" - -#: client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js:60 -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:64 -msgid "" -"Surveys allow users to be prompted at job launch with a series of questions " -"related to the job. This allows for variables to be defined that affect the " -"playbook run at time of launch." -msgstr "" -"Les questionnaires permettent aux utilisateurs d'être invités lors du " -"lancement d'une tâche à répondre à une série de questions liées à la tâche. " -"Cela permet de définir les variables affectant l'exécution du Playbook au " -"moment du lancement." - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:58 -msgid "Sync all inventory sources" -msgstr "Synchroniser toutes les sources d'inventaire" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:29 -msgid "Sync canceled. Click to view log." -msgstr "Synchronisation annulée. Cliquez pour afficher le journal." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:35 -msgid "Sync completed. Click to view log." -msgstr "Synchronisation terminée. Cliquez pour afficher le journal." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:32 -msgid "Sync failed. Click to view log." -msgstr "Échec de la synchronisation. Cliquez pour afficher le journal." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "Sync not performed. Click" -msgstr "Synchronisation non effectuée. Cliquez" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:38 -msgid "Sync pending." -msgstr "Synchronisation en attente." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:45 -msgid "Sync running" -msgstr "Synchronisation en cours" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:46 -msgid "Sync running. Click to view log." -msgstr "Synchronisation en cours. Cliquez pour afficher le journal." - -#: client/src/configuration/configuration.partial.html:17 -msgid "System" -msgstr "Système" - -#: client/src/users/add/users-add.controller.js:12 -#: client/src/users/edit/users-edit.controller.js:12 -#: client/src/users/list/users-list.controller.js:12 -msgid "System Administrator" -msgstr "Administrateur système" - -#: client/src/users/add/users-add.controller.js:11 -#: client/src/users/edit/users-edit.controller.js:11 -#: client/src/users/list/users-list.controller.js:11 -msgid "System Auditor" -msgstr "Auditeur système" - -#: client/src/configuration/configuration.partial.html:3 -msgid "System auditors have read-only permissions in this section." -msgstr "" -"Les auditeurs de système n’ont que des permissions lecture-seule sur cette " -"section." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:114 -msgid "TACACS+" -msgstr "TACACS+" - -#: client/src/activity-stream/get-target-title.factory.js:23 -#: client/src/organizations/linkout/organizations-linkout.route.js:97 -#: client/src/organizations/list/organizations-list.controller.js:60 -#: client/src/teams/main.js:46 client/src/teams/teams.list.js:14 -#: client/src/teams/teams.list.js:15 -msgid "TEAMS" -msgstr "ÉQUIPES" - -#: client/src/activity-stream/get-target-title.factory.js:44 -#: client/src/main-menu/main-menu.partial.html:113 -#: client/src/main-menu/main-menu.partial.html:35 -#: client/src/templates/list/templates-list.route.js:13 -#: client/src/templates/templates.list.js:15 -#: client/src/templates/templates.list.js:16 -msgid "TEMPLATES" -msgstr "MODÈLES" - -#: client/src/instance-groups/instance-groups.list.js:8 -msgid "THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED" -msgstr "IL N'Y AUCUN GROUPE D'INSTANCES ACTUELLEMENT DÉFINIS" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:104 -msgid "TIME" -msgstr "DURÉE" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:61 -msgid "TOP" -msgstr "TOP" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:181 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:262 -msgid "Tag None:" -msgstr "Ne rien baliser :" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:133 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task." -msgstr "" -"Les balises sont utiles si votre playbook est important et que vous " -"souhaitez exécuter une partie donnée d’une scène ou d’une tâche." - -#: client/src/templates/job_templates/job-template.form.js:206 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task. Use commas to separate multiple tags. Refer" -" to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"Les balises sont utiles si votre playbook est important et que vous " -"souhaitez faire jouer certaines parties d’une scène ou exécuter une tâche. " -"Utiliser des virgules pour séparer plusieurs balises. Consulter la " -"documentation Ansible Tower pour obtenir des détails sur l'utilisation des " -"balises." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:179 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "Tags:" -msgstr "Balises :" - -#: client/src/notifications/notificationTemplates.form.js:309 -msgid "Target URL" -msgstr "URL cible" - -#: client/src/job-results/job-results.partial.html:496 -msgid "Tasks" -msgstr "Tâches" - -#: client/features/credentials/legacy.credentials.js:94 -#: client/src/credentials/credentials.form.js:467 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:154 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:155 -#: client/src/projects/projects.form.js:261 -#: client/src/templates/workflows.form.js:144 -msgid "Team Roles" -msgstr "Rôles d’équipe" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:34 -#: client/src/organizations/linkout/organizations-linkout.route.js:108 -#: client/src/setup-menu/setup-menu.partial.html:16 -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/users/users.form.js:159 -msgid "Teams" -msgstr "Équipes" - -#: client/src/job-results/job-results.partial.html:135 -#: client/src/templates/templates.list.js:14 -msgid "Template" -msgstr "Modèle" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:35 -msgid "Templates" -msgstr "Modèles" - -#: client/src/credentials/credentials.form.js:337 -msgid "Tenant ID" -msgstr "ID Client" - -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:79 -msgid "Test" -msgstr "Test" - -#: client/src/notifications/notificationTemplates.list.js:67 -msgid "Test notification" -msgstr "Notification test" - -#: client/src/shared/form-generator.js:1386 -#: client/src/shared/form-generator.js:1392 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" -"Cette valeur n’a pas été trouvée. Veuillez entrer ou sélectionner une valeur" -" valide." - -#: client/lib/components/components.strings.js:43 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" -"Cette valeur n’a pas été trouvée. Veuillez entrer ou sélectionner une valeur" -" valide." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:66 -msgid "The Insights Credential for {{inventory.name}} was not found." -msgstr "" -"Informations d'identification Insights introuvables pour {{inventory.name}}." - -#: client/src/credentials/factories/become-method-change.factory.js:32 -#: client/src/credentials/factories/kind-change.factory.js:89 -msgid "" -"The Project ID is the GCE assigned identification. It is constructed as two " -"words followed by a three digit number. Such as:" -msgstr "" -"L’ID du projet est l’identifiant attribué par GCE. Il se compose de deux " -"mots suivis d’un nombre à trois chiffres. Exemple :" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "The SCM update process is running." -msgstr "Le processus de mise à jour SCM est en cours d’exécution." - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:70 -msgid "The credential used to run this command." -msgstr "" -"Les informations d’identification utilisées pour exécuter cette commande." - -#: client/src/credentials/credentials.form.js:190 -msgid "" -"The email address assigned to the Google Compute Engine %sservice account." -msgstr "" -"Adresse électronique attribuée au compte de service Google Compute Engine " -"%s." - -#: client/src/job-results/job-results.partial.html:513 -msgid "The host count will update when the job is complete." -msgstr "Le nombre d'hôtes s'actualisera une fois la tâche terminée." - -#: client/src/credentials/factories/become-method-change.factory.js:62 -#: client/src/credentials/factories/kind-change.factory.js:119 -msgid "The host to authenticate with." -msgstr "Hôte avec lequel s’authentifier." - -#: client/src/credentials/factories/kind-change.factory.js:60 -msgid "The host value" -msgstr "Valeur de l’hôte" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:61 -msgid "The inventory this command ran on." -msgstr "L’inventaire sur lequel cette commande a été exécutée." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:101 -msgid "" -"The inventory will be in a pending status until the final delete is " -"processed." -msgstr "" -"L'inventaire présentera le statut en attente tant que la suppression " -"complète ne sera pas traitée." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:104 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Inputting no value will use the default value from the %sansible " -"configuration file%s." -msgstr "" -"Nombre de processus parallèles ou simultanés à utiliser lors de l'exécution " -"du playbook. La saisie d'aucune valeur entraînera l'utilisation de la valeur" -" par défaut du %sfichier de configuration ansible%s." - -#: client/src/templates/job_templates/job-template.form.js:152 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Value defaults to 0. Refer to the Ansible documentation for " -"details about the configuration file." -msgstr "" -"Nombre de processus parallèles ou simultanés à utiliser lors de l'exécution " -"du playbook. 0 indique la valeur par défaut. Voir la documentation Ansible " -"pour plus d'informations sur le fichier de configuration." - -#: client/src/job-results/job-results.controller.js:619 -msgid "The output is too large to display. Please download." -msgstr "" -"La sortie est trop volumineuse pour être affichée. Veuillez télécharger." - -#: client/src/credentials/factories/kind-change.factory.js:59 -msgid "The project value" -msgstr "Valeur du projet" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "" -"The selected project is not configured for SCM. To configure for SCM, edit " -"the project and provide SCM settings, and then run an update." -msgstr "" -"Le projet sélectionné n’est pas configuré pour SCM. Afin de le configurer " -"pour SCM, modifiez le projet et définissez les paramètres SCM, puis lancez " -"une mise à jour." - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:42 -msgid "" -"The standard output is too large to display. Please specify additional " -"filters to narrow the standard out." -msgstr "" -"La sortie standard out est trop volumineuse pour être affichée. Veuillez " -"spécifier d'autres filtres pour restreindre le standard." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:52 -msgid "" -"The suggested format for variable names is lowercase and underscore-" -"separated (for example, foo_bar, user_id, host_name, etc.). Variable names " -"with spaces are not allowed." -msgstr "" -"Le format suggéré pour les noms de variables est en minuscules avec des " -"tirets de séparation (exemple, foo_bar, user_id, host_name, etc.). Les noms " -"de variables contenant des espaces ne sont pas autorisés." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:124 -msgid "The time must be in HH24:MM:SS format." -msgstr "L’heure doit être sous le format suivant HH24:MM:SS" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:79 -msgid "The user who ran this command." -msgstr "L’utilisateur qui a exécuté cette commande." - -#: client/src/activity-stream/streams.list.js:17 -msgid "There are no events to display at this time" -msgstr "Aucun événement à afficher pour le moment" - -#: client/src/portal-mode/portal-job-templates.list.js:18 -msgid "There are no job templates to display at this time" -msgstr "Aucun modèle de tâche à afficher pour le moment" - -#: client/src/portal-mode/portal-jobs.list.js:18 -msgid "There are no jobs to display at this time" -msgstr "Aucune tâche à afficher pour le moment" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "" -"There is no SCM update information available for this project. An update has" -" not yet been completed. If you have not already done so, start an update " -"for this project." -msgstr "" -"Aucune information de mise à jour SCM n’est disponible pour ce projet. Une " -"mise à jour n’est pas encore terminée. Si vous n’avez pas encore lancé une " -"mise à jour pour ce projet, faites-le." - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:140 -msgid "There was an error deleting inventory source groups. Returned status:" -msgstr "" -"Une erreur s’est produite lors de la suppression des groupes de source " -"d'inventaire. État renvoyé :" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:130 -msgid "There was an error deleting inventory source hosts. Returned status:" -msgstr "" -"Une erreur s’est produite lors de la suppression des hôtes de source " -"d'inventaire. État renvoyé :" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:167 -msgid "There was an error deleting inventory source. Returned status:" -msgstr "" -"Une erreur s’est produite lors de la suppression de la source d'inventaire. " -"État renvoyé :" - -#: client/src/configuration/configuration.controller.js:349 -msgid "There was an error resetting value. Returned status:" -msgstr "" -"Une erreur s’est produite lors de la réinitialisation de la valeur. État " -"renvoyé :" - -#: client/src/configuration/configuration.controller.js:531 -msgid "There was an error resetting values. Returned status:" -msgstr "" -"Une erreur s’est produite lors de la réinitialisation des valeurs. État " -"renvoyé :" - -#: client/src/configuration/system-form/configuration-system.controller.js:232 -msgid "There was an error testing the log aggregator. Returned status:" -msgstr "" -"Une erreur s’est produite lors du test de l'agrégateur. État renvoyé :" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:29 -msgid "" -"These are the modules that {{BRAND_NAME}} supports running commands against." -msgstr "" -"Il s'agit des modules pris en charge par {{BRAND_NAME}} pour l'exécution de " -"commandes." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:26 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "This group contains" -msgstr "Ce groupe contient" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:168 -msgid "This is not a valid number." -msgstr "Le nombre n’est pas valide." - -#: client/src/credentials/factories/become-method-change.factory.js:59 -#: client/src/credentials/factories/kind-change.factory.js:116 -msgid "" -"This is the tenant name. This value is usually the same as the username." -msgstr "" -"Il s’agit du nom du client. Cette valeur est habituellement la même que " -"celle du nom d’utilisateur." - -#: client/src/notifications/notifications.list.js:21 -msgid "" -"This list is populated by notification templates added from the " -"%sNotifications%s section" -msgstr "" -"Cette liste contient des modèles de notification ajoutés à partir de la " -"section %sNotifications%s" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:4 -msgid "" -"This machine has not checked in with Insights in {{last_check_in}} hours" -msgstr "" -"Cette machine n'a pas été connectée à Insights depuis {{last_check_in}} " -"heures" - -#: client/src/shared/form-generator.js:746 -msgid "" -"This setting has been set manually in a settings file and is now disabled." -msgstr "" -"Cette valeur a été définie manuellement dans un fichier de configuration et " -"est maintenant désactivée." - -#: client/src/users/users.form.js:164 -msgid "This user is not a member of any teams" -msgstr "Cet utilisateur n’est pas membre d’une équipe" - -#: client/src/shared/form-generator.js:856 -#: client/src/shared/form-generator.js:951 -msgid "" -"This value does not match the password you entered previously. Please " -"confirm that password." -msgstr "" -"Cette valeur ne correspond pas au mot de passe que vous avez entré " -"précédemment. Veuillez confirmer ce mot de passe." - -#: client/src/configuration/configuration.controller.js:556 -msgid "" -"This will reset all configuration values to their factory defaults. Are you " -"sure you want to proceed?" -msgstr "" -"Cette opération rétablit toutes les valeurs de configuration sur leurs " -"valeurs par défaut. Voulez-vous vraiment continuer ?" - -#: client/src/activity-stream/streams.list.js:25 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:14 -#: client/src/notifications/notification-templates-list/list.controller.js:72 -msgid "Time" -msgstr "Durée" - -#: client/src/license/license.partial.html:45 -msgid "Time Remaining" -msgstr "Durée restante" - -#: client/src/projects/projects.form.js:196 -msgid "" -"Time in seconds to consider a project to be current. During job runs and " -"callbacks the task system will evaluate the timestamp of the latest project " -"update. If it is older than Cache Timeout, it is not considered current, and" -" a new project update will be performed." -msgstr "" -"Délai en secondes à prévoir pour qu’un projet soit actualisé. Durant " -"l’exécution des tâches et les rappels, le système de tâches évalue " -"l’horodatage de la dernière mise à jour du projet. Si elle est plus ancienne" -" que le délai d’expiration du cache, elle n’est pas considérée comme " -"actualisée, et une nouvelle mise à jour du projet sera effectuée." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:387 -msgid "" -"Time in seconds to consider an inventory sync to be current. During job runs" -" and callbacks the task system will evaluate the timestamp of the latest " -"sync. If it is older than Cache Timeout, it is not considered current, and a" -" new inventory sync will be performed." -msgstr "" -"Délai en secondes à prévoir pour qu'une synchronisation d'inventaire soit " -"actualisée. Durant l’exécution des tâches et les rappels, le système de " -"tâches évalue l’horodatage de la dernière mise à jour du projet. Si elle est" -" plus ancienne que le délai d’expiration du cache, elle n’est pas considérée" -" comme actualisée, et une nouvelle synchronisation de l'inventaire sera " -"effectuée." - -#: client/src/credentials/credentials.form.js:125 -msgid "" -"To learn more about the IAM STS Token, refer to the %sAmazon " -"documentation%s." -msgstr "" -"Pour en savoir plus sur le token STS d’IAM, reportez-vous à la documentation" -" d’%sAmazon%s." - -#: client/src/shared/form-generator.js:881 -msgid "Toggle the display of plaintext." -msgstr "Bascule l’affichage du texte en clair." - -#: client/src/notifications/shared/type-change.service.js:34 -#: client/src/notifications/shared/type-change.service.js:40 -msgid "Token" -msgstr "Token" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:44 -msgid "Too much previous output to display. Showing running standard output." -msgstr "" -"La sortie précédente est trop volumineuse pour être affichée. Affichage de " -"la sortie standard en cours d'exécution." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:10 -msgid "Total Issues" -msgstr "Nombre de problèmes total" - -#: client/src/partials/logviewer.html:6 -msgid "Traceback" -msgstr "Traceback" - -#: client/src/credentials/credentials.form.js:60 -#: client/src/credentials/credentials.form.js:84 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:52 -#: client/src/instance-groups/jobs/jobs.list.js:51 -#: client/src/inventories-hosts/inventories/inventory.list.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:52 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:41 -#: client/src/jobs/all-jobs.list.js:59 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:39 -#: client/src/notifications/notifications.list.js:31 -#: client/src/projects/projects.list.js:44 -#: client/src/scheduler/scheduled-jobs.list.js:42 -#: client/src/teams/teams.form.js:130 -#: client/src/templates/completed-jobs.list.js:53 -#: client/src/templates/templates.list.js:31 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:27 -#: client/src/users/users.form.js:200 -msgid "Type" -msgstr "Type" - -#: client/features/credentials/credentials.strings.js:18 -#: client/src/credentials/credentials.form.js:23 -#: client/src/notifications/notificationTemplates.form.js:26 -msgid "Type Details" -msgstr "Détails sur le type" - -#: client/src/projects/add/projects-add.controller.js:169 -#: client/src/projects/edit/projects-edit.controller.js:304 -msgid "URL popover text" -msgstr "Texte popover de l’URL" - -#: client/src/login/loginModal/loginModal.partial.html:49 -msgid "USERNAME" -msgstr "NOM D’UTILISATEUR" - -#: client/src/activity-stream/get-target-title.factory.js:20 -#: client/src/organizations/linkout/organizations-linkout.route.js:42 -#: client/src/organizations/list/organizations-list.controller.js:54 -#: client/src/users/main.js:46 client/src/users/users.list.js:18 -#: client/src/users/users.list.js:19 -msgid "USERS" -msgstr "UTILISATEURS" - -#: client/lib/components/components.strings.js:20 -msgid "Unable to Submit" -msgstr "Validation impossible" - -#: client/lib/components/components.strings.js:52 -msgid "Unavailable to run jobs." -msgstr "Non disponible pour exécuter les tâches." - -#: client/lib/components/components.strings.js:22 -msgid "Unexpected Error" -msgstr "Erreur inattendue" - -#: client/lib/components/components.strings.js:21 -msgid "Unexpected server error. View the console for more information" -msgstr "" -"Erreur de serveur inattendue. Affichez la console pour plus d'informations." - -#: client/lib/components/components.strings.js:34 -msgid "Unsupported display model type" -msgstr "Type de modèle d'affichage non pris en charge" - -#: client/lib/components/components.strings.js:26 -msgid "Unsupported input type" -msgstr "Type d'entrée non prise en charge" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "Update Not Found" -msgstr "Mise à jour introuvable" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:321 -msgid "Update Options" -msgstr "Mettre à jour les options" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "Update in Progress" -msgstr "Mise à jour en cours" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:352 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:357 -#: client/src/projects/projects.form.js:177 -msgid "Update on Launch" -msgstr "Mettre à jour au lancement" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:364 -msgid "Update on Project Change" -msgstr "Mettre à jour lorsqu'une modification est apportée au projet" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:370 -msgid "Update on Project Update" -msgstr "Mettre à jour lorsque le projet est actualisé" - -#: client/src/license/license.partial.html:71 -msgid "Upgrade" -msgstr "Mettre à niveau" - -#: client/src/templates/job_templates/job-template.form.js:299 -#: client/src/templates/job_templates/job-template.form.js:304 -msgid "Use Fact Cache" -msgstr "Utiliser le cache des facts" - -#: client/src/notifications/notificationTemplates.form.js:395 -msgid "Use SSL" -msgstr "Utiliser SSL" - -#: client/src/notifications/notificationTemplates.form.js:390 -msgid "Use TLS" -msgstr "Utiliser TLS" - -#: client/src/instance-groups/instance-group.partial.html:10 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:10 -#: client/src/instance-groups/instances/instances-list.partial.html:21 -#: client/src/instance-groups/list/instance-groups-list.partial.html:32 -msgid "Used Capacity" -msgstr "Capacité utilisée" - -#: client/src/credentials/credentials.form.js:76 -msgid "" -"Used to check out and synchronize playbook repositories with a remote source" -" control management system such as Git, Subversion (svn), or Mercurial (hg)." -" These credentials are used by Projects." -msgstr "" -"Utilisé pour vérifier et synchroniser les référentiels de playbooks avec un " -"SCM à distance tel que Git, Subversion (svn) ou Mercurial (hg). Ces " -"informations d’identification sont utilisées par les Projets." - -#: client/features/credentials/legacy.credentials.js:83 -#: client/src/credentials/credentials.form.js:456 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:143 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:144 -#: client/src/organizations/organizations.form.js:92 -#: client/src/projects/projects.form.js:250 client/src/teams/teams.form.js:93 -#: client/src/templates/workflows.form.js:133 -msgid "User" -msgstr "Utilisateur" - -#: client/src/configuration/configuration.partial.html:18 -msgid "User Interface" -msgstr "Interface utilisateur" - -#: client/src/users/users.form.js:95 -msgid "User Type" -msgstr "Type d’utilisateur" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:30 -#: client/src/credentials/factories/become-method-change.factory.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:38 -#: client/src/credentials/factories/kind-change.factory.js:17 -#: client/src/credentials/factories/kind-change.factory.js:41 -#: client/src/credentials/factories/kind-change.factory.js:74 -#: client/src/credentials/factories/kind-change.factory.js:95 -#: client/src/notifications/notificationTemplates.form.js:64 -#: client/src/users/users.form.js:58 client/src/users/users.list.js:29 -msgid "Username" -msgstr "Nom d’utilisateur" - -#: client/src/credentials/credentials.form.js:80 -msgid "" -"Usernames, passwords, and access keys for authenticating to the specified " -"cloud or infrastructure provider. These are used for smart inventory sources" -" and for cloud provisioning and deployment in playbook runs." -msgstr "" -"Noms d'utilisateur, mots de passe et clés d'accès pour s'authentifier auprès" -" du fournisseur de cloud ou d'infrastructure spécifié. Ceux-ci sont utilisés" -" pour les sources d'inventaire smarts et pour l'allocation de services dans " -"le cloud et leur déploiement dans les playbooks." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:36 -#: client/src/organizations/organizations.form.js:74 -#: client/src/setup-menu/setup-menu.partial.html:10 -#: client/src/teams/teams.form.js:75 -msgid "Users" -msgstr "Utilisateurs" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:7 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:7 -msgid "VIEW ALL" -msgstr "TOUT AFFICHER" - -#: client/src/main-menu/main-menu.partial.html:75 -msgid "VIEW DOCUMENTATION" -msgstr "AFFICHER LA DOCUMENTATION" - -#: client/src/shared/paginate/paginate.partial.html:48 -msgid "VIEW PER PAGE" -msgstr "AFFICHER PAR PAGE" - -#: client/src/main-menu/main-menu.partial.html:51 -msgid "VIEW USER PAGE FOR {{ $root.current_user.username | uppercase }}" -msgstr "" -"AFFICHER LA PAGE UTILISATEUR POUR {{ $root.current_user.username | uppercase" -" }}" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:180 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:261 -msgid "VPC ID:" -msgstr "ID VPC :" - -#: client/src/license/license.partial.html:10 -msgid "Valid License" -msgstr "Licence valide" - -#: client/src/inventories-hosts/hosts/host.form.js:68 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:46 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:67 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:67 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:81 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:88 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:94 -msgid "Variables" -msgstr "Variables" - -#: client/src/job-submission/job-submission.partial.html:364 -msgid "Vault" -msgstr "Coffre-fort" - -#: client/src/job-results/job-results.partial.html:321 -msgid "Vault Credential" -msgstr "Informations d'identification du coffre-fort" - -#: client/src/credentials/credentials.form.js:391 -#: client/src/job-submission/job-submission.partial.html:146 -msgid "Vault Password" -msgstr "Mot de passe Vault" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:81 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:90 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:307 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:314 -#: client/src/job-results/job-results.partial.html:358 -#: client/src/job-submission/job-submission.partial.html:183 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:99 -#: client/src/templates/job_templates/job-template.form.js:174 -#: client/src/templates/job_templates/job-template.form.js:181 -msgid "Verbosity" -msgstr "Verbosité" - -#: client/src/license/license.partial.html:15 -msgid "Version" -msgstr "Version" - -#: client/src/activity-stream/streams.list.js:63 -#: client/src/credential-types/credential-types.list.js:64 -#: client/src/credentials/credentials.list.js:75 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:58 -#: client/src/inventories-hosts/inventories/inventory.list.js:104 -#: client/src/inventory-scripts/inventory-scripts.list.js:62 -#: client/src/notifications/notificationTemplates.list.js:82 -#: client/src/scheduler/schedules.list.js:83 client/src/teams/teams.list.js:64 -#: client/src/templates/templates.list.js:112 -#: client/src/users/users.list.js:70 -msgid "View" -msgstr "Afficher" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "View Activity Stream" -msgstr "Afficher le flux d’activité" - -#: client/src/main-menu/main-menu.partial.html:173 -msgid "View Documentation" -msgstr "Afficher la documentation" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:79 -msgid "View Insights Data" -msgstr "Afficher les données des informations" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:202 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:226 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:250 -msgid "View JSON examples at" -msgstr "Afficher les exemples JSON à" - -#: client/src/inventories-hosts/hosts/host.form.js:78 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:77 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:77 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:91 -msgid "View JSON examples at %s" -msgstr "Afficher les exemples JSON à %s" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:13 -msgid "View Less" -msgstr "Afficher moins" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:11 -msgid "View More" -msgstr "Afficher plus" - -#: client/src/shared/form-generator.js:1719 -#: client/src/templates/job_templates/job-template.form.js:436 -#: client/src/templates/workflows.form.js:161 -msgid "View Survey" -msgstr "Afficher le questionnaire" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:203 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:227 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:251 -msgid "View YAML examples at" -msgstr "Afficher les exemples YAML à" - -#: client/src/inventories-hosts/hosts/host.form.js:79 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:78 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:78 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:92 -msgid "View YAML examples at %s" -msgstr "Afficher les exemples YAML à %s" - -#: client/src/setup-menu/setup-menu.partial.html:72 -msgid "View Your License" -msgstr "Afficher votre licence" - -#: client/src/setup-menu/setup-menu.partial.html:73 -msgid "View and edit your license information." -msgstr "Affichez et modifiez vos informations de licence." - -#: client/src/credentials/credentials.list.js:77 -msgid "View credential" -msgstr "Afficher les informations d’identification" - -#: client/src/credential-types/credential-types.list.js:66 -msgid "View credential type" -msgstr "Afficher le type d'informations d’identification" - -#: client/src/activity-stream/streams.list.js:67 -msgid "View event details" -msgstr "Afficher les détails de l’événement" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:93 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:103 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:91 -msgid "View group" -msgstr "Afficher le groupe" - -#: client/src/inventories-hosts/hosts/host.list.js:89 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:93 -msgid "View host" -msgstr "Afficher l'hôte" - -#: client/src/setup-menu/setup-menu.partial.html:67 -msgid "View information about this version of Ansible {{BRAND_NAME}}." -msgstr "Afficher des informations sur cette version d'Ansible {{BRAND_NAME}}." - -#: client/src/inventories-hosts/inventories/inventory.list.js:106 -msgid "View inventory" -msgstr "Afficher l’inventaire" - -#: client/src/inventory-scripts/inventory-scripts.list.js:64 -msgid "View inventory script" -msgstr "Afficher le script d’inventaire" - -#: client/src/setup-menu/setup-menu.partial.html:55 -msgid "View list and capacity of {{BRAND_NAME}} instances." -msgstr "Afficher la liste et la capacité des instances {{BRAND_NAME}}." - -#: client/src/notifications/notificationTemplates.list.js:84 -msgid "View notification" -msgstr "Afficher la notification" - -#: client/src/job-results/job-results.partial.html:222 -msgid "View project sync results" -msgstr "Afficher les résultats de synchronisation du projet" - -#: client/src/scheduler/schedules.list.js:85 -msgid "View schedule" -msgstr "Afficher le calendrier" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:118 -msgid "View source" -msgstr "Afficher la source" - -#: client/src/teams/teams.list.js:67 -msgid "View team" -msgstr "Afficher l’équipe" - -#: client/src/templates/templates.list.js:114 -msgid "View template" -msgstr "Afficher le modèle" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "View the" -msgstr "Afficher " - -#: client/src/jobs/all-jobs.list.js:92 -msgid "View the job" -msgstr "Afficher la tâche" - -#: client/src/projects/projects.list.js:111 -msgid "View the project" -msgstr "Afficher le projet" - -#: client/src/scheduler/scheduled-jobs.list.js:74 -msgid "View the schedule" -msgstr "Afficher le calendrier" - -#: client/src/users/users.list.js:73 -msgid "View user" -msgstr "Afficher l’utilisateur" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:42 -#: client/src/instance-groups/jobs/jobs.list.js:41 -#: client/src/job-results/job-results.partial.html:145 -#: client/src/jobs/all-jobs.list.js:49 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:25 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:25 -msgid "View workflow results" -msgstr "Afficher les résultats du workflow" - -#: client/src/templates/workflows.form.js:20 -msgid "WORKFLOW" -msgstr "WORKFLOW" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:73 -#: client/src/configuration/configuration.controller.js:200 -#: client/src/configuration/configuration.controller.js:262 -#: client/src/configuration/system-form/configuration-system.controller.js:55 -msgid "Warning: Unsaved Changes" -msgstr "Avertissement : modifications non enregistrées" - -#: client/src/license/license.partial.html:78 -msgid "" -"Welcome to Ansible Tower! Please complete the steps below to acquire a " -"license." -msgstr "" -"Bienvenue à Ansible Tower ! Veuillez suivre les étapes ci-dessous pour " -"obtenir une licence." - -#: client/src/login/loginModal/loginModal.partial.html:17 -msgid "Welcome to Ansible {{BRAND_NAME}}!  Please sign in." -msgstr "Bienvenue sur Ansible {{BRAND_NAME}} !  Connectez-vous." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:344 -msgid "" -"When not checked, a merge will be performed, combining local variables with " -"those found on the external source." -msgstr "" -"Si la case n'est pas cochée, une fusion aura lieu, combinant les variables " -"locales à celles qui se trouvent dans la source externe." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:332 -msgid "" -"When not checked, local child hosts and groups not found on the external " -"source will remain untouched by the inventory update process." -msgstr "" -"Si non cochée, les hôtes et groupes locaux dépendants non trouvés dans la " -"source externe ne seront pas touchés par le processus de mise à jour de " -"l'inventaire." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:97 -msgid "" -"When this template is submitted as a job, setting the type to %s will " -"execute the playbook, running tasks on the selected hosts." -msgstr "" -"Lorsque ce modèle est validé en tant que tâche, le fait de définir le type " -"sur %s exécute le playbook en lançant les tâches sur les hôtes sélectionnés." - -#: client/src/shared/form-generator.js:1723 -#: client/src/templates/workflows.form.js:187 -msgid "Workflow Editor" -msgstr "Workflow Editor" - -#: client/src/templates/templates.list.js:66 -msgid "Workflow Template" -msgstr "Modèle de workflow" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:41 -msgid "Workflow Templates" -msgstr "Modèles de workflow" - -#: client/src/job-submission/job-submission.partial.html:171 -msgid "YAML" -msgstr "YAML" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:200 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:224 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:248 -msgid "YAML:" -msgstr "YAML :" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Yellow" -msgstr "Jaune" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:56 -msgid "" -"You can create a job template here." -msgstr "" -"Vous pouvez créer un modèle de tâche ici." - -#: client/src/projects/edit/projects-edit.controller.js:62 -msgid "You do not have access to view this property" -msgstr "Vous n’avez pas d’accès pour afficher cette propriété" - -#: client/src/projects/add/projects-add.controller.js:29 -msgid "You do not have permission to add a project." -msgstr "Vous n’êtes pas autorisé à ajouter un projet." - -#: client/src/users/add/users-add.controller.js:43 -msgid "You do not have permission to add a user." -msgstr "Vous n’êtes pas autorisé à ajouter un utilisateur." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:28 -msgid "You do not have sufficient permissions to edit the host filter." -msgstr "" -"Vous ne disposez pas de suffisamment de permissions pour modifier le filtre " -"de l'hôte." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:72 -#: client/src/configuration/configuration.controller.js:199 -#: client/src/configuration/configuration.controller.js:261 -#: client/src/configuration/system-form/configuration-system.controller.js:54 -msgid "" -"You have unsaved changes. Would you like to proceed without" -" saving?" -msgstr "" -"Des modifications n’ont pas été enregistrées. Voulez-vous continuer " -"sans les enregistrer ?" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "Your request to cancel the update was submitted to the task manager." -msgstr "" -"Votre demande d’annulation de la mise à jour a été envoyée au gestionnaire " -"de tâches." - -#: client/src/login/loginModal/loginModal.partial.html:22 -msgid "Your session timed out due to inactivity. Please sign in." -msgstr "" -"Votre session a expiré en raison d’un temps d’inactivité. Veuillez vous " -"connecter." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/shared/form-generator.js:1193 -msgid "and" -msgstr "et" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "characters long." -msgstr "caractères." - -#: client/src/shared/smart-search/smart-search.partial.html:53 -msgid "documentation" -msgstr "documentation" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:193 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:275 -msgid "for a complete list of supported filters." -msgstr "pour obtenir une liste complète des filtres pris en charge." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "from the" -msgstr "à partir du" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -#: client/src/inventories-hosts/inventory-hosts.strings.js:8 -msgid "group" -msgid_plural "groups" -msgstr[0] "group" -msgstr[1] "groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "groups" -msgstr "groupes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -msgid "groups and" -msgstr "groupes et" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:9 -msgid "host" -msgid_plural "hosts" -msgstr[0] "hôte" -msgstr[1] "hôtes" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -msgid "hosts" -msgstr "hôtes" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:58 -msgid "hosts with failures. Click for details." -msgstr "hôtes avec échecs. Cliquez pour obtenir plus d'informations." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:21 -msgid "name" -msgstr "nom" - -#: client/src/shared/paginate/paginate.partial.html:34 -msgid "of" -msgstr "de" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "of the filters match." -msgstr "des filtres correspondent." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:24 -msgid "organization" -msgstr "organisation" - -#: client/src/shared/form-generator.js:1069 -msgid "playbook" -msgstr "playbook" - -#: client/src/credentials/credentials.form.js:138 -#: client/src/credentials/credentials.form.js:364 -msgid "set in helpers/credentials" -msgstr "définir dans helpers/credentials" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:43 -msgid "sources with sync failures. Click for details" -msgstr "" -"sources avec échecs de synchronisation. Cliquez pour obtenir plus " -"d'informations." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "test" -msgstr "test" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "to" -msgstr "pour" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "" -"to include all regions. Only Hosts associated with the selected regions will" -" be updated." -msgstr "" -"pour inclure toutes les régions. Seuls les hôtes associés aux régions " -"sélectionnées sont actualisés." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "to start it now." -msgstr "pour commencer maintenant." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "to update." -msgstr "pour actualiser." - -#: client/src/credentials/credentials.form.js:381 -msgid "v2 URLs%s - leave blank" -msgstr "v2 URLs%s - laisser vide" - -#: client/src/credentials/credentials.form.js:382 -msgid "v3 default%s - set to 'default'" -msgstr "v3 default%s - définir sur 'default'" - -#: client/src/credentials/credentials.form.js:383 -msgid "v3 multi-domain%s - your domain name" -msgstr "v3 multi-domain%s - votre nom de domaine" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:220 -msgid "view ec2.ini in the Ansible github repo." -msgstr "afficher ec2.ini dans le référentiel github Ansible." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:244 -msgid "view vmware_inventory.ini in the Ansible github repo." -msgstr "afficher vmware_inventory.ini dans le référentiel github Ansible." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "when" -msgstr "quand" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:171 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:252 -msgid "" -"will create group names similar to the following examples based on the " -"options selected:" -msgstr "" -"créera des noms de groupe semblables aux noms de groupes des exemples " -"suivants selon les options sélectionnées :" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:11 -msgid "with failed jobs." -msgstr "avec des tâches ayant échoué." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs-list.route.js:9 -msgid "{{ breadcrumb.instance_name }}" -msgstr "{{ breadcrumb.instance_name }}" - -#: client/lib/components/input/label.partial.html:5 -msgid "{{::state._hint}}" -msgstr "{{::state._hint}}" - -#: client/src/instance-groups/instances/instances-list.route.js:10 -msgid "{{breadcrumb.instance_group_name}}" -msgstr "{{breadcrumb.instance_group_name}}" - -#: client/src/shared/paginate/paginate.partial.html:55 -msgid "{{pageSize}}" -msgstr "{{pageSize}}" diff --git a/awx/ui/po/ja.po b/awx/ui/po/ja.po deleted file mode 100644 index 719df35933e1..000000000000 --- a/awx/ui/po/ja.po +++ /dev/null @@ -1,5799 +0,0 @@ -# asasaki , 2017. #zanata -# mkim , 2017. #zanata -# myamamot , 2017. #zanata -# shanemcd , 2017. #zanata -msgid "" -msgstr "" -"Project-Id-Version: \n" -"PO-Revision-Date: 2017-12-06 12:57+0000\n" -"Last-Translator: asasaki \n" -"Language-Team: Japanese\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ja\n" -"Plural-Forms: nplurals=1; plural=0\n" -"X-Generator: Zanata 4.3.2\n" - -#: client/src/projects/add/projects-add.controller.js:153 -#: client/src/projects/edit/projects-edit.controller.js:288 -msgid "" -"%sNote:%s Mercurial does not support password authentication for SSH. Do not" -" put the username and key in the URL. If using Bitbucket and SSH, do not " -"supply your Bitbucket username." -msgstr "" -"%s注:%s Mercurial は SSH のパスワード認証をサポートしません。ユーザー名およびキーを URL " -"に入れないでください。Bitbucket および SSH を使用している場合は、Bitbucket ユーザー名を入力しないでください。" - -#: client/src/projects/add/projects-add.controller.js:132 -#: client/src/projects/edit/projects-edit.controller.js:267 -msgid "" -"%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key " -"only, do not enter a username (other than git). Additionally, GitHub and " -"Bitbucket do not support password authentication when using SSH. GIT read " -"only protocol (git://) does not use username or password information." -msgstr "" -"%s注:%s GitHub または Bitbucket の SSH プロトコルを使用している場合、SSH キーのみを入力し、ユーザー名 (git 以外)" -" を入力しないでください。また、GitHub および Bitbucket は、SSH の使用時のパスワード認証をサポートしません。GIT " -"の読み取り専用プロトコル (git://) はユーザー名またはパスワード情報を使用しません。" - -#: client/src/credentials/credentials.form.js:287 -msgid "(defaults to %s)" -msgstr "(%s にデフォルト設定)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -msgid "(seconds)" -msgstr "(秒)" - -#: client/src/organizations/list/organizations-list.partial.html:20 -msgid "+ ADD" -msgstr "+ 追加" - -#: client/src/shared/paginate/paginate.partial.html:66 -msgid "100" -msgstr "100" - -#: client/src/shared/paginate/paginate.partial.html:60 -msgid "20" -msgstr "20" - -#: client/src/shared/paginate/paginate.partial.html:63 -msgid "50" -msgstr "50" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:33 -msgid "A schedule name is required." -msgstr "スケジュール名が必要です。" - -#: client/src/users/add/users-add.controller.js:102 -msgid "A value is required" -msgstr "値が必要です" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:167 -msgid "A value is required." -msgstr "値が必要です。" - -#: client/src/about/about.route.js:10 -msgid "ABOUT" -msgstr "情報" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 -msgid "ACTION" -msgstr "アクション" - -#: client/src/activity-stream/activity-detail.form.js:23 -msgid "ACTIVITY DETAIL" -msgstr "アクティビティーの詳細" - -#: client/src/activity-stream/activitystream.route.js:28 -#: client/src/activity-stream/streams.list.js:14 -#: client/src/activity-stream/streams.list.js:15 -msgid "ACTIVITY STREAM" -msgstr "アクティビティーストリーム" - -#: client/features/credentials/legacy.credentials.js:76 -#: client/src/credential-types/credential-types.list.js:44 -#: client/src/credentials/credentials.form.js:449 -#: client/src/credentials/credentials.list.js:54 -#: client/src/inventories-hosts/inventories/inventory.list.js:77 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:71 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:120 -#: client/src/inventory-scripts/inventory-scripts.list.js:42 -#: client/src/notifications/notificationTemplates.list.js:54 -#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 -#: client/src/organizations/organizations.form.js:84 -#: client/src/projects/projects.form.js:243 -#: client/src/projects/projects.list.js:78 -#: client/src/scheduler/schedules.list.js:68 client/src/teams/teams.form.js:85 -#: client/src/teams/teams.list.js:45 -#: client/src/templates/job_templates/job-template.form.js:397 -#: client/src/templates/templates.list.js:58 -#: client/src/templates/workflows.form.js:125 -#: client/src/users/users.list.js:50 -msgid "ADD" -msgstr "追加" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:71 -msgid "ADD GROUP" -msgstr "グループの追加" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:125 -msgid "ADD HOST" -msgstr "ホストの追加" - -#: client/src/teams/teams.form.js:157 client/src/users/users.form.js:216 -msgid "ADD PERMISSIONS" -msgstr "パーミッションの追加" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:70 -msgid "ADD SOURCE" -msgstr "ソースの追加" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:16 -msgid "ADD SURVEY PROMPT" -msgstr "Survey プロンプトの追加" - -#: client/src/shared/smart-search/smart-search.partial.html:51 -msgid "ADDITIONAL INFORMATION" -msgstr "追加情報" - -#: client/src/organizations/linkout/organizations-linkout.route.js:330 -#: client/src/organizations/list/organizations-list.controller.js:84 -msgid "ADMINS" -msgstr "管理者" - -#: client/src/activity-stream/get-target-title.factory.js:4 -msgid "ALL ACTIVITY" -msgstr "すべてのアクティビティー" - -#: client/src/jobs/all-jobs.list.js:14 -msgid "ALL JOBS" -msgstr "すべてのジョブ" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "ANY" -msgstr "任意" - -#: client/src/credentials/credentials.form.js:198 -msgid "API Key" -msgstr "API キー" - -#: client/src/notifications/notificationTemplates.form.js:243 -msgid "API Service/Integration Key" -msgstr "API サービス/統合キー" - -#: client/src/notifications/shared/type-change.service.js:52 -msgid "API Token" -msgstr "API トークン" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:71 -msgid "ASSOCIATE GROUP" -msgstr "グループの関連付け" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js:19 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js:19 -msgid "ASSOCIATED GROUPS" -msgstr "関連付けられているグループ" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js:19 -msgid "ASSOCIATED HOSTS" -msgstr "関連付けられているホスト" - -#: client/src/setup-menu/setup-menu.partial.html:66 -msgid "About {{BRAND_NAME}}" -msgstr "{{BRAND_NAME}} の概要" - -#: client/src/credentials/credentials.form.js:91 -msgid "Access Key" -msgstr "アクセスキー" - -#: client/src/notifications/notificationTemplates.form.js:221 -msgid "Account SID" -msgstr "アカウント SID" - -#: client/src/notifications/notificationTemplates.form.js:180 -msgid "Account Token" -msgstr "アカウントトークン" - -#: client/src/activity-stream/activity-detail.form.js:36 -msgid "Action" -msgstr "アクション" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/inventories-hosts/hosts/hosts.partial.html:47 -#: client/src/shared/list-generator/list-generator.factory.js:573 -msgid "Actions" -msgstr "アクション" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:17 -#: client/src/templates/templates.list.js:36 -msgid "Activity" -msgstr "アクティビティー" - -#: client/src/configuration/system-form/configuration-system.controller.js:88 -msgid "Activity Stream" -msgstr "アクティビティーストリーム" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:131 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:132 -#: client/src/organizations/organizations.form.js:81 -#: client/src/teams/teams.form.js:82 -#: client/src/templates/workflows.form.js:122 -msgid "Add" -msgstr "追加" - -#: client/src/credentials/credentials.list.js:14 -msgid "Add Credentials" -msgstr "認証情報の追加" - -#: client/src/inventories-hosts/inventories/inventory.list.js:13 -msgid "Add Inventories" -msgstr "インベントリーの追加" - -#: client/src/shared/stateDefinitions.factory.js:288 -msgid "Add Permissions" -msgstr "パーミッションの追加" - -#: client/src/projects/projects.list.js:13 -msgid "Add Project" -msgstr "プロジェクトの追加" - -#: client/src/shared/form-generator.js:1711 -#: client/src/templates/job_templates/job-template.form.js:445 -#: client/src/templates/workflows.form.js:170 -msgid "Add Survey" -msgstr "Survey の追加" - -#: client/src/teams/teams.list.js:13 -msgid "Add Team" -msgstr "チームの追加" - -#: client/src/teams/teams.form.js:83 -msgid "Add User" -msgstr "ユーザーの追加" - -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/shared/stateDefinitions.factory.js:578 -#: client/src/users/users.list.js:17 -msgid "Add Users" -msgstr "ユーザーの追加" - -#: client/src/organizations/organizations.form.js:82 -msgid "Add Users to this organization." -msgstr "ユーザーをこの組織に追加してください。" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:69 -msgid "Add a group" -msgstr "グループの追加" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:118 -msgid "Add a host" -msgstr "ホストの追加" - -#: client/src/scheduler/schedules.list.js:66 -msgid "Add a new schedule" -msgstr "新規スケジュールの追加" - -#: client/features/credentials/legacy.credentials.js:74 -#: client/src/credentials/credentials.form.js:447 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:133 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:134 -#: client/src/projects/projects.form.js:241 -#: client/src/templates/job_templates/job-template.form.js:395 -#: client/src/templates/workflows.form.js:123 -msgid "Add a permission" -msgstr "パーミッションの追加" - -#: client/src/setup-menu/setup-menu.partial.html:23 -msgid "" -"Add passwords, SSH keys, and other credentials to use when launching jobs " -"against machines, or when syncing inventories or projects." -msgstr "" -"マシンに対するジョブの起動時やインベントリーまたはプロジェクトの同期時に使用するパスワード、SSH キーおよびその他の認証情報を追加します。" - -#: client/src/shared/form-generator.js:1446 -msgid "Admin" -msgstr "管理者" - -#: client/src/organizations/linkout/organizations-linkout.route.js:354 -msgid "Admins" -msgstr "管理者" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:367 -msgid "" -"After every project update where the SCM revision changes, refresh the " -"inventory from the selected source before executing job tasks. This is " -"intended for static content, like the Ansible inventory .ini file format." -msgstr "" -"SCM " -"リビジョンが変更されるプロジェクトの毎回の更新後に、選択されたソースのインベントリーを更新してからジョブのタスクを実行します。これは、Ansible " -"インベントリーの .ini ファイル形式のような静的コンテンツが対象であることが意図されています。" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:37 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:43 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:65 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:74 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "All" -msgstr "すべて" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 -msgid "All Activity" -msgstr "すべてのアクティビティー" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:10 -#: client/src/portal-mode/portal-mode-layout.partial.html:17 -msgid "All Jobs" -msgstr "すべてのジョブ" - -#: client/src/templates/job_templates/job-template.form.js:275 -#: client/src/templates/job_templates/job-template.form.js:282 -msgid "Allow Provisioning Callbacks" -msgstr "プロビジョニングコールバックの許可" - -#: client/src/setup-menu/setup-menu.partial.html:11 -msgid "" -"Allow others to sign into {{BRAND_NAME}} and own the content they create." -msgstr "他のユーザーが {{BRAND_NAME}} にサインインし、独自に作成するコンテンツを所有できるようにします。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:43 -msgid "Always" -msgstr "常時" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "" -"An SCM update does not appear to be running for project: %s. Click the " -"%sRefresh%s button to view the latest status." -msgstr "SCM 更新がプロジェクトに対して実行されていないようです: %s。%s更新%s ボタンをクリックして最新のステータスを表示してください。" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:62 -#: client/src/templates/survey-maker/shared/question-definition.form.js:68 -msgid "Answer Type" -msgstr "回答タイプ" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:44 -#: client/src/templates/survey-maker/shared/question-definition.form.js:53 -msgid "Answer Variable Name" -msgstr "回答の変数名" - -#: client/src/job-results/job-results.service.js:144 -msgid "Are you sure you want to cancel the job below?" -msgstr "以下のジョブを取り消してもよろしいですか?" - -#: client/src/credentials/list/credentials-list.controller.js:133 -msgid "Are you sure you want to delete the credential below?" -msgstr "以下の認証情報を削除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:100 -msgid "Are you sure you want to delete the inventory below?" -msgstr "以下のインベントリーを削除してもよろしいですか?" - -#: client/src/job-results/job-results.service.js:95 -#: client/src/jobs/factories/delete-job.factory.js:110 -msgid "Are you sure you want to delete the job below?" -msgstr "以下のジョブを削除してもよろしいですか?" - -#: client/src/notifications/notification-templates-list/list.controller.js:190 -msgid "Are you sure you want to delete the notification template below?" -msgstr "以下の通知テンプレートを削除してもよろしいですか?" - -#: client/src/organizations/list/organizations-list.controller.js:172 -msgid "Are you sure you want to delete the organization below?" -msgstr "以下の組織を削除してもよろしいですか?" - -#: client/src/projects/list/projects-list.controller.js:208 -msgid "Are you sure you want to delete the project below?" -msgstr "以下のプロジェクトを削除してもよろしいですか?" - -#: client/src/templates/list/templates-list.controller.js:103 -msgid "Are you sure you want to delete the template below?" -msgstr "以下のテンプレートを削除してもよろしいですか?" - -#: client/src/users/list/users-list.controller.js:90 -msgid "Are you sure you want to delete the user below?" -msgstr "以下のユーザーを削除してもよろしいですか?" - -#: client/src/partials/survey-maker-modal.html:13 -msgid "Are you sure you want to delete this {{deleteMode}}?" -msgstr "この {{deleteMode}} を削除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:25 -msgid "Are you sure you want to disassociate the group below from" -msgstr "以下のグループの関連付けを解除してもよろしいですか?" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:23 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:26 -msgid "Are you sure you want to disassociate the host below from" -msgstr "以下のホストの関連付けを解除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:47 -msgid "" -"Are you sure you want to permanently delete the group below from the " -"inventory?" -msgstr "インベントリーから以下のグループを完全に削除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js:106 -msgid "" -"Are you sure you want to permanently delete the host below from the " -"inventory?" -msgstr "インベントリーからホストを完全に削除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:69 -msgid "" -"Are you sure you want to permanently delete the inventory source below from " -"the inventory?" -msgstr "インベントリーから以下のインベントリーソースを完全に削除してもよろしいですか?" - -#: client/src/projects/edit/projects-edit.controller.js:244 -msgid "Are you sure you want to remove the %s below from %s?" -msgstr "%s から以下の %s を削除してもよろしいですか?" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:39 -msgid "Arguments" -msgstr "引数" - -#: client/src/credentials/credentials.form.js:232 -#: client/src/credentials/credentials.form.js:271 -#: client/src/credentials/credentials.form.js:311 -#: client/src/credentials/credentials.form.js:397 -msgid "Ask at runtime?" -msgstr "実行時に確認しますか?" - -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:69 -msgid "Associate an existing group" -msgstr "既存グループの関連付け" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:51 -msgid "Associate this host with a new group" -msgstr "新規グループへのこのホストの関連付け" - -#: client/src/shared/form-generator.js:1448 -msgid "Auditor" -msgstr "監査者" - -#: client/src/configuration/configuration.partial.html:15 -msgid "Authentication" -msgstr "認証" - -#: client/src/credentials/credentials.form.js:72 -msgid "" -"Authentication for network device access. This can include SSH keys, " -"usernames, passwords, and authorize information. Network credentials are " -"used when submitting jobs to run playbooks against network devices." -msgstr "" -"ネットワークデバイスアクセスの認証です。これには SSH " -"キー、ユーザー名、パスワードおよび認証情報が含まれることがあります。ネットワークの認証情報は、ジョブを送信し、ネットワークデバイスに対して " -"Playbook を実行する際に使用されます。" - -#: client/src/credentials/credentials.form.js:68 -msgid "" -"Authentication for remote machine access. This can include SSH keys, " -"usernames, passwords, and sudo information. Machine credentials are used " -"when submitting jobs to run playbooks against remote hosts." -msgstr "" -"リモートマシンアクセスの認証です。これには SSH キー、ユーザー名、パスワードおよび sudo " -"情報が含まれることがあります。マシンの認証情報は、ジョブを送信し、リモートホストに対して Playbook を実行する際に使用されます。" - -#: client/src/credentials/credentials.form.js:343 -msgid "Authorize" -msgstr "認証" - -#: client/src/credentials/credentials.form.js:351 -msgid "Authorize Password" -msgstr "認証パスワード" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:172 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "Availability Zone:" -msgstr "アベイラビリティーゾーン" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:106 -msgid "Azure AD" -msgstr "Azure AD" - -#: client/src/shared/directives.js:75 -msgid "BROWSE" -msgstr "参照" - -#: client/src/projects/projects.form.js:80 -msgid "" -"Base path used for locating playbooks. Directories found inside this path " -"will be listed in the playbook directory drop-down. Together the base path " -"and selected playbook directory provide the full path used to locate " -"playbooks." -msgstr "" -"Playbook を見つけるために使用されるベースパスです。このパス内にあるディレクトリーは Playbook " -"ディレクトリーのドロップダウンに一覧表示されます。ベースパスと選択された Playbook ディレクトリーは、Playbook " -"を見つけるために使用される完全なパスを提供します。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:128 -msgid "Become Privilege Escalation" -msgstr "Become (権限昇格)" - -#: client/src/license/license.partial.html:107 -msgid "Browse" -msgstr "参照" - -#: client/lib/services/base-string.service.js:61 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:28 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:73 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:16 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:16 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:16 -#: client/src/job-submission/job-submission.partial.html:370 -#: client/src/partials/survey-maker-modal.html:17 -#: client/src/partials/survey-maker-modal.html:85 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:17 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:65 -msgid "CANCEL" -msgstr "取り消し" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 -msgid "CHANGES" -msgstr "変更" - -#: client/src/shared/smart-search/smart-search.partial.html:30 -msgid "CLEAR ALL" -msgstr "すべてをクリア" - -#: client/src/partials/survey-maker-modal.html:86 -msgid "CLOSE" -msgstr "閉じる" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:19 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js:19 -#: client/src/templates/completed-jobs.list.js:20 -msgid "COMPLETED JOBS" -msgstr "完了したジョブ" - -#: client/src/configuration/configuration.partial.html:10 -msgid "CONFIGURE {{BRAND_NAME}}" -msgstr "{{BRAND_NAME}} の設定" - -#: client/src/shared/stateDefinitions.factory.js:157 -msgid "CREATE %s" -msgstr "%sの作成" - -#: client/features/credentials/credentials.strings.js:8 -#: client/src/credentials/credentials.form.js:16 -msgid "CREATE CREDENTIAL" -msgstr "認証情報の作成" - -#: client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:16 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:16 -msgid "CREATE GROUP" -msgstr "グループの作成" - -#: client/src/inventories-hosts/hosts/host.form.js:17 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:17 -#: client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:17 -msgid "CREATE HOST" -msgstr "ホストの作成" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js:8 -msgid "CREATE INVENTORY SOURCE" -msgstr "インベントリーソースの作成" - -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js:8 -#: client/src/scheduler/main.js:113 client/src/scheduler/main.js:206 -#: client/src/scheduler/main.js:290 -msgid "CREATE SCHEDULE" -msgstr "スケジュールの作成" - -#: client/src/management-jobs/scheduler/main.js:81 -msgid "CREATE SCHEDULED JOB" -msgstr "スケジュール済みジョブの作成" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:32 -msgid "CREATE SOURCE" -msgstr "ソースの作成" - -#: client/src/job-submission/job-submission.partial.html:351 -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:93 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:82 -msgid "CREDENTIAL" -msgstr "認証情報" - -#: client/src/credential-types/credential-types.form.js:21 -msgid "CREDENTIAL TYPE" -msgstr "認証情報タイプ" - -#: client/src/job-submission/job-submission.partial.html:92 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:56 -msgid "CREDENTIAL TYPE:" -msgstr "認証情報タイプ:" - -#: client/src/activity-stream/get-target-title.factory.js:11 -#: client/src/credential-types/credential-types.list.js:12 -#: client/src/credential-types/main.js:45 -msgid "CREDENTIAL TYPES" -msgstr "認証情報タイプ" - -#: client/features/credentials/legacy.credentials.js:14 -#: client/src/activity-stream/get-target-title.factory.js:17 -#: client/src/credentials/credentials.list.js:15 -#: client/src/credentials/credentials.list.js:16 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:5 -msgid "CREDENTIALS" -msgstr "認証情報" - -#: client/features/credentials/credentials.strings.js:28 -msgid "CREDENTIALS PERMISSIONS" -msgstr "認証情報のパーミッション" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:390 -#: client/src/projects/projects.form.js:199 -msgid "Cache Timeout" -msgstr "キャッシュタイムアウト" - -#: client/src/projects/projects.form.js:188 -msgid "Cache Timeout%s (seconds)%s" -msgstr "キャッシュタイムアウト%s (seconds)%s" - -#: client/src/projects/list/projects-list.controller.js:199 -#: client/src/users/list/users-list.controller.js:83 -msgid "Call to %s failed. DELETE returned status:" -msgstr "%s の呼び出しに失敗しました。DELETE で返されたステータス:" - -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:263 -msgid "Call to %s failed. GET status:" -msgstr "%s の呼び出しに失敗しました。GET ステータス:" - -#: client/src/projects/edit/projects-edit.controller.js:238 -msgid "Call to %s failed. POST returned status:" -msgstr "%s の呼び出しに失敗しました。POST で返されたステータス:" - -#: client/src/projects/list/projects-list.controller.js:225 -msgid "Call to %s failed. POST status:" -msgstr "%s の呼び出しに失敗しました。POST ステータス:" - -#: client/src/management-jobs/card/card.controller.js:29 -msgid "Call to %s failed. Return status: %d" -msgstr "%s の呼び出しが失敗しました。返されたステータス: %d" - -#: client/src/projects/list/projects-list.controller.js:272 -msgid "Call to get project failed. GET status:" -msgstr "プロジェクトを取得するための呼び出しに失敗しました。GET ステータス:" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:105 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:188 -#: client/src/configuration/configuration.controller.js:541 -#: client/src/job-results/job-results.partial.html:42 -#: client/src/jobs/factories/delete-job.factory.js:33 -#: client/src/shared/form-generator.js:1699 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:12 -#: client/src/workflow-results/workflow-results.partial.html:42 -msgid "Cancel" -msgstr "取り消し" - -#: client/src/job-results/job-results.service.js:142 -msgid "Cancel Job" -msgstr "ジョブの取り消し" - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "Cancel Not Allowed" -msgstr "取り消しは許可されていません" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:93 -msgid "Cancel sync process" -msgstr "同期プロセスの取り消し" - -#: client/src/projects/projects.list.js:124 -msgid "Cancel the SCM update" -msgstr "SCM 更新の取り消し" - -#: client/src/jobs/all-jobs.list.js:106 -msgid "Cancel the job" -msgstr "ジョブの取り消し" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:30 -#: client/src/projects/list/projects-list.controller.js:79 -msgid "Canceled. Click for details" -msgstr "取り消されました。クリックして詳細を確認してください。" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:91 -msgid "Cannot search running job" -msgstr "実行中のジョブを検索することはできません" - -#: client/src/instance-groups/instance-groups.list.js:22 -#: client/src/instance-groups/instances/instances.list.js:20 -msgid "Capacity" -msgstr "容量" - -#: client/src/projects/projects.form.js:82 -msgid "Change %s under \"Configure {{BRAND_NAME}}\" to change this location." -msgstr "この場所を変更するには「{{BRAND_NAME}} の設定」下の %s を変更します。" - -#: client/src/activity-stream/activity-detail.form.js:41 -msgid "Changes" -msgstr "変更" - -#: client/src/shared/form-generator.js:1071 -msgid "Choose a %s" -msgstr "%s の選択" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:64 -msgid "Choose an answer type" -msgstr "回答タイプの選択" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:67 -msgid "" -"Choose an answer type or format you want as the prompt for the user. Refer " -"to the Ansible Tower Documentation for more additional information about " -"each option." -msgstr "" -"ユーザーのプロンプトが表示される際に、必要な回答タイプを選択します。それぞれのオプションの詳細については、Ansible Tower " -"ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:112 -msgid "Choose an inventory file" -msgstr "インベントリーファイルの選択" - -#: client/src/shared/directives.js:76 -msgid "Choose file" -msgstr "ファイルの選択" - -#: client/src/license/license.partial.html:97 -msgid "" -"Choose your license file, agree to the End User License Agreement, and click" -" submit." -msgstr "ライセンスファイルを選択し、使用許諾契約書に同意した後に「送信」をクリックします。" - -#: client/src/projects/projects.form.js:156 -msgid "Clean" -msgstr "クリーニング" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:299 -msgid "Clear" -msgstr "消去" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:64 -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Click for details" -msgstr "クリックして詳細を確認してください。" - -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:63 -msgid "Click here to open the workflow graph editor." -msgstr "こちらをクリックしてワークフローグラフエディターを開きます。" - -#: client/src/inventories-hosts/inventories/inventory.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new inventory." -msgstr "行をクリックしてこれを選択し、終了したら「終了」をクリックします。%s ボタンをクリックして新規インベントリーを作成します。" - -#: client/src/teams/teams.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new team." -msgstr "行をクリックしてこれを選択し、終了したら「終了」をクリックします。%s ボタンをクリックして新規チームを作成します。" - -#: client/src/templates/templates.list.js:17 -msgid "" -"Click on a row to select it, and click Finished when done. Use the %s button" -" to create a new job template." -msgstr "行をクリックしてこれを選択し、終了したら「終了」をクリックします。%s ボタンをクリックして新規ジョブテンプレートを作成します。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:138 -msgid "" -"Click on the regions field to see a list of regions for your cloud provider." -" You can select multiple regions, or choose" -msgstr "リージョンフィールドをクリックして、クラウドプロバイダーの一覧を表示します。複数のリージョンを選択したり、以下を選択したりできます。" - -#: client/src/credentials/credentials.form.js:321 -msgid "Client ID" -msgstr "クライアント ID" - -#: client/src/notifications/notificationTemplates.form.js:254 -msgid "Client Identifier" -msgstr "クライアント識別子" - -#: client/src/credentials/credentials.form.js:330 -msgid "Client Secret" -msgstr "クライアントシークレット" - -#: client/src/shared/form-generator.js:1703 -msgid "Close" -msgstr "閉じる" - -#: client/src/job-results/job-results.partial.html:291 -msgid "Cloud Credential" -msgstr "クラウド認証情報" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:26 -msgid "Cloud source not configured." -msgstr "クラウドリソースは設定されていません。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "Cloud source not configured. Click" -msgstr "クラウドソースは設定されていません。以下をクリックします。" - -#: client/src/credentials/factories/become-method-change.factory.js:80 -#: client/src/credentials/factories/kind-change.factory.js:137 -msgid "CloudForms URL" -msgstr "CloudForms URL" - -#: client/src/job-results/job-results.controller.js:226 -#: client/src/standard-out/standard-out.controller.js:243 -#: client/src/workflow-results/workflow-results.controller.js:118 -msgid "Collapse Output" -msgstr "出力の縮小" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:13 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:21 -msgid "Completed Jobs" -msgstr "完了したジョブ" - -#: client/src/management-jobs/card/card.partial.html:34 -msgid "Configure Notifications" -msgstr "通知の設定" - -#: client/src/setup-menu/setup-menu.partial.html:60 -msgid "Configure {{BRAND_NAME}}" -msgstr "{{BRAND_NAME}} の設定" - -#: client/src/users/users.form.js:81 -msgid "Confirm Password" -msgstr "パスワードの確認" - -#: client/src/configuration/configuration.controller.js:548 -msgid "Confirm Reset" -msgstr "リセットの確認" - -#: client/src/configuration/configuration.controller.js:557 -msgid "Confirm factory reset" -msgstr "出荷時の設定へのリセットの確認" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:120 -msgid "" -"Confirm that you want to permanently delete the inventory source below from " -"the inventory. Deleting this inventory source also deletes its associated " -"groups and hosts." -msgstr "" -"インベントリーから以下のインベントリーソースを完全に削除してもよいかを確認します。このインベントリーソースを削除すると、それに関連付けられたグループおよびホストも削除されます。" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "Confirm the removal of the" -msgstr "以下の削除を確認:" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:134 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:149 -msgid "" -"Consult the Ansible documentation for further details on the usage of tags." -msgstr "タグの使用法についての詳細は、Ansible ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:18 -msgid "Contains 0 hosts." -msgstr "0 ホストが含まれています。" - -#: client/src/templates/job_templates/job-template.form.js:180 -msgid "" -"Control the level of output ansible will produce as the playbook executes." -msgstr "Playbook の実行時に Ansible が生成する出力のレベルを制御します。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:313 -msgid "" -"Control the level of output ansible will produce for inventory source update" -" jobs." -msgstr "インベントリーソースの更新ジョブ用に Ansible が生成する出力のレベルを制御します。" - -#: client/lib/components/components.strings.js:48 -msgid "Copied to clipboard." -msgstr "クリップボードにコピーしました。" - -#: client/src/templates/templates.list.js:95 -msgid "Copy" -msgstr "コピー" - -#: client/lib/components/components.strings.js:47 -msgid "Copy full revision to clipboard." -msgstr "完全なリビジョンをクリップボードにコピーします。" - -#: client/src/templates/templates.list.js:98 -msgid "Copy template" -msgstr "テンプレートのコピー" - -#: client/src/about/about.partial.html:27 -msgid "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Visit Ansible.com for more information.
" -msgstr "" -"Copyright © 2017 Red Hat, Inc.
\n" -" 詳細は、 Ansible.com をご覧ください。
" - -#: client/src/users/users.list.js:44 -msgid "Create New" -msgstr "新規作成" - -#: client/src/credentials/credentials.list.js:52 -msgid "Create a new credential" -msgstr "新規認証情報の作成" - -#: client/src/credential-types/credential-types.list.js:42 -msgid "Create a new credential type" -msgstr "新規認証情報タイプの作成" - -#: client/src/inventory-scripts/inventory-scripts.list.js:40 -msgid "Create a new custom inventory" -msgstr "新規カスタムインベントリーの作成" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:69 -msgid "Create a new group" -msgstr "新規グループの作成" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:123 -msgid "Create a new host" -msgstr "新規ホストの作成" - -#: client/src/inventories-hosts/inventories/inventory.list.js:75 -msgid "Create a new inventory" -msgstr "新規インベントリーの作成" - -#: client/src/notifications/notificationTemplates.list.js:52 -msgid "Create a new notification template" -msgstr "新規通知テンプレートの作成" - -#: client/src/organizations/list/organizations-list.partial.html:21 -msgid "Create a new organization" -msgstr "新規組織の作成" - -#: client/src/projects/projects.list.js:76 -msgid "Create a new project" -msgstr "新規プロジェクトの作成" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:68 -msgid "Create a new source" -msgstr "新規ソースの作成" - -#: client/src/teams/teams.list.js:43 -msgid "Create a new team" -msgstr "新規チームの作成" - -#: client/src/templates/templates.list.js:56 -msgid "Create a new template" -msgstr "新規テンプレートの作成" - -#: client/src/users/users.list.js:48 -msgid "Create a new user" -msgstr "新規ユーザーの作成" - -#: client/src/setup-menu/setup-menu.partial.html:42 -msgid "Create and edit scripts to dynamically load hosts from any source." -msgstr "任意のソースからホストを動的にロードするためのスクリプトを作成し、編集します。" - -#: client/src/setup-menu/setup-menu.partial.html:30 -msgid "" -"Create custom credential types to be used for authenticating to network " -"hosts and cloud sources" -msgstr "ネットワークホストおよびクラウドソースに対する認証に使用されるカスタム認証情報タイプを作成します。" - -#: client/src/setup-menu/setup-menu.partial.html:49 -msgid "" -"Create templates for sending notifications with Email, HipChat, Slack, and " -"SMS." -msgstr "メール、HipChat、Slack、および SMS での通知を送信するためのテンプレートを作成します。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:72 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:74 -#: client/src/job-submission/job-submission.partial.html:18 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:67 -#: client/src/templates/job_templates/job-template.form.js:121 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:53 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:62 -msgid "Credential" -msgstr "認証情報" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:32 -#: client/src/setup-menu/setup-menu.partial.html:29 -msgid "Credential Types" -msgstr "認証情報タイプ" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:129 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:58 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 -#: client/src/setup-menu/setup-menu.partial.html:22 -#: client/src/templates/job_templates/job-template.form.js:134 -msgid "Credentials" -msgstr "認証情報" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:17 -msgid "Critical" -msgstr "重大" - -#: client/src/shared/directives.js:77 -msgid "Current Image:" -msgstr "現在のイメージ:" - -#: client/src/job-results/job-results.controller.js:271 -msgid "Currently following standard out as it comes in. Click to unfollow." -msgstr "現在、受信時の標準出力をフォローしています。クリックしてフォローを解除します。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:171 -msgid "Custom Inventory Script" -msgstr "カスタムインベントリースクリプト" - -#: client/src/inventory-scripts/inventory-scripts.form.js:50 -#: client/src/inventory-scripts/inventory-scripts.form.js:60 -msgid "Custom Script" -msgstr "カスタムスクリプト" - -#: client/src/home/home.route.js:21 -msgid "DASHBOARD" -msgstr "ダッシュボード" - -#: client/src/credentials/list/credentials-list.controller.js:135 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:103 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:52 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:74 -#: client/src/job-results/job-results.service.js:119 -#: client/src/jobs/factories/delete-job.factory.js:115 -#: client/src/notifications/notification-templates-list/list.controller.js:195 -#: client/src/organizations/list/organizations-list.controller.js:174 -#: client/src/partials/survey-maker-modal.html:18 -#: client/src/projects/edit/projects-edit.controller.js:246 -#: client/src/templates/list/templates-list.controller.js:154 -#: client/src/users/list/users-list.controller.js:92 -msgid "DELETE" -msgstr "削除" - -#: client/src/partials/survey-maker-modal.html:84 -msgid "DELETE SURVEY" -msgstr "Survey の削除" - -#: client/src/job-results/job-results.partial.html:16 -msgid "DETAILS" -msgstr "詳細" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:31 -msgid "DISASSOCIATE" -msgstr "関連付けの解除" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:5 -msgid "DYNAMIC HOSTS" -msgstr "動的ホスト" - -#: client/src/credential-types/credential-types.list.js:73 -#: client/src/credentials/credentials.list.js:85 -#: client/src/credentials/list/credentials-list.controller.js:132 -#: client/src/inventories-hosts/inventories/inventory.list.js:111 -#: client/src/inventory-scripts/inventory-scripts.list.js:71 -#: client/src/job-results/job-results.partial.html:54 -#: client/src/jobs/factories/delete-job.factory.js:37 -#: client/src/notifications/notification-templates-list/list.controller.js:192 -#: client/src/notifications/notificationTemplates.list.js:91 -#: client/src/organizations/list/organizations-list.controller.js:171 -#: client/src/projects/edit/projects-edit.controller.js:243 -#: client/src/projects/list/projects-list.controller.js:207 -#: client/src/scheduler/schedules.list.js:90 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:13 -#: client/src/teams/teams.list.js:72 -#: client/src/templates/list/templates-list.controller.js:102 -#: client/src/templates/templates.list.js:120 -#: client/src/users/list/users-list.controller.js:89 -#: client/src/users/users.list.js:79 -#: client/src/workflow-results/workflow-results.partial.html:54 -msgid "Delete" -msgstr "削除" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:6 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:6 -msgid "Delete Group" -msgstr "グループの削除" - -#: client/src/job-results/job-results.service.js:93 -msgid "Delete Job" -msgstr "ジョブの削除" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:175 -msgid "Delete Source" -msgstr "ソースの削除" - -#: client/src/credentials/credentials.list.js:87 -msgid "Delete credential" -msgstr "認証情報の削除" - -#: client/src/credential-types/credential-types.list.js:75 -msgid "Delete credential type" -msgstr "認証情報タイプの削除" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:101 -#: client/src/inventories-hosts/inventory-hosts.strings.js:19 -msgid "Delete group" -msgid_plural "Delete groups" -msgstr[0] "グループの削除" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:48 -msgid "Delete groups" -msgstr "グループの削除" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:37 -msgid "Delete groups and hosts" -msgstr "グループおよびホストの削除" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:100 -#: client/src/inventories-hosts/inventory-hosts.strings.js:21 -msgid "Delete host" -msgid_plural "Delete hosts" -msgstr[0] "ホストの削除" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:59 -msgid "Delete hosts" -msgstr "ホストの削除" - -#: client/src/inventories-hosts/inventories/inventory.list.js:113 -msgid "Delete inventory" -msgstr "インベントリーの削除" - -#: client/src/inventory-scripts/inventory-scripts.list.js:73 -msgid "Delete inventory script" -msgstr "インベントリースクリプトの削除" - -#: client/src/notifications/notificationTemplates.list.js:93 -msgid "Delete notification" -msgstr "通知の削除" - -#: client/src/projects/projects.form.js:166 -msgid "Delete on Update" -msgstr "更新時の削除" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:27 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:27 -msgid "Delete or promote the group's children?" -msgstr "グループの子を削除またはプロモートしますか?" - -#: client/src/scheduler/schedules.list.js:93 -msgid "Delete schedule" -msgstr "スケジュールの削除" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:125 -msgid "Delete source" -msgstr "ソースの削除" - -#: client/src/teams/teams.list.js:76 -msgid "Delete team" -msgstr "チームの削除" - -#: client/src/templates/templates.list.js:123 -msgid "Delete template" -msgstr "テンプレートの削除" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:84 -#: client/src/jobs/all-jobs.list.js:113 -#: client/src/templates/completed-jobs.list.js:85 -msgid "Delete the job" -msgstr "ジョブの削除" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Delete the local repository in its entirety prior to performing an update." -msgstr "更新の実行前にローカルリポジトリーを完全に削除します。" - -#: client/src/projects/projects.list.js:118 -msgid "Delete the project" -msgstr "プロジェクトの削除" - -#: client/src/scheduler/scheduled-jobs.list.js:81 -msgid "Delete the schedule" -msgstr "スケジュールの削除" - -#: client/src/users/users.list.js:83 -msgid "Delete user" -msgstr "ユーザーの削除" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:14 -msgid "Delete {{ group }} and {{ host }}" -msgstr "{{ group }} および {{ host }} の削除" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:23 -msgid "Deleting group" -msgstr "グループを削除しています" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Depending on the size of the repository this may significantly increase the " -"amount of time required to complete an update." -msgstr "リポジトリーのサイズにより、更新の完了までに必要な時間が大幅に長くなる可能性があります。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "Describe Instances documentation" -msgstr "インスタンスの概要ドキュメント" - -#: client/src/credential-types/credential-types.form.js:34 -#: client/src/credentials/credentials.form.js:39 -#: client/src/inventories-hosts/hosts/host.form.js:63 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:39 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:62 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:62 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:58 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:46 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:53 -#: client/src/inventory-scripts/inventory-scripts.form.js:35 -#: client/src/notifications/notificationTemplates.form.js:39 -#: client/src/organizations/organizations.form.js:33 -#: client/src/projects/projects.form.js:36 client/src/teams/teams.form.js:32 -#: client/src/templates/job_templates/job-template.form.js:41 -#: client/src/templates/survey-maker/shared/question-definition.form.js:36 -#: client/src/templates/workflows.form.js:39 -#: client/src/users/users.form.js:145 client/src/users/users.form.js:171 -msgid "Description" -msgstr "説明" - -#: client/src/notifications/notificationTemplates.form.js:136 -#: client/src/notifications/notificationTemplates.form.js:140 -#: client/src/notifications/notificationTemplates.form.js:152 -#: client/src/notifications/notificationTemplates.form.js:156 -msgid "Destination Channels" -msgstr "送信先チャネル" - -#: client/src/notifications/notificationTemplates.form.js:359 -#: client/src/notifications/notificationTemplates.form.js:363 -msgid "Destination Channels or Users" -msgstr "送信先チャネルまたはユーザー" - -#: client/src/notifications/notificationTemplates.form.js:205 -#: client/src/notifications/notificationTemplates.form.js:206 -msgid "Destination SMS Number" -msgstr "送信先 SMS 番号" - -#: client/features/credentials/credentials.strings.js:13 -#: client/src/license/license.partial.html:5 -#: client/src/shared/form-generator.js:1481 -msgid "Details" -msgstr "詳細" - -#: client/src/job-submission/job-submission.partial.html:263 -msgid "Diff Mode" -msgstr "差分モード" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Group From Group" -msgstr "グループの他のグループとの関連付けを解除" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:6 -msgid "Disassociate Host" -msgstr "ホストの関連付けの解除" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:6 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Host From Group" -msgstr "ホストのグループとの関連付けを解除" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:65 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:110 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:98 -msgid "Disassociate group" -msgstr "グループの関連付けの解除" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:87 -msgid "Disassociate host" -msgstr "ホストの関連付けの解除" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:75 -#: client/src/configuration/configuration.controller.js:202 -#: client/src/configuration/configuration.controller.js:264 -#: client/src/configuration/system-form/configuration-system.controller.js:57 -msgid "Discard changes" -msgstr "変更の破棄" - -#: client/src/teams/teams.form.js:146 -msgid "Dissasociate permission from team" -msgstr "チームからパーミッションの関連付けを解除" - -#: client/src/users/users.form.js:225 -msgid "Dissasociate permission from user" -msgstr "ユーザーからパーミッションの関連付けを解除" - -#: client/src/credentials/credentials.form.js:384 -#: client/src/credentials/factories/become-method-change.factory.js:54 -#: client/src/credentials/factories/kind-change.factory.js:111 -msgid "Domain Name" -msgstr "ドメイン名" - -#: client/src/job-results/job-results.controller.js:15 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:134 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:141 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:102 -msgid "Download Output" -msgstr "出力のダウンロード" - -#: client/src/inventory-scripts/inventory-scripts.form.js:59 -msgid "" -"Drag and drop your custom inventory script file here or create one in the " -"field to import your custom inventory. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"カスタムインベントリーのスクリプトファイルをここにドラッグアンドドロップするか、またはこのフィールドにカスタムインベントリーをインポートするためのファイルを作成します。構文のサンプルについては、Ansible" -" Tower ドキュメントを参照してください。" - -#: client/src/partials/survey-maker-modal.html:77 -msgid "Drop question here to reorder" -msgstr "並び替える質問をドロップ" - -#: client/src/configuration/configuration.route.js:30 -msgid "EDIT CONFIGURATION" -msgstr "設定の編集" - -#: client/features/credentials/credentials.strings.js:9 -msgid "EDIT CREDENTIAL" -msgstr "認証情報の編集" - -#: client/src/management-jobs/scheduler/main.js:95 -msgid "EDIT SCHEDULED JOB" -msgstr "スケジュール済みジョブの編集" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:17 -msgid "EDIT SURVEY PROMPT" -msgstr "Survey プロンプトの編集" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:46 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:79 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:59 -msgid "ELAPSED" -msgstr "経過時間" - -#: client/lib/components/components.strings.js:9 -msgid "ENCRYPTED" -msgstr "暗号化" - -#: client/src/shared/smart-search/smart-search.partial.html:39 -msgid "EXAMPLES:" -msgstr "例:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:15 -msgid "EXECUTE COMMAND" -msgstr "コマンドの実行" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:46 -msgid "EXPLANATION" -msgstr "説明" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:355 -msgid "" -"Each time a job runs using this inventory, refresh the inventory from the " -"selected source before executing job tasks." -msgstr "このインベントリーでジョブを実行する際は常に、選択されたソースのインベントリーを更新してからジョブのタスクを実行します。" - -#: client/src/projects/projects.form.js:179 -msgid "" -"Each time a job runs using this project, perform an update to the local " -"repository prior to starting the job." -msgstr "このプロジェクトでジョブを実行する際は常に、ジョブの開始前にローカルリポジトリーに対して更新を実行します。" - -#: client/src/credential-types/credential-types.list.js:56 -#: client/src/credentials/credentials.list.js:66 -#: client/src/inventories-hosts/inventories/inventory.list.js:97 -#: client/src/inventory-scripts/inventory-scripts.list.js:54 -#: client/src/notifications/notificationTemplates.list.js:65 -#: client/src/notifications/notificationTemplates.list.js:74 -#: client/src/scheduler/schedules.list.js:75 client/src/teams/teams.list.js:55 -#: client/src/templates/templates.list.js:103 -#: client/src/users/users.list.js:60 -msgid "Edit" -msgstr "編集" - -#: client/src/shared/form-generator.js:1715 -#: client/src/templates/job_templates/job-template.form.js:452 -#: client/src/templates/workflows.form.js:177 -msgid "Edit Survey" -msgstr "Survey の編集" - -#: client/src/credential-types/credential-types.list.js:58 -msgid "Edit credenital type" -msgstr "認証情報タイプの編集" - -#: client/src/credentials/credentials.list.js:68 -msgid "Edit credential" -msgstr "認証情報の編集" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:85 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:96 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:84 -msgid "Edit group" -msgstr "グループの編集" - -#: client/src/inventories-hosts/hosts/host.list.js:83 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:73 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:87 -msgid "Edit host" -msgstr "ホストの編集" - -#: client/src/inventories-hosts/inventories/inventory.list.js:99 -msgid "Edit inventory" -msgstr "インベントリーの編集" - -#: client/src/inventory-scripts/inventory-scripts.list.js:56 -msgid "Edit inventory script" -msgstr "インベントリースクリプトの編集" - -#: client/src/notifications/notificationTemplates.list.js:76 -msgid "Edit notification" -msgstr "通知の編集" - -#: client/src/scheduler/schedules.list.js:78 -msgid "Edit schedule" -msgstr "スケジュールの編集" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:111 -msgid "Edit source" -msgstr "ソースの編集" - -#: client/src/teams/teams.list.js:59 -msgid "Edit team" -msgstr "チームの編集" - -#: client/src/templates/templates.list.js:105 -msgid "Edit template" -msgstr "テンプレートの編集" - -#: client/src/job-results/job-results.partial.html:191 -msgid "Edit the Schedule" -msgstr "スケジュールの編集" - -#: client/src/job-results/job-results.partial.html:175 -#: client/src/workflow-results/workflow-results.partial.html:124 -msgid "Edit the User" -msgstr "ユーザーの編集" - -#: client/src/job-results/job-results.partial.html:265 -#: client/src/job-results/job-results.partial.html:280 -#: client/src/job-results/job-results.partial.html:296 -#: client/src/job-results/job-results.partial.html:311 -#: client/src/job-results/job-results.partial.html:326 -msgid "Edit the credential" -msgstr "認証情報の編集" - -#: client/src/job-results/job-results.partial.html:206 -msgid "Edit the inventory" -msgstr "インベントリーの編集" - -#: client/src/job-results/job-results.partial.html:140 -msgid "Edit the job template" -msgstr "ジョブテンプレートの編集" - -#: client/src/job-results/job-results.partial.html:229 -#: client/src/projects/projects.list.js:105 -msgid "Edit the project" -msgstr "プロジェクトの編集" - -#: client/src/scheduler/scheduled-jobs.list.js:67 -msgid "Edit the schedule" -msgstr "スケジュールの編集" - -#: client/src/users/users.list.js:64 -msgid "Edit user" -msgstr "ユーザーの編集" - -#: client/src/setup-menu/setup-menu.partial.html:61 -msgid "Edit {{BRAND_NAME}}'s configuration." -msgstr "{{BRAND_NAME}} の設定を編集します。" - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "" -"Either you do not have access or the SCM update process completed. Click the" -" %sRefresh%s button to view the latest status." -msgstr "アクセスがないか、または SCM 更新プロセスが完了しました。%s更新%s ボタンをクリックして最新のステータスを表示します。" - -#: client/src/job-results/job-results.partial.html:520 -msgid "Elapsed" -msgstr "経過時間" - -#: client/src/credentials/credentials.form.js:191 -#: client/src/users/users.form.js:51 -msgid "Email" -msgstr "メール" - -#: client/src/templates/job_templates/job-template.form.js:288 -#: client/src/templates/job_templates/job-template.form.js:293 -msgid "Enable Concurrent Jobs" -msgstr "同時実行ジョブの有効化" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:123 -#: client/src/templates/job_templates/job-template.form.js:264 -#: client/src/templates/job_templates/job-template.form.js:269 -msgid "Enable Privilege Escalation" -msgstr "権限昇格の有効化" - -#: client/src/templates/job_templates/job-template.form.js:279 -msgid "" -"Enables creation of a provisioning callback URL. Using the URL a host can " -"contact {{BRAND_NAME}} and request a configuration update using this job " -"template." -msgstr "" -"プロビジョニングコールバック URL の作成を有効にします。この URL を使用してホストは {{BRAND_NAME}} " -"に接続でき、このジョブテンプレートを使用して設定の更新を要求できます。" - -#: client/src/credentials/factories/credential-form-save.factory.js:73 -msgid "Encrypted credentials are not supported." -msgstr "暗号化された認証情報はサポートされていません。" - -#: client/src/license/license.partial.html:113 -msgid "End User License Agreement" -msgstr "使用許諾契約書" - -#: client/src/inventories-hosts/hosts/host.form.js:73 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:72 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:86 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two." -msgstr "" -"JSON または YAML 構文のいずれかを使用してインベントリー変数を入力します。ラジオボタンを使用して 2 つの間の切り替えを行います。" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:93 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two. Refer to the Ansible Tower documentation " -"for example syntax." -msgstr "" -"JSON または YAML " -"構文のいずれかを使用してインベントリー変数を入力します。ラジオボタンを使用してこれらの間で切り替えを行います。構文のサンプルについては Ansible " -"Tower ドキュメントを参照してください。" - -#: client/src/notifications/notificationTemplates.form.js:155 -msgid "" -"Enter one HipChat channel per line. The pound symbol (#) is not required." -msgstr "各行に 1 つの HipChat チャンネルを入力します。シャープ記号 (#) は不要です。" - -#: client/src/notifications/notificationTemplates.form.js:362 -msgid "" -"Enter one IRC channel or username per line. The pound symbol (#) for " -"channels, and the at (@) symbol for users, are not required." -msgstr "" -"各行に 1 つの IRC チャンネルまたはユーザー名を入力します。チャンネルのシャープ記号 (#) およびユーザーのアットマーク (@) " -"記号は不要です。" - -#: client/src/notifications/notificationTemplates.form.js:139 -msgid "" -"Enter one Slack channel per line. The pound symbol (#) is not required." -msgstr "各行に 1 つの Slack チャンネルを入力します。シャープ記号 (#) は不要です。" - -#: client/src/notifications/notificationTemplates.form.js:97 -msgid "" -"Enter one email address per line to create a recipient list for this type of" -" notification." -msgstr "各行に 1 つのメールアドレスを入力し、この通知タイプの受信者リストを作成します。" - -#: client/src/notifications/notificationTemplates.form.js:209 -msgid "" -"Enter one phone number per line to specify where to route SMS messages." -msgstr "各行に 1 つの電話番号を入力し、SMS メッセージのルート先を指定します。" - -#: client/src/credentials/factories/become-method-change.factory.js:81 -#: client/src/credentials/factories/kind-change.factory.js:138 -msgid "" -"Enter the URL for the virtual machine which %scorresponds to your CloudForm " -"instance. %sFor example, %s" -msgstr "CloudForms インスタンスに対応する %s仮想マシンの URL を入力します (%s例: %s)。" - -#: client/src/credentials/factories/become-method-change.factory.js:71 -#: client/src/credentials/factories/kind-change.factory.js:128 -msgid "" -"Enter the URL which corresponds to your %sRed Hat Satellite 6 server. %sFor " -"example, %s" -msgstr "Red Hat Satellite 6 Server に対応する %sURL を入力します (%s例: %s)。" - -#: client/src/credentials/factories/become-method-change.factory.js:49 -#: client/src/credentials/factories/kind-change.factory.js:106 -msgid "" -"Enter the hostname or IP address which corresponds to your VMware vCenter." -msgstr "VMware vCenter に対応するホスト名または IP アドレスを入力します。" - -#: client/src/notifications/notificationTemplates.form.js:195 -msgid "" -"Enter the number associated with the \"Messaging Service\" in Twilio in the " -"format +18005550199." -msgstr "Twilio の \"メッセージングサービス\" に関連付けられた番号を入力します (形式: +18005550199)。 " - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:197 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:221 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:245 -msgid "" -"Enter variables using either JSON or YAML syntax. Use the radio button to " -"toggle between the two." -msgstr "JSON または YAML 構文のいずれかを使用して変数を入力します。ラジオボタンを使用して 2 つの間の切り替えを行います。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:187 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:194 -msgid "Environment Variables" -msgstr "環境変数" - -#: client/src/configuration/configuration.controller.js:348 -#: client/src/configuration/configuration.controller.js:449 -#: client/src/configuration/configuration.controller.js:483 -#: client/src/configuration/configuration.controller.js:530 -#: client/src/configuration/system-form/configuration-system.controller.js:231 -#: client/src/credentials/factories/credential-form-save.factory.js:77 -#: client/src/credentials/factories/credential-form-save.factory.js:93 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:129 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:139 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:166 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:194 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:213 -#: client/src/management-jobs/card/card.controller.js:140 -#: client/src/management-jobs/card/card.controller.js:230 -#: client/src/management-jobs/card/card.controller.js:28 -#: client/src/projects/add/projects-add.controller.js:108 -#: client/src/projects/edit/projects-edit.controller.js:156 -#: client/src/projects/edit/projects-edit.controller.js:222 -#: client/src/projects/edit/projects-edit.controller.js:238 -#: client/src/projects/list/projects-list.controller.js:169 -#: client/src/projects/list/projects-list.controller.js:198 -#: client/src/projects/list/projects-list.controller.js:225 -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:262 -#: client/src/projects/list/projects-list.controller.js:271 -#: client/src/users/add/users-add.controller.js:99 -#: client/src/users/edit/users-edit.controller.js:180 -#: client/src/users/edit/users-edit.controller.js:80 -#: client/src/users/list/users-list.controller.js:82 -msgid "Error!" -msgstr "エラー!" - -#: client/src/activity-stream/streams.list.js:40 -msgid "Event" -msgstr "イベント" - -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Event ID" -msgstr "イベント ID" - -#: client/src/activity-stream/factories/build-description.factory.js:120 -msgid "Event summary not available" -msgstr "イベントの概要はありません" - -#: client/src/projects/add/projects-add.controller.js:129 -#: client/src/projects/edit/projects-edit.controller.js:265 -msgid "Example URLs for GIT SCM include:" -msgstr "GIT SCM のサンプル URL には以下が含まれます:" - -#: client/src/projects/add/projects-add.controller.js:150 -#: client/src/projects/edit/projects-edit.controller.js:285 -msgid "Example URLs for Mercurial SCM include:" -msgstr "Mercurial SCM のサンプル URL には以下が含まれます:" - -#: client/src/projects/add/projects-add.controller.js:141 -#: client/src/projects/edit/projects-edit.controller.js:276 -msgid "Example URLs for Subversion SCM include:" -msgstr "Subversion SCM のサンプル URL には以下が含まれます:" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Example: ansible_facts.ansible_distribution:\"RedHat\"" -msgstr "例: ansible_facts.ansible_distribution:\"RedHat\"" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:76 -msgid "Existing Group" -msgstr "既存グループ" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:125 -msgid "Existing Host" -msgstr "既存ホスト" - -#: client/src/job-results/job-results.controller.js:18 -#: client/src/job-results/job-results.controller.js:228 -#: client/src/standard-out/standard-out.controller.js:24 -#: client/src/standard-out/standard-out.controller.js:245 -#: client/src/workflow-results/workflow-results.controller.js:120 -#: client/src/workflow-results/workflow-results.controller.js:76 -msgid "Expand Output" -msgstr "出力の展開" - -#: client/src/license/license.partial.html:39 -msgid "Expires On" -msgstr "有効期限" - -#: client/src/job-results/job-results.partial.html:81 -msgid "Explanation" -msgstr "説明" - -#: client/src/job-results/job-results.partial.html:275 -msgid "Extra Credentials" -msgstr "追加の認証情報" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:132 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:144 -#: client/src/job-results/job-results.partial.html:409 -#: client/src/job-submission/job-submission.partial.html:165 -#: client/src/partials/logviewer.html:8 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:105 -#: client/src/templates/job_templates/job-template.form.js:342 -#: client/src/templates/job_templates/job-template.form.js:349 -#: client/src/templates/workflows.form.js:74 -#: client/src/templates/workflows.form.js:81 -msgid "Extra Variables" -msgstr "追加変数" - -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html:4 -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js:7 -msgid "FACTS" -msgstr "ファクト" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:64 -msgid "FAILED" -msgstr "失敗" - -#: client/src/shared/smart-search/smart-search.partial.html:45 -msgid "FIELDS:" -msgstr "フィールド:" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:39 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:72 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:52 -msgid "FINISHED" -msgstr "完了" - -#: client/src/inventories-hosts/hosts/host.form.js:107 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:106 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:107 -msgid "Facts" -msgstr "ファクト" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:80 -msgid "Failed" -msgstr "失敗" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:44 -msgid "Failed Hosts" -msgstr "失敗したホスト" - -#: client/src/users/add/users-add.controller.js:99 -msgid "Failed to add new user. POST returned status:" -msgstr "新規ユーザーを追加できませんでした。POST で返されたステータス:" - -#: client/src/credentials/factories/credential-form-save.factory.js:78 -msgid "Failed to create new Credential. POST status:" -msgstr "新規の認証情報を作成できませんでした。POST ステータス:" - -#: client/src/projects/add/projects-add.controller.js:109 -msgid "Failed to create new project. POST returned status:" -msgstr "新規プロジェクトを作成できませんでした。POST で返されたステータス:" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:214 -msgid "Failed to retrieve job template extra variables." -msgstr "ジョブテンプレートの追加変数を取得できませんでした。" - -#: client/src/projects/edit/projects-edit.controller.js:157 -msgid "Failed to retrieve project: %s. GET status:" -msgstr "プロジェクトを取得できませんでした: %s. GET ステータス:" - -#: client/src/users/edit/users-edit.controller.js:181 -#: client/src/users/edit/users-edit.controller.js:81 -msgid "Failed to retrieve user: %s. GET status:" -msgstr "ユーザーを取得できませんでした: %s. GET ステータス:" - -#: client/src/configuration/configuration.controller.js:450 -msgid "Failed to save settings. Returned status:" -msgstr "設定を保存できませんでした。返されたステータス:" - -#: client/src/configuration/configuration.controller.js:484 -msgid "Failed to save toggle settings. Returned status:" -msgstr "トグルの設定を保存できませんでした。返されたステータス:" - -#: client/src/credentials/factories/credential-form-save.factory.js:94 -msgid "Failed to update Credential. PUT status:" -msgstr "認証情報を更新できませんでした。PUT ステータス:" - -#: client/src/projects/edit/projects-edit.controller.js:222 -msgid "Failed to update project: %s. PUT status:" -msgstr "プロジェクトを更新できませんでした: %s. PUT ステータス:" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:195 -#: client/src/management-jobs/card/card.controller.js:141 -#: client/src/management-jobs/card/card.controller.js:231 -msgid "Failed updating job %s with variables. POST returned: %d" -msgstr "変数でジョブ %s を更新できませんでした。POST で返されたステータス: %d" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:24 -msgid "Failed. Click for details" -msgstr "失敗しました。クリックして詳細を確認してください。" - -#: client/src/notifications/notifications.list.js:48 -msgid "Failure" -msgstr "失敗" - -#: client/src/scheduler/schedules.list.js:48 -msgid "Final Run" -msgstr "最終実行日時" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:59 -#: client/src/instance-groups/jobs/jobs.list.js:57 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:54 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:58 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:44 -#: client/src/job-results/job-results.partial.html:111 -#: client/src/jobs/all-jobs.list.js:66 -#: client/src/portal-mode/portal-jobs.list.js:40 -#: client/src/templates/completed-jobs.list.js:59 -msgid "Finished" -msgstr "終了日時" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:21 -#: client/src/users/users.form.js:26 client/src/users/users.list.js:33 -msgid "First Name" -msgstr "名" - -#: client/src/scheduler/schedules.list.js:38 -msgid "First Run" -msgstr "初回実行日時" - -#: client/src/shared/smart-search/smart-search.partial.html:52 -msgid "" -"For additional information on advanced search search syntax please see the " -"Ansible Tower" -msgstr "詳細検索の検索構文についての詳細は、Ansible Tower ドキュメントを参照してください。" - -#: client/src/credentials/factories/become-method-change.factory.js:63 -#: client/src/credentials/factories/kind-change.factory.js:120 -msgid "For example, %s" -msgstr "例: %s" - -#: client/src/inventories-hosts/hosts/host.form.js:36 -#: client/src/inventories-hosts/hosts/host.list.js:36 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:35 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:32 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:35 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:31 -msgid "" -"For hosts that are part of an external inventory, this flag cannot be " -"changed. It will be set by the inventory sync process." -msgstr "外部インベントリーの一部であるホストの場合、このフラグを変更できません。これはインベントリー同期プロセスで設定されます。" - -#: client/src/templates/job_templates/job-template.form.js:54 -msgid "" -"For job templates, select run to execute the playbook. Select check to only " -"check playbook syntax, test environment setup, and report problems without " -"executing the playbook." -msgstr "" -"ジョブテンプレートについて、Playbook を実行するために実行を選択します。Playbook を実行せずに、Playbook " -"構文、テスト環境セットアップおよびレポートの問題のみを検査するチェックを選択します。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:118 -msgid "" -"For more information and examples see %sthe Patterns topic at " -"docs.ansible.com%s." -msgstr "詳細情報およびサンプルについては、docs.ansible.com の %sパターンのトピック%sを参照してください。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:109 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:96 -#: client/src/job-results/job-results.partial.html:336 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:87 -#: client/src/templates/job_templates/job-template.form.js:144 -#: client/src/templates/job_templates/job-template.form.js:154 -msgid "Forks" -msgstr "フォーク" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:172 -msgid "Frequency Details" -msgstr "頻度の詳細" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js:45 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js:46 -msgid "GROUPS" -msgstr "グループ" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:107 -msgid "GitHub" -msgstr "GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:108 -msgid "GitHub Org" -msgstr "GitHub 組織" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:109 -msgid "GitHub Team" -msgstr "GitHub チーム" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:110 -msgid "Google OAuth2" -msgstr "Google OAuth2" - -#: client/src/teams/teams.form.js:155 client/src/users/users.form.js:214 -msgid "Grant Permission" -msgstr "パーミッションの付与" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Gray" -msgstr "灰色" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Green" -msgstr "緑" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:52 -msgid "Group Variables" -msgstr "グループ変数" - -#: client/src/setup-menu/setup-menu.partial.html:5 -msgid "" -"Group all of your content to manage permissions across departments in your " -"company." -msgstr "会社内の複数の部署のパーミッションを管理するためにすべてのコンテンツを分類します。" - -#: client/src/inventories-hosts/hosts/host.form.js:115 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:31 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:89 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:88 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:115 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:167 -msgid "Groups" -msgstr "グループ" - -#: client/lib/components/components.strings.js:12 -msgid "HIDE" -msgstr "非表示" - -#: client/lib/components/components.strings.js:39 -msgid "HINT: Drag and drop an SSH private key file on the field below." -msgstr "ヒント: 以下のフィールドに SSH 秘密鍵ファイルをドラッグアンドドロップします。" - -#: client/src/activity-stream/get-target-title.factory.js:41 -#: client/src/inventories-hosts/hosts/hosts.partial.html:9 -#: client/src/inventories-hosts/hosts/main.js:80 -#: client/src/inventories-hosts/inventories/inventories.partial.html:14 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.route.js:18 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js:17 -msgid "HOSTS" -msgstr "ホスト" - -#: client/src/notifications/notificationTemplates.form.js:320 -#: client/src/notifications/notificationTemplates.form.js:321 -msgid "HTTP Headers" -msgstr "HTTP ヘッダー" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "Hide Activity Stream" -msgstr "アクティビティーストリームの非表示" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:23 -msgid "High" -msgstr "高" - -#: client/src/credentials/credentials.form.js:139 -#: client/src/notifications/notificationTemplates.form.js:83 -msgid "Host" -msgstr "ホスト" - -#: client/src/credentials/factories/become-method-change.factory.js:52 -#: client/src/credentials/factories/kind-change.factory.js:109 -msgid "Host (Authentication URL)" -msgstr "ホスト (認証 URL)" - -#: client/src/templates/job_templates/job-template.form.js:324 -#: client/src/templates/job_templates/job-template.form.js:333 -msgid "Host Config Key" -msgstr "ホスト設定キー" - -#: client/src/inventories-hosts/hosts/host.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:39 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:39 -msgid "Host Enabled" -msgstr "有効なホスト" - -#: client/src/inventories-hosts/hosts/host.form.js:46 -#: client/src/inventories-hosts/hosts/host.form.js:57 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:45 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:56 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:45 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:56 -msgid "Host Name" -msgstr "ホスト名" - -#: client/src/inventories-hosts/hosts/host.form.js:80 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:79 -msgid "Host Variables" -msgstr "ホスト変数" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is available" -msgstr "ホストが利用可能です。" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is available. Click to toggle." -msgstr "ホストが利用可能です。クリックして切り替えます。" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is not available" -msgstr "ホストを利用できません。" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is not available. Click to toggle." -msgstr "ホストを利用できません。クリックして切り替えます。" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:39 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:98 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:57 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:56 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:167 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:176 -#: client/src/job-results/job-results.partial.html:504 -msgid "Hosts" -msgstr "ホスト" - -#: client/src/license/license.partial.html:52 -msgid "Hosts Available" -msgstr "利用可能なホスト" - -#: client/src/license/license.partial.html:64 -msgid "Hosts Remaining" -msgstr "残りのホスト" - -#: client/src/license/license.partial.html:58 -msgid "Hosts Used" -msgstr "使用されたホスト" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "Hosts are imported to" -msgstr "ホストのインポート先" - -#: client/src/license/license.partial.html:121 -msgid "I agree to the End User License Agreement" -msgstr "使用許諾契約書に同意します。" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:27 -#: client/src/instance-groups/jobs/jobs.list.js:26 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:38 -msgid "ID" -msgstr "ID" - -#: client/src/partials/job-template-details.html:2 -msgid "INFO" -msgstr "情報" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 -msgid "INITIATED BY" -msgstr "開始:" - -#: client/src/inventories-hosts/inventories/insights/insights.route.js:7 -msgid "INSIGHTS" -msgstr "INSIGHTS" - -#: client/src/instance-groups/instance-groups.list.js:6 -#: client/src/instance-groups/instance-groups.list.js:7 -#: client/src/instance-groups/instance-groups.route.js:10 -#: client/src/instance-groups/list/instance-groups-list.partial.html:3 -msgid "INSTANCE GROUPS" -msgstr "インスタンスグループ" - -#: client/src/instance-groups/instance-group.partial.html:27 -msgid "INSTANCES" -msgstr "インスタンス" - -#: client/src/activity-stream/get-target-title.factory.js:14 -#: client/src/inventories-hosts/hosts/hosts.partial.html:8 -#: client/src/inventories-hosts/inventories/inventories.partial.html:13 -#: client/src/inventories-hosts/inventories/inventories.route.js:8 -#: client/src/inventories-hosts/inventories/inventory.list.js:14 -#: client/src/inventories-hosts/inventories/inventory.list.js:15 -#: client/src/main-menu/main-menu.partial.html:104 -#: client/src/main-menu/main-menu.partial.html:27 -#: client/src/organizations/linkout/organizations-linkout.route.js:143 -#: client/src/organizations/list/organizations-list.controller.js:66 -msgid "INVENTORIES" -msgstr "インベントリー" - -#: client/src/job-submission/job-submission.partial.html:346 -#: client/src/partials/job-template-details.html:2 -msgid "INVENTORY" -msgstr "インベントリー" - -#: client/src/inventory-scripts/inventory-scripts.form.js:23 -msgid "INVENTORY SCRIPT" -msgstr "インベントリースクリプト" - -#: client/src/activity-stream/get-target-title.factory.js:35 -#: client/src/inventory-scripts/inventory-scripts.list.js:12 -#: client/src/inventory-scripts/main.js:66 -msgid "INVENTORY SCRIPTS" -msgstr "インベントリースクリプト" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js:8 -msgid "INVENTORY SOURCES" -msgstr "インベントリーソース" - -#: client/src/notifications/notificationTemplates.form.js:348 -msgid "IRC Nick" -msgstr "IRC ニック" - -#: client/src/notifications/notificationTemplates.form.js:337 -msgid "IRC Server Address" -msgstr "IRC サーバーアドレス" - -#: client/src/notifications/shared/type-change.service.js:58 -msgid "IRC Server Password" -msgstr "IRC サーバーパスワード" - -#: client/src/notifications/shared/type-change.service.js:57 -msgid "IRC Server Port" -msgstr "IRC サーバーポート" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:79 -msgid "ISSUE: {{report.rule.description}}" -msgstr "問題: {{report.rule.description}}" - -#: client/src/shared/paginate/paginate.partial.html:43 -msgid "ITEMS" -msgstr "項目" - -#: client/src/login/authenticationServices/timer.factory.js:157 -msgid "Idle Session" -msgstr "アイドル状態のセッション" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "If blank, all groups above are created except" -msgstr "空白の場合には、以下を除く上記のすべてのグループが作成されます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:343 -msgid "" -"If checked, all variables for child groups and hosts will be removed and " -"replaced by those found on the external source." -msgstr "チェックが付けられている場合、子グループおよびホストのすべての変数が削除され、外部ソースにあるものによって置き換えられます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:331 -msgid "" -"If checked, any hosts and groups that were previously present on the " -"external source but are now removed will be removed from the Tower " -"inventory. Hosts and groups that were not managed by the inventory source " -"will be promoted to the next manually created group or if there is no " -"manually created group to promote them into, they will be left in the " -"\"all\" default group for the inventory." -msgstr "" -"チェックが付けられている場合、以前は外部ソースにあり、現在は削除されているホストおよびグループが Tower " -"インベントリーから削除されます。インベントリーソースで管理されていなかったホストおよびグループは次に手動で作成されるグループにプロモートされるか、またはプロモート先となる手動で作成されたグループがない場合は、それらはインベントリーの「すべて」のデフォルトグループに残ります。" - -#: client/src/templates/job_templates/job-template.form.js:267 -msgid "If enabled, run this playbook as an administrator." -msgstr "有効にされている場合、この Playbook を管理者として実行します。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:120 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Ansible タスクで加えられた変更を表示します (有効にされ、サポートされている場合)。これは Ansible の --diff " -"モードに相当します。" - -#: client/src/templates/job_templates/job-template.form.js:251 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Ansible タスクで加えられた変更を表示します (有効にされ、サポートされている場合)。これは Ansible の --diff " -"モードに相当します。" - -#: client/src/templates/job_templates/job-template.form.js:291 -msgid "If enabled, simultaneous runs of this job template will be allowed." -msgstr "このジョブテンプレートの同時実行が許可されます (有効にされている場合)。" - -#: client/src/templates/job_templates/job-template.form.js:302 -msgid "" -"If enabled, use cached facts if available and store discovered facts in the " -"cache." -msgstr "キャッシュされたファクトを使用し (有効にされ、ファクトが利用可能な場合)、検出されたファクトをキャッシュに保存します。" - -#: client/src/credentials/credentials.form.js:52 -msgid "" -"If no organization is given, the credential can only be used by the user " -"that creates the credential. Organization admins and system administrators " -"can assign an organization so that roles for the credential can be assigned " -"to users and teams in that organization." -msgstr "" -"組織が指定されない場合、認証情報はそれを作成するユーザーのみに使用されます。組織管理者およびシステム管理者は組織を割り当て、認証情報のロールを組織内のユーザーおよびチームに割り当てられるようにします。" - -#: client/src/license/license.partial.html:70 -msgid "" -"If you are ready to upgrade, please contact us by clicking the button below" -msgstr "アップグレードの準備ができましたら、以下のボタンをクリックしてお問い合わせください。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:173 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:254 -msgid "Image ID:" -msgstr "イメージ ID:" - -#: client/src/inventories-hosts/hosts/host.form.js:34 -#: client/src/inventories-hosts/hosts/host.list.js:34 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:33 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:30 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:33 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:29 -msgid "" -"Indicates if a host is available and should be included in running jobs." -msgstr "ホストが利用可能かどうか、また実行中のジョブに組み込む必要があるかどうかを示します。" - -#: client/src/activity-stream/activity-detail.form.js:31 -#: client/src/activity-stream/streams.list.js:33 -msgid "Initiated by" -msgstr "開始:" - -#: client/src/credential-types/credential-types.form.js:53 -#: client/src/credential-types/credential-types.form.js:61 -msgid "Injector Configuration" -msgstr "インジェクターの設定" - -#: client/src/credential-types/credential-types.form.js:39 -#: client/src/credential-types/credential-types.form.js:47 -msgid "Input Configuration" -msgstr "入力の設定" - -#: client/src/inventories-hosts/hosts/host.form.js:123 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:122 -msgid "Insights" -msgstr "Insights" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:69 -msgid "Insights Credential" -msgstr "Insights 認証情報" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:145 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:148 -msgid "Instance Filters" -msgstr "インスタンスフィルター" - -#: client/src/job-results/job-results.partial.html:369 -msgid "Instance Group" -msgstr "インスタンスグループ" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:75 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:78 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:81 -#: client/src/organizations/organizations.form.js:38 -#: client/src/organizations/organizations.form.js:41 -#: client/src/setup-menu/setup-menu.partial.html:54 -#: client/src/templates/job_templates/job-template.form.js:191 -#: client/src/templates/job_templates/job-template.form.js:194 -msgid "Instance Groups" -msgstr "インスタンスグループ" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "Instance ID" -msgstr "インスタンス ID" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:174 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:255 -msgid "Instance ID:" -msgstr "インスタンス ID:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:175 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:256 -msgid "Instance Type:" -msgstr "インスタンスタイプ:" - -#: client/src/license/license.partial.html:11 -msgid "Invalid License" -msgstr "無効なライセンス" - -#: client/src/license/license.controller.js:63 -#: client/src/license/license.controller.js:70 -msgid "Invalid file format. Please upload valid JSON." -msgstr "無効なファイル形式です。有効な JSON をアップロードしてください。" - -#: client/lib/components/components.strings.js:16 -msgid "Invalid input for this type." -msgstr "このタイプの無効な入力です。" - -#: client/src/login/loginModal/loginModal.partial.html:34 -msgid "Invalid username and/or password. Please try again." -msgstr "無効なユーザー名および/またはパスワードです。やり直してください。" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:122 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:52 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:50 -#: client/src/organizations/linkout/organizations-linkout.route.js:155 -msgid "Inventories" -msgstr "インベントリー" - -#: client/src/inventories-hosts/hosts/host.list.js:69 -#: client/src/inventories-hosts/inventories/inventory.list.js:80 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/job-results/job-results.partial.html:201 -#: client/src/job-submission/job-submission.partial.html:17 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:58 -#: client/src/templates/job_templates/job-template.form.js:66 -#: client/src/templates/job_templates/job-template.form.js:80 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:72 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:82 -msgid "Inventory" -msgstr "インベントリー" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:110 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:124 -msgid "Inventory File" -msgstr "インベントリーファイル" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 -#: client/src/setup-menu/setup-menu.partial.html:41 -msgid "Inventory Scripts" -msgstr "インベントリースクリプト" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:46 -msgid "Inventory Sync" -msgstr "インベントリー同期" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:55 -msgid "Inventory Sync Failures" -msgstr "インベントリーの同期の失敗" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:93 -msgid "Inventory Variables" -msgstr "インベントリー変数" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:66 -msgid "Inventory contains 0 hosts." -msgstr "インベントリーには 0 ホストが含まれています。" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:4 -msgid "JOB STATUS" -msgstr "ジョブステータス" - -#: client/src/templates/job_templates/job-template.form.js:22 -msgid "JOB TEMPLATE" -msgstr "ジョブテンプレート" - -#: client/src/organizations/linkout/organizations-linkout.route.js:256 -#: client/src/organizations/list/organizations-list.controller.js:78 -#: client/src/portal-mode/portal-job-templates.list.js:13 -#: client/src/portal-mode/portal-job-templates.list.js:14 -msgid "JOB TEMPLATES" -msgstr "ジョブテンプレート" - -#: client/src/activity-stream/get-target-title.factory.js:32 -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:118 -#: client/src/instance-groups/instance-group.partial.html:28 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:27 -#: client/src/instance-groups/jobs/jobs-list.route.js:9 -#: client/src/jobs/jobs.route.js:15 -#: client/src/main-menu/main-menu.partial.html:122 -#: client/src/main-menu/main-menu.partial.html:43 -#: client/src/portal-mode/portal-jobs.list.js:13 -#: client/src/portal-mode/portal-jobs.list.js:17 -msgid "JOBS" -msgstr "ジョブ" - -#: client/src/job-submission/job-submission.partial.html:173 -msgid "JSON" -msgstr "JSON" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:198 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:222 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:246 -msgid "JSON:" -msgstr "JSON:" - -#: client/src/job-results/job-results.partial.html:384 -#: client/src/job-submission/job-submission.partial.html:228 -#: client/src/templates/job_templates/job-template.form.js:200 -#: client/src/templates/job_templates/job-template.form.js:207 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:127 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:135 -msgid "Job Tags" -msgstr "ジョブタグ" - -#: client/src/templates/templates.list.js:61 -msgid "Job Template" -msgstr "ジョブテンプレート" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:36 -#: client/src/organizations/linkout/organizations-linkout.route.js:268 -msgid "Job Templates" -msgstr "ジョブテンプレート" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:32 -#: client/src/job-results/job-results.partial.html:159 -#: client/src/job-submission/job-submission.partial.html:202 -#: client/src/templates/job_templates/job-template.form.js:47 -#: client/src/templates/job_templates/job-template.form.js:55 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:103 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:92 -msgid "Job Type" -msgstr "ジョブタイプ" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:46 -msgid "" -"Job details are not available for this job. Please download to view " -"standard out." -msgstr "このジョブのジョブ詳細は利用できません。ダウンロードして標準出力を表示します。" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 -#: client/src/configuration/configuration.partial.html:16 -#: client/src/jobs/jobs.partial.html:7 -msgid "Jobs" -msgstr "ジョブ" - -#: client/src/job-results/job-results.controller.js:269 -#: client/src/job-results/job-results.controller.js:366 -msgid "Jump to last line of standard out." -msgstr "標準出力の最終行にジャンプ" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:61 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:154 -#: client/src/shared/smart-search/smart-search.partial.html:14 -msgid "Key" -msgstr "キー" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:176 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:257 -msgid "Key Name:" -msgstr "キー名:" - -#: client/src/credential-types/credential-types.list.js:31 -#: client/src/credentials/credentials.list.js:33 -msgid "Kind" -msgstr "種類" - -#: client/src/job-submission/job-submission.partial.html:6 -msgid "LAUNCH JOB" -msgstr "ジョブの起動" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:86 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:66 -msgid "LAUNCH TYPE" -msgstr "起動タイプ" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:111 -msgid "LDAP" -msgstr "LDAP" - -#: client/src/license/license.route.js:19 -msgid "LICENSE" -msgstr "ライセンス" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:58 -msgid "LICENSE ERROR" -msgstr "ライセンスエラー" - -#: client/src/main-menu/main-menu.partial.html:83 -msgid "LOG OUT" -msgstr "ログアウト" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:68 -#: client/src/instance-groups/jobs/jobs.list.js:66 -#: client/src/job-results/job-results.partial.html:434 -#: client/src/job-results/job-results.partial.html:443 -#: client/src/jobs/all-jobs.list.js:74 -#: client/src/templates/job_templates/job-template.form.js:234 -#: client/src/templates/job_templates/job-template.form.js:238 -#: client/src/templates/templates.list.js:43 -#: client/src/templates/workflows.form.js:62 -#: client/src/templates/workflows.form.js:67 -msgid "Labels" -msgstr "ラベル" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:25 -#: client/src/users/users.form.js:33 client/src/users/users.list.js:37 -msgid "Last Name" -msgstr "姓" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:56 -msgid "Last Sync" -msgstr "最終同期" - -#: client/src/projects/projects.list.js:56 -msgid "Last Updated" -msgstr "最終更新日時" - -#: client/src/portal-mode/portal-job-templates.list.js:36 -#: client/src/shared/form-generator.js:1707 -#: client/src/templates/templates.list.js:80 -msgid "Launch" -msgstr "起動" - -#: client/src/management-jobs/card/card.partial.html:23 -msgid "Launch Management Job" -msgstr "管理ジョブの起動" - -#: client/src/job-results/job-results.partial.html:170 -#: client/src/job-results/job-results.partial.html:185 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:76 -msgid "Launched By" -msgstr "起動:" - -#: client/src/job-submission/job-submission.partial.html:99 -msgid "" -"Launching this job requires the passwords listed below. Enter and confirm " -"each password before continuing." -msgstr "このジョブの起動には以下に記載されているパスワードが必要です。それぞれのパスワードを入力し、確認してから続行します。" - -#: client/features/credentials/legacy.credentials.js:357 -msgid "Legacy state configuration for does not exist" -msgstr "レガシー状態の設定は存在しません。" - -#: client/src/license/license.controller.js:40 -#: client/src/license/license.partial.html:8 -msgid "License" -msgstr "ライセンス" - -#: client/src/license/license.partial.html:104 -msgid "License File" -msgstr "ライセンスファイル" - -#: client/src/license/license.partial.html:33 -msgid "License Key" -msgstr "ライセンスキー" - -#: client/src/license/license.controller.js:40 -msgid "License Management" -msgstr "ライセンス管理" - -#: client/src/license/license.partial.html:21 -msgid "License Type" -msgstr "ライセンスタイプ" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:55 -#: client/src/job-results/job-results.partial.html:347 -#: client/src/job-submission/job-submission.partial.html:220 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:92 -#: client/src/templates/job_templates/job-template.form.js:160 -#: client/src/templates/job_templates/job-template.form.js:164 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:113 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:120 -msgid "Limit" -msgstr "制限" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:186 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:268 -msgid "Limit to hosts having a tag:" -msgstr "タグを持つホストに制限:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:188 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:270 -msgid "Limit to hosts using either key pair:" -msgstr "いずれかのキーペアを使用するホストに制限:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "Limit to hosts where the Name tag begins with" -msgstr "名前タグの開始点となるホストに制限" - -#: client/src/shared/socket/socket.service.js:168 -msgid "Live events: attempting to connect to the server." -msgstr "ライブイベント: サーバーへの接続を試行しています。" - -#: client/src/shared/socket/socket.service.js:172 -msgid "" -"Live events: connected. Pages containing job status information will " -"automatically update in real-time." -msgstr "ライブイベント: 接続されています。ジョブステータス情報を含むページは自動的にリアルタイムで更新されます。" - -#: client/src/shared/socket/socket.service.js:176 -msgid "Live events: error connecting to the server." -msgstr "ライブイベント: サーバーへの接続時にエラーが発生しました。" - -#: client/src/shared/form-generator.js:1983 -msgid "Loading..." -msgstr "ロード中..." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:133 -msgid "Local Time Zone" -msgstr "ローカルタイムゾーン" - -#: client/src/main-menu/main-menu.partial.html:188 -msgid "Log Out" -msgstr "ログアウト" - -#: client/src/configuration/system-form/configuration-system.controller.js:225 -msgid "Log aggregator test failed.
Detail:" -msgstr "ログアグリゲーターのテストに失敗しました。
詳細:" - -#: client/src/configuration/system-form/configuration-system.controller.js:218 -msgid "Log aggregator test successful." -msgstr "ログアグリゲーターのテストが成功しました。" - -#: client/src/configuration/system-form/configuration-system.controller.js:89 -msgid "Logging" -msgstr "ロギング" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:35 -msgid "Low" -msgstr "低" - -#: client/src/management-jobs/card/card.partial.html:6 -#: client/src/management-jobs/card/card.route.js:21 -msgid "MANAGEMENT JOBS" -msgstr "管理ジョブ" - -#: client/src/portal-mode/portal-mode.route.js:12 -msgid "MY VIEW" -msgstr "マイビュー" - -#: client/src/credentials/credentials.form.js:67 -#: client/src/job-submission/job-submission.partial.html:356 -msgid "Machine" -msgstr "マシン" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:60 -#: client/src/job-results/job-results.partial.html:260 -msgid "Machine Credential" -msgstr "マシンの認証情報" - -#: client/src/setup-menu/setup-menu.partial.html:36 -msgid "" -"Manage the cleanup of old job history, activity streams, data marked for " -"deletion, and system tracking info." -msgstr "古いジョブ履歴、アクティビティーストリーム、削除用にマークされたデータ、およびシステムトラッキング情報のクリーンアップを管理します。" - -#: client/src/setup-menu/setup-menu.partial.html:35 -msgid "Management Jobs" -msgstr "管理ジョブ" - -#: client/src/projects/list/projects-list.controller.js:89 -msgid "Manual projects do not require a schedule" -msgstr "手動プロジェクトにスケジュールは不要です" - -#: client/src/projects/edit/projects-edit.controller.js:141 -#: client/src/projects/list/projects-list.controller.js:88 -msgid "Manual projects do not require an SCM update" -msgstr "手動プロジェクトに SCM 更新は不要です" - -#: client/src/login/loginModal/loginModal.partial.html:28 -msgid "Maximum per-user sessions reached. Please sign in." -msgstr "ユーザーあたりの最大セッション数に達しました。サインインしてください。" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:29 -msgid "Medium" -msgstr "中" - -#: client/src/configuration/system-form/configuration-system.controller.js:90 -msgid "Misc. System" -msgstr "その他のシステム" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:27 -msgid "Missing. Click for details" -msgstr "見つかりません。クリックして詳細を確認してください。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:22 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:30 -msgid "Module" -msgstr "モジュール" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:53 -msgid "Module Args" -msgstr "モジュールの引数" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:25 -msgid "Most recent job failed. Click to view jobs." -msgstr "最新のジョブが失敗しました。クリックしてジョブを表示します。" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:29 -msgid "Most recent job successful. Click to view jobs." -msgstr "最新のジョブが成功しました。クリックしてジョブを表示します。" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:77 -msgid "Multiple Choice Options" -msgstr "複数の選択オプション" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:4 -#: client/src/portal-mode/portal-mode-layout.partial.html:11 -msgid "My Jobs" -msgstr "マイジョブ" - -#: client/src/main-menu/main-menu.partial.html:160 -msgid "My View" -msgstr "マイビュー" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:19 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:19 -msgid "NAME" -msgstr "名前" - -#: client/features/credentials/credentials.strings.js:24 -msgid "NEW CREDENTIAL" -msgstr "新規の認証情報" - -#: client/src/credential-types/credential-types.form.js:16 -msgid "NEW CREDENTIAL TYPE" -msgstr "新規の認証情報タイプ" - -#: client/src/inventory-scripts/inventory-scripts.form.js:16 -msgid "NEW CUSTOM INVENTORY" -msgstr "新規カスタムインベントリー" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:34 -msgid "NEW INVENTORY" -msgstr "新規インベントリー" - -#: client/src/templates/job_templates/job-template.form.js:19 -msgid "NEW JOB TEMPLATE" -msgstr "新規ジョブテンプレート" - -#: client/src/notifications/notificationTemplates.form.js:16 -msgid "NEW NOTIFICATION TEMPLATE" -msgstr "新規通知テンプレート" - -#: client/src/organizations/organizations.form.js:18 -msgid "NEW ORGANIZATION" -msgstr "新規組織" - -#: client/src/projects/projects.form.js:16 -msgid "NEW PROJECT" -msgstr "新規プロジェクト" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:28 -msgid "NEW SMART INVENTORY" -msgstr "新規スマートインベントリー" - -#: client/src/teams/teams.form.js:16 -msgid "NEW TEAM" -msgstr "新規チーム" - -#: client/src/users/users.form.js:16 -msgid "NEW USER" -msgstr "新規ユーザー" - -#: client/src/templates/workflows.form.js:17 -msgid "NEW WORKFLOW JOB TEMPLATE" -msgstr "新規ワークフロージョブテンプレート" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:38 -msgid "NO HOSTS HAVE BEEN CREATED" -msgstr "ホストが作成されていません" - -#: client/lib/components/components.strings.js:35 -msgid "NO OPTIONS AVAILABLE" -msgstr "利用可能なオプションがありません" - -#: client/src/login/loginModal/loginModal.partial.html:89 -msgid "NOTICE" -msgstr "通知" - -#: client/src/notifications/notificationTemplates.form.js:21 -msgid "NOTIFICATION TEMPLATE" -msgstr "通知テンプレート" - -#: client/src/activity-stream/get-target-title.factory.js:26 -#: client/src/notifications/notificationTemplates.list.js:14 -msgid "NOTIFICATION TEMPLATES" -msgstr "通知テンプレート" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js:9 -#: client/src/management-jobs/notifications/notification.route.js:46 -#: client/src/notifications/main.js:43 client/src/notifications/main.js:91 -msgid "NOTIFICATIONS" -msgstr "通知" - -#: client/src/credential-types/credential-types.form.js:27 -#: client/src/credential-types/credential-types.list.js:24 -#: client/src/credentials/credentials.form.js:32 -#: client/src/credentials/credentials.list.js:26 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:14 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:13 -#: client/src/instance-groups/instance-groups.list.js:15 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:35 -#: client/src/instance-groups/instances/instances-list.partial.html:15 -#: client/src/instance-groups/instances/instances.list.js:14 -#: client/src/instance-groups/jobs/jobs.list.js:34 -#: client/src/instance-groups/list/instance-groups-list.partial.html:26 -#: client/src/inventories-hosts/hosts/host.list.js:61 -#: client/src/inventories-hosts/inventories/inventory.list.js:47 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:45 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:33 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:51 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:39 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:45 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:45 -#: client/src/inventory-scripts/inventory-scripts.form.js:28 -#: client/src/inventory-scripts/inventory-scripts.list.js:20 -#: client/src/jobs/all-jobs.list.js:43 -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 -#: client/src/notifications/notificationTemplates.form.js:32 -#: client/src/notifications/notificationTemplates.list.js:32 -#: client/src/notifications/notifications.list.js:26 -#: client/src/organizations/organizations.form.js:26 -#: client/src/portal-mode/portal-job-templates.list.js:23 -#: client/src/portal-mode/portal-jobs.list.js:35 -#: client/src/projects/projects.form.js:29 -#: client/src/projects/projects.list.js:37 -#: client/src/scheduler/scheduled-jobs.list.js:31 -#: client/src/scheduler/schedules.list.js:33 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:19 -#: client/src/teams/teams.form.js:124 client/src/teams/teams.form.js:25 -#: client/src/teams/teams.list.js:23 -#: client/src/templates/completed-jobs.list.js:46 -#: client/src/templates/job_templates/job-template.form.js:34 -#: client/src/templates/templates.list.js:24 -#: client/src/templates/workflows.form.js:32 -#: client/src/users/users.form.js:142 client/src/users/users.form.js:168 -#: client/src/users/users.form.js:194 -msgid "Name" -msgstr "名前" - -#: client/src/credentials/credentials.form.js:71 -msgid "Network" -msgstr "ネットワーク" - -#: client/src/job-results/job-results.partial.html:306 -msgid "Network Credential" -msgstr "ネットワークの認証情報" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:81 -msgid "New Group" -msgstr "新規グループ" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:130 -msgid "New Host" -msgstr "新規ホスト" - -#: client/src/users/add/users-add.controller.js:91 -msgid "New user successfully created!" -msgstr "新規ユーザーが正常に作成されました!" - -#: client/src/scheduler/scheduled-jobs.list.js:51 -#: client/src/scheduler/schedules.list.js:43 -msgid "Next Run" -msgstr "次回実行日時" - -#: client/src/credentials/credentials.list.js:21 -msgid "No Credentials Have Been Created" -msgstr "認証情報が作成されていません" - -#: client/src/job-submission/lists/credential/job-sub-cred-list.controller.js:44 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:140 -msgid "No Credentials Matching This Type Have Been Created" -msgstr "このタイプに一致する認証情報が作成されていません" - -#: client/src/job-results/host-event/host-event-codemirror.partial.html:3 -msgid "No JSON data returned by the module" -msgstr "JSON データがモジュールによって返されていません" - -#: client/src/projects/projects.list.js:20 -msgid "No Projects Have Been Created" -msgstr "プロジェクトが作成されていません" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:50 -msgid "No Remediation Playbook Available" -msgstr "修復 Playbook を使用できません" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "No SCM Configuration" -msgstr "SCM 設定がありません" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:9 -msgid "No SCM updates have run for this project" -msgstr "このプロジェクトで実行された SCM 更新はありません" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:17 -msgid "No Teams exist" -msgstr "チームが存在しません" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "No Updates Available" -msgstr "利用可能な更新がありません" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:18 -msgid "No Users exist" -msgstr "ユーザーが存在しません" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:23 -#: client/src/templates/completed-jobs.list.js:24 -msgid "No completed jobs" -msgstr "完了したジョブがありません" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:63 -msgid "No data is available. There are no issues to report." -msgstr "使用できるデータがありません。報告する問題がありません。" - -#: client/src/license/license.controller.js:39 -msgid "No file selected." -msgstr "ファイルが選択されていません。" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:62 -msgid "No hosts with failures. Click for details." -msgstr "障害のあるホストがありません。クリックして詳細を確認してください。" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:47 -msgid "No inventory sync failures. Click for details." -msgstr "インベントリーの同期に障害が発生していません。クリックして詳細を確認してください。" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:16 -msgid "No job data" -msgstr "ジョブデータがありません" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:75 -msgid "No job data available." -msgstr "利用可能なジョブデータがありません。" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:22 -msgid "No job failures" -msgstr "ジョブに障害が発生していません" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:54 -msgid "No job templates were recently used." -msgstr "最近使用されたジョブテンプレートはありません。" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:9 -#: client/src/instance-groups/jobs/jobs.list.js:9 -#: client/src/jobs/all-jobs.list.js:18 -msgid "No jobs have yet run." -msgstr "実行されたジョブがありません。" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:44 -msgid "No jobs were recently run." -msgstr "最近実行されたジョブがありません。" - -#: client/src/teams/teams.form.js:121 client/src/users/users.form.js:191 -msgid "No permissions have been granted" -msgstr "パーミッションが付与されていません" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:17 -msgid "No recent job data available for this host." -msgstr "このホストに利用できる最新のジョブデータがありません。" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:75 -msgid "No recent job data available for this inventory." -msgstr "このインベントリーに利用できる最新のジョブデータがありません。" - -#: client/src/notifications/notification-templates-list/list.controller.js:86 -msgid "No recent notifications." -msgstr "最新の通知はありません。" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:36 -#: client/src/shared/form-generator.js:1879 -#: client/src/shared/list-generator/list-generator.factory.js:240 -msgid "No records matched your search." -msgstr "検索に一致するレコードはありません" - -#: client/src/scheduler/scheduled-jobs.list.js:16 -msgid "No schedules exist" -msgstr "スケジュールがありません" - -#: client/src/job-submission/job-submission.partial.html:348 -#: client/src/job-submission/job-submission.partial.html:353 -msgid "None selected" -msgstr "いずれも選択されていません" - -#: client/src/users/add/users-add.controller.js:10 -#: client/src/users/edit/users-edit.controller.js:10 -#: client/src/users/list/users-list.controller.js:10 -msgid "Normal User" -msgstr "標準ユーザー" - -#: client/src/projects/list/projects-list.controller.js:91 -msgid "Not configured for SCM" -msgstr "SCM 用に設定されていません" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:52 -msgid "Not configured for inventory sync." -msgstr "インベントリーの同期に設定されていません。" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -msgid "" -"Note that only hosts directly in this group can be disassociated. Hosts in " -"sub-groups must be disassociated directly from the sub-group level that they" -" belong." -msgstr "" -"このグループに直接含まれるホストのみの関連付けを解除できることに注意してください。サブグループのホストの関連付けの解除については、それらのホストが属するサブグループのレベルで直接実行する必要があります。" - -#: client/src/notifications/notificationTemplates.form.js:288 -#: client/src/notifications/notificationTemplates.form.js:289 -msgid "Notification Color" -msgstr "通知の色" - -#: client/src/notifications/notification-templates-list/list.controller.js:113 -msgid "Notification Failed." -msgstr "通知に失敗しました。" - -#: client/src/notifications/notificationTemplates.form.js:277 -msgid "Notification Label" -msgstr "通知レベル" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 -msgid "Notification Templates" -msgstr "通知テンプレート" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:20 -#: client/src/management-jobs/notifications/notification.route.js:21 -#: client/src/notifications/notifications.list.js:17 -#: client/src/setup-menu/setup-menu.partial.html:48 -msgid "Notifications" -msgstr "通知" - -#: client/src/notifications/notificationTemplates.form.js:302 -msgid "Notify Channel" -msgstr "通知チャネル" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:55 -#: client/src/job-submission/job-submission.partial.html:269 -#: client/src/partials/survey-maker-modal.html:27 -#: client/src/shared/form-generator.js:542 -#: client/src/shared/form-generator.js:773 -#: client/src/shared/generator-helpers.js:551 -msgid "OFF" -msgstr "オフ" - -#: client/lib/services/base-string.service.js:63 -#: client/src/jobs/factories/delete-job.factory.js:115 -msgid "OK" -msgstr "OK" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:54 -#: client/src/job-submission/job-submission.partial.html:267 -#: client/src/partials/survey-maker-modal.html:26 -#: client/src/shared/form-generator.js:538 -#: client/src/shared/form-generator.js:771 -#: client/src/shared/generator-helpers.js:547 -msgid "ON" -msgstr "オン" - -#: client/lib/components/components.strings.js:10 -msgid "OPTIONS" -msgstr "オプション" - -#: client/src/activity-stream/get-target-title.factory.js:29 -#: client/src/organizations/list/organizations-list.partial.html:6 -#: client/src/organizations/main.js:52 -msgid "ORGANIZATIONS" -msgstr "組織" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:116 -msgid "OVERWRITE" -msgstr "上書き" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:123 -msgid "OVERWRITE VARS" -msgstr "変数の上書き" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:38 -msgid "On Failure" -msgstr "失敗した場合 " - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:33 -msgid "On Success" -msgstr "成功した場合 " - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:157 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:162 -msgid "Only Group By" -msgstr "グループ化のみ" - -#: client/src/credentials/credentials.form.js:379 -msgid "" -"OpenStack domains define administrative boundaries. It is only needed for " -"Keystone v3 authentication URLs. Common scenarios include:" -msgstr "" -"OpenStack ドメインは管理上の境界を定義します。これは Keystone v3 認証 URL " -"にのみ必要です。共通するシナリオには以下が含まれます:" - -#: client/src/templates/job_templates/job-template.form.js:240 -#: client/src/templates/workflows.form.js:69 -msgid "" -"Optional labels that describe this job template, such as 'dev' or 'test'. " -"Labels can be used to group and filter job templates and completed jobs." -msgstr "" -"「dev」または「test」などのこのジョブテンプレートを説明するオプションラベルです。ラベルを使用し、ジョブテンプレートおよび完了したジョブの分類およびフィルターを実行できます。" - -#: client/src/notifications/notificationTemplates.form.js:382 -#: client/src/partials/logviewer.html:7 -#: client/src/templates/job_templates/job-template.form.js:259 -msgid "Options" -msgstr "オプション" - -#: client/src/credentials/credentials.form.js:46 -#: client/src/credentials/credentials.form.js:53 -#: client/src/inventories-hosts/inventories/inventory.list.js:60 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:51 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:58 -#: client/src/inventory-scripts/inventory-scripts.form.js:40 -#: client/src/inventory-scripts/inventory-scripts.list.js:27 -#: client/src/notifications/notificationTemplates.form.js:44 -#: client/src/projects/projects.form.js:41 -#: client/src/projects/projects.form.js:47 client/src/teams/teams.form.js:37 -#: client/src/teams/teams.list.js:30 client/src/templates/workflows.form.js:45 -#: client/src/templates/workflows.form.js:51 client/src/users/users.form.js:40 -msgid "Organization" -msgstr "組織" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:136 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:64 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:30 -#: client/src/setup-menu/setup-menu.partial.html:4 -#: client/src/users/users.form.js:132 -msgid "Organizations" -msgstr "組織" - -#: client/src/job-submission/job-submission.partial.html:19 -msgid "Other Prompts" -msgstr "他のプロンプト" - -#: client/src/credentials/credentials.form.js:79 -msgid "Others (Cloud Providers)" -msgstr "その他 (クラウドプロバイダー)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:283 -msgid "" -"Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"cloudforms.ini にあり、インベントリー更新スクリプトで使用される変数を上書きします。たとえば、変数の設定\n" -" \n" -" は Ansible github リポジトリーで cloudforms.ini を表示します。 JSON または YAML 構文のいずれかを使用してインベントリー変数を入力します。ラジオボタンを使用して 2 つの間の切り替えを行います。構文のサンプルについては、Ansible Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:218 -msgid "" -"Override variables found in ec2.ini and used by the inventory update script." -" For a detailed description of these variables" -msgstr "" -"ec2.ini にあり、インベントリー更新スクリプトで使用される変数を上書きします。これらの変数の詳細な説明については、次を参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:300 -msgid "" -"Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"foreman.ini にあり、インベントリー更新スクリプトで使用される変数を上書きします。たとえば、変数の設定\n" -" \n" -" は Ansible github リポジトリーで foreman.ini を表示します。 JSON または YAML 構文のいずれかを使用してインベントリー変数を入力します。ラジオボタンを使用して 2 つの間の切り替えを行います。構文のサンプルについては、Ansible Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:266 -msgid "" -"Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration\n" -" \n" -" view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"openstack.yml にあり、インベントリー更新スクリプトで使用される変数を上書きします。たとえば、変数の設定\n" -" \n" -" は Ansible github リポジトリーで openstack.yml を表示します。 JSON または YAML 構文のいずれかを使用してインベントリー変数を入力します。ラジオボタンを使用して 2 つの間の切り替えを行います。構文のサンプルについては、Ansible Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:242 -msgid "" -"Override variables found in vmware.ini and used by the inventory update " -"script. For a detailed description of these variables" -msgstr "" -"vmware.ini にあり、インベントリー更新スクリプトで使用される変数を上書きします。これらの変数の詳細な説明については、次を参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:328 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:333 -msgid "Overwrite" -msgstr "上書き" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:340 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:345 -msgid "Overwrite Variables" -msgstr "変数の上書き" - -#: client/src/credentials/credentials.list.js:40 -msgid "Owners" -msgstr "所有者" - -#: client/src/login/loginModal/loginModal.partial.html:68 -msgid "PASSWORD" -msgstr "パスワード" - -#: client/features/credentials/legacy.credentials.js:122 -msgid "PERMISSIONS" -msgstr "パーミッション" - -#: client/src/partials/job-template-details.html:2 -msgid "PLAYBOOK" -msgstr "PLAYBOOK" - -#: client/src/partials/survey-maker-modal.html:45 -msgid "PLEASE ADD A SURVEY PROMPT." -msgstr "Survey プロンプトを追加してください。" - -#: client/src/instance-groups/instances/instances-list.partial.html:6 -#: client/src/instance-groups/list/instance-groups-list.partial.html:16 -#: client/src/organizations/list/organizations-list.partial.html:47 -#: client/src/shared/form-generator.js:1885 -#: client/src/shared/list-generator/list-generator.factory.js:248 -msgid "PLEASE ADD ITEMS TO THIS LIST" -msgstr "項目をこの一覧に追加してください" - -#: client/src/main-menu/main-menu.partial.html:67 -msgid "PORTAL MODE" -msgstr "ポータルモード" - -#: client/src/partials/survey-maker-modal.html:43 -msgid "PREVIEW" -msgstr "プレビュー" - -#: client/src/job-results/job-results.service.js:166 -msgid "PROCEED" -msgstr "続行" - -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:73 -msgid "PROJECT" -msgstr "プロジェクト" - -#: client/src/activity-stream/get-target-title.factory.js:8 -#: client/src/main-menu/main-menu.partial.html:19 -#: client/src/main-menu/main-menu.partial.html:95 -#: client/src/organizations/linkout/organizations-linkout.route.js:195 -#: client/src/organizations/list/organizations-list.controller.js:72 -#: client/src/projects/main.js:73 client/src/projects/projects.list.js:14 -#: client/src/projects/projects.list.js:15 -msgid "PROJECTS" -msgstr "プロジェクト" - -#: client/src/shared/paginate/paginate.partial.html:33 -msgid "Page" -msgstr "ページ" - -#: client/src/notifications/notificationTemplates.form.js:232 -msgid "Pagerduty subdomain" -msgstr "Pagerduty サブドメイン" - -#: client/src/templates/job_templates/job-template.form.js:348 -msgid "" -"Pass extra command line variables to the playbook. Provide key/value pairs " -"using either YAML or JSON. Refer to the Ansible Tower documentation for " -"example syntax." -msgstr "" -"追加のコマンドライン変数を Playbook に渡します。YAML または JSON " -"のいずれかを使用してキーと値のペアを指定します。構文のサンプルについては Ansible Tower ドキュメントを参照してください。" - -#: client/src/templates/workflows.form.js:80 -msgid "" -"Pass extra command line variables to the playbook. This is the -e or " -"--extra-vars command line parameter for ansible-playbook. Provide key/value " -"pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for" -" example syntax." -msgstr "" -"追加のコマンドライン変数を Playbook に渡します。これは、ansible-playbook の -e または --extra-vars " -"コマンドラインパラメーターです。YAML または JSON のいずれかを使用してキーと値のペアを指定します。構文のサンプルについては Ansible " -"Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:138 -msgid "" -"Pass extra command line variables. This is the %s or %s command line " -"parameter for %s. Provide key/value pairs using either YAML or JSON." -msgstr "" -"追加のコマンドライン変数を渡します。これは、%s の %s または %s コマンドラインパラメーターです。YAML または JSON " -"のいずれかを使用してキーと値のペアを指定します。" - -#: client/src/credentials/credentials.form.js:226 -#: client/src/credentials/factories/become-method-change.factory.js:21 -#: client/src/credentials/factories/become-method-change.factory.js:40 -#: client/src/credentials/factories/become-method-change.factory.js:48 -#: client/src/credentials/factories/become-method-change.factory.js:68 -#: client/src/credentials/factories/become-method-change.factory.js:78 -#: client/src/credentials/factories/become-method-change.factory.js:88 -#: client/src/credentials/factories/kind-change.factory.js:105 -#: client/src/credentials/factories/kind-change.factory.js:125 -#: client/src/credentials/factories/kind-change.factory.js:135 -#: client/src/credentials/factories/kind-change.factory.js:145 -#: client/src/credentials/factories/kind-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:78 -#: client/src/credentials/factories/kind-change.factory.js:97 -#: client/src/job-submission/job-submission.partial.html:104 -#: client/src/notifications/shared/type-change.service.js:28 -#: client/src/users/users.form.js:68 -msgid "Password" -msgstr "パスワード" - -#: client/src/credentials/factories/kind-change.factory.js:58 -msgid "Password (API Key)" -msgstr "パスワード (API キー)" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:20 -msgid "Past 24 Hours" -msgstr "過去 24 時間" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:15 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:26 -msgid "Past Month" -msgstr "過去 1 ヵ月" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:23 -msgid "Past Week" -msgstr "過去 1 週間" - -#: client/src/credentials/factories/become-method-change.factory.js:29 -#: client/src/credentials/factories/kind-change.factory.js:86 -msgid "" -"Paste the contents of the PEM file associated with the service account " -"email." -msgstr "サービスアカウントメールに関連付けられた PEM ファイルの内容を貼り付けます。" - -#: client/src/credentials/factories/kind-change.factory.js:51 -msgid "Paste the contents of the SSH private key file." -msgstr "SSH 秘密鍵ファイルの内容を貼り付けます。" - -#: client/src/credentials/factories/kind-change.factory.js:26 -msgid "Paste the contents of the SSH private key file.%s or click to close%s" -msgstr "SSH 秘密鍵ファイルの内容を貼り付けます。%s またはクリックして %s を閉じます。" - -#: client/src/inventories-hosts/inventories/inventory.list.js:119 -msgid "Pending Delete" -msgstr "保留中の削除" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:8 -msgid "Period" -msgstr "期間" - -#: client/src/projects/add/projects-add.controller.js:29 -#: client/src/users/add/users-add.controller.js:43 -msgid "Permission Error" -msgstr "パーミッションのエラー" - -#: client/features/credentials/credentials.strings.js:14 -#: client/features/credentials/legacy.credentials.js:66 -#: client/src/credentials/credentials.form.js:439 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:122 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:123 -#: client/src/projects/projects.form.js:233 client/src/teams/teams.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:386 -#: client/src/templates/workflows.form.js:114 -#: client/src/users/users.form.js:187 -msgid "Permissions" -msgstr "パーミッション" - -#: client/src/job-results/job-results.partial.html:249 -#: client/src/shared/form-generator.js:1069 -#: client/src/templates/job_templates/job-template.form.js:107 -#: client/src/templates/job_templates/job-template.form.js:115 -msgid "Playbook" -msgstr "Playbook" - -#: client/src/projects/projects.form.js:89 -msgid "Playbook Directory" -msgstr "Playbook ディレクトリー" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:52 -msgid "Playbook Run" -msgstr "Playbook 実行" - -#: client/src/job-results/job-results.partial.html:488 -msgid "Plays" -msgstr "プレイ" - -#: client/src/users/users.form.js:126 -msgid "Please add user to an Organization." -msgstr "ユーザーを組織に追加してください。" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:100 -msgid "Please assign roles to the selected resources" -msgstr "ロールを選択したリソースに割り当ててください。" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:60 -msgid "Please assign roles to the selected users/teams" -msgstr "ロールを選択したユーザー/チームに割り当ててください。" - -#: client/src/license/license.partial.html:84 -msgid "" -"Please click the button below to visit Ansible's website to get a Tower " -"license key." -msgstr "以下のボタンをクリックし、Ansible の web サイトに移動して Tower ライセンスキーを取得します。" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:27 -msgid "Please click the icon to edit the host filter." -msgstr "アイコンをクリックしてホストフィルターを編集します。" - -#: client/src/shared/form-generator.js:861 -#: client/src/shared/form-generator.js:956 -msgid "" -"Please enter a URL that begins with ssh, http or https. The URL may not " -"contain the '@' character." -msgstr "ssh、http または https で始まる URL を入力します。URL には「@」文字を含めることはできません。" - -#: client/src/shared/form-generator.js:1158 -msgid "Please enter a number greater than %d and less than %d." -msgstr "%d より大きく、%d より小さい数値を入力してください。" - -#: client/src/shared/form-generator.js:1160 -msgid "Please enter a number greater than %d." -msgstr "%d より大きい数値を入力してください。" - -#: client/src/shared/form-generator.js:1152 -msgid "Please enter a number." -msgstr "数値を入力してください。" - -#: client/src/job-submission/job-submission.partial.html:112 -#: client/src/job-submission/job-submission.partial.html:126 -#: client/src/job-submission/job-submission.partial.html:140 -#: client/src/job-submission/job-submission.partial.html:154 -#: client/src/login/loginModal/loginModal.partial.html:78 -msgid "Please enter a password." -msgstr "パスワードを入力してください。" - -#: client/src/login/loginModal/loginModal.partial.html:58 -msgid "Please enter a username." -msgstr "ユーザー名を入力してください。" - -#: client/src/shared/form-generator.js:851 -#: client/src/shared/form-generator.js:946 -msgid "Please enter a valid email address." -msgstr "有効なメールアドレスを入力してください。" - -#: client/lib/components/components.strings.js:15 -#: client/src/shared/form-generator.js:1016 -#: client/src/shared/form-generator.js:846 -#: client/src/shared/form-generator.js:941 -msgid "Please enter a value." -msgstr "値を入力してください。" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/job-submission/job-submission.partial.html:311 -#: client/src/job-submission/job-submission.partial.html:317 -msgid "Please enter an answer between" -msgstr "次の範囲で回答を入力してください:" - -#: client/src/job-submission/job-submission.partial.html:316 -msgid "Please enter an answer that is a decimal number." -msgstr "10 進数の回答を入力してください。" - -#: client/src/job-submission/job-submission.partial.html:310 -msgid "Please enter an answer that is a valid integer." -msgstr "有効な整数の回答を入力してください。" - -#: client/src/job-submission/job-submission.partial.html:288 -#: client/src/job-submission/job-submission.partial.html:293 -#: client/src/job-submission/job-submission.partial.html:304 -#: client/src/job-submission/job-submission.partial.html:309 -#: client/src/job-submission/job-submission.partial.html:315 -msgid "Please enter an answer." -msgstr "回答を入力してください。" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:11 -#: client/src/templates/completed-jobs.list.js:11 -msgid "Please save and run a job to view." -msgstr "表示するジョブを保存し、実行してください。" - -#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:50 -msgid "Please save before adding a survey to this job template." -msgstr "Survey をこのジョブテンプレートに追加する前に保存してください。" - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:46 -msgid "Please save before adding a survey to this workflow." -msgstr "Survey をこのワークフローに追加する前に保存してください。" - -#: client/src/notifications/notifications.list.js:15 -msgid "Please save before adding notifications." -msgstr "通知を追加する前に保存してください。" - -#: client/src/organizations/organizations.form.js:68 -#: client/src/teams/teams.form.js:69 -msgid "Please save before adding users." -msgstr "ユーザーを追加する前に保存してください。" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:118 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:119 -#: client/src/projects/projects.form.js:225 client/src/teams/teams.form.js:113 -#: client/src/templates/job_templates/job-template.form.js:379 -#: client/src/templates/workflows.form.js:107 -msgid "Please save before assigning permissions." -msgstr "パーミッションを割り当てる前に保存してください。" - -#: client/src/users/users.form.js:124 client/src/users/users.form.js:183 -msgid "Please save before assigning to organizations." -msgstr "組織に割り当てる前に保存してください。" - -#: client/src/users/users.form.js:152 -msgid "Please save before assigning to teams." -msgstr "チームに割り当てる前に保存してください。" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:164 -msgid "Please save before creating groups." -msgstr "グループを作成する前に保存してください。" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:173 -msgid "Please save before creating hosts." -msgstr "ホストを作成する前に保存してください。" - -#: client/src/inventories-hosts/hosts/host.form.js:112 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:86 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:111 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:112 -msgid "Please save before defining groups." -msgstr "グループを定義する前に保存してください。" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:94 -msgid "Please save before defining hosts." -msgstr "ホストを定義する前に保存してください。" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:182 -msgid "Please save before defining inventory sources." -msgstr "インベントリーソースを定義する前に保存してください。" - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:45 -msgid "Please save before defining the workflow graph." -msgstr "ワークフローグラフを定義する前に保存してください。" - -#: client/src/inventories-hosts/hosts/host.form.js:121 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:120 -msgid "Please save before viewing Insights." -msgstr "Insights を表示する前に保存してください。" - -#: client/src/inventories-hosts/hosts/host.form.js:105 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:104 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:105 -msgid "Please save before viewing facts." -msgstr "ファクトを表示する前に保存してください。" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:164 -msgid "Please save before viewing hosts." -msgstr "ホストを表示する前に保存してください。" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 -msgid "Please select Users / Teams from the lists below." -msgstr "以下の一覧からユーザー/チームを選択してください。" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 -msgid "Please select Users from the list below." -msgstr "以下の一覧からユーザーを選択してください。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:58 -msgid "Please select a Credential." -msgstr "認証情報を選択してください。" - -#: client/src/templates/job_templates/multi-credential/multi-credential.partial.html:46 -msgid "" -"Please select a machine (SSH) credential or check the \"Prompt on launch\" " -"option." -msgstr "マシン (SSH) 認証情報を選択するか、または「起動プロンプト」オプションにチェックを付けます。" - -#: client/src/shared/form-generator.js:1193 -msgid "Please select a number between" -msgstr "Please select a number between" - -#: client/src/shared/form-generator.js:1189 -msgid "Please select a number." -msgstr "数値を選択してください。" - -#: client/src/shared/form-generator.js:1081 -#: client/src/shared/form-generator.js:1149 -#: client/src/shared/form-generator.js:1270 -#: client/src/shared/form-generator.js:1378 -msgid "Please select a value." -msgstr "値を選択してください。" - -#: client/src/templates/job_templates/job-template.form.js:77 -msgid "Please select an Inventory or check the Prompt on launch option." -msgstr "インベントリーを選択するか、または「起動プロンプト」オプションにチェックを付けてください。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:79 -msgid "Please select an Inventory." -msgstr "インベントリーを選択してください。" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:26 -msgid "Please select an organization before editing the host filter." -msgstr "組織を選択してからホストフィルターを編集します。" - -#: client/src/shared/form-generator.js:1186 -msgid "Please select at least one value." -msgstr "1 つ以上の値を選択してください。" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:30 -msgid "Please select resources from the lists below." -msgstr "以下の一覧からリソースを選択してください。" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Populate the hosts for this inventory by using a search filter." -msgstr "検索フィルターを使用してこのインベントリーのホストを設定します。" - -#: client/src/notifications/shared/type-change.service.js:27 -msgid "Port" -msgstr "ポート" - -#: client/src/credentials/credentials.form.js:257 -#: client/src/credentials/factories/kind-change.factory.js:21 -#: client/src/credentials/factories/kind-change.factory.js:45 -msgid "Private Key" -msgstr "秘密鍵" - -#: client/src/credentials/credentials.form.js:264 -#: client/src/job-submission/job-submission.partial.html:118 -msgid "Private Key Passphrase" -msgstr "秘密鍵のパスフレーズ" - -#: client/src/credentials/credentials.form.js:279 -#: client/src/credentials/credentials.form.js:283 -msgid "Privilege Escalation" -msgstr "権限昇格" - -#: client/src/credentials/credentials.form.js:305 -#: client/src/job-submission/job-submission.partial.html:132 -msgid "Privilege Escalation Password" -msgstr "権限昇格のパスワード" - -#: client/src/credentials/credentials.form.js:295 -msgid "Privilege Escalation Username" -msgstr "権限昇格のユーザー名" - -#: client/src/credentials/factories/become-method-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:87 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:93 -#: client/src/job-results/job-results.partial.html:216 -#: client/src/templates/job_templates/job-template.form.js:100 -#: client/src/templates/job_templates/job-template.form.js:91 -msgid "Project" -msgstr "プロジェクト" - -#: client/src/credentials/factories/become-method-change.factory.js:53 -#: client/src/credentials/factories/kind-change.factory.js:110 -msgid "Project (Tenant Name)" -msgstr "プロジェクト (テナント名)" - -#: client/src/projects/projects.form.js:75 -#: client/src/projects/projects.form.js:83 -msgid "Project Base Path" -msgstr "プロジェクトのベースパス" - -#: client/src/credentials/credentials.form.js:365 -msgid "Project Name" -msgstr "プロジェクト名" - -#: client/src/projects/projects.form.js:100 -msgid "Project Path" -msgstr "プロジェクトパス" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:66 -msgid "Project Sync Failures" -msgstr "プロジェクトの同期の失敗" - -#: client/src/projects/list/projects-list.controller.js:170 -msgid "Project lookup failed. GET returned:" -msgstr "プロジェクトの検索に失敗しました。GET で以下が返されました:" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:115 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:47 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:31 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:61 -#: client/src/organizations/linkout/organizations-linkout.route.js:206 -msgid "Projects" -msgstr "プロジェクト" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:18 -msgid "Promote group" -msgid_plural "Promote groups" -msgstr[0] "グループのプロモート" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:43 -msgid "Promote groups" -msgstr "グループのプロモート" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:32 -msgid "Promote groups and hosts" -msgstr "グループおよびホストのプロモート" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:20 -msgid "Promote host" -msgid_plural "Promote hosts" -msgstr[0] "ホストのプロモート" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:54 -msgid "Promote hosts" -msgstr "ホストのプロモート" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:10 -msgid "Promote {{ group }} and {{ host }}" -msgstr "{{ group }} および {{ host }} のプロモート" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:27 -msgid "Prompt" -msgstr "プロンプト" - -#: client/lib/components/components.strings.js:30 -#: client/src/templates/job_templates/job-template.form.js:139 -#: client/src/templates/job_templates/job-template.form.js:169 -#: client/src/templates/job_templates/job-template.form.js:186 -#: client/src/templates/job_templates/job-template.form.js:212 -#: client/src/templates/job_templates/job-template.form.js:229 -#: client/src/templates/job_templates/job-template.form.js:254 -#: client/src/templates/job_templates/job-template.form.js:354 -#: client/src/templates/job_templates/job-template.form.js:60 -#: client/src/templates/job_templates/job-template.form.js:86 -msgid "Prompt on launch" -msgstr "起動プロンプト" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:132 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:147 -msgid "Provide a comma separated list of tags." -msgstr "カンマ区切りのタグの一覧を指定してください。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:184 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:266 -msgid "Provide a comma-separated list of filter expressions." -msgstr "フィルター式のカンマ区切りリストを指定します。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:200 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:284 -msgid "" -"Provide a comma-separated list of filter expressions. Hosts are imported " -"when all of the filters match. Refer to Ansible Tower documentation for more" -" detail." -msgstr "" -"カンマ区切りのフィルター式の一覧を提供します。ホストは、フィルターのすべてが一致する場合にインポートされます。詳細については、Ansible Tower" -" ドキュメントを参照してください。" - -#: client/src/inventories-hosts/hosts/host.form.js:50 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:49 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:49 -msgid "Provide a host name, ip address, or ip address:port. Examples include:" -msgstr "host name、ip address、または ip address:port を指定してください。例:" - -#: client/src/templates/job_templates/job-template.form.js:163 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns are allowed. Refer to" -" Ansible documentation for more information and examples on patterns." -msgstr "" -"Playbook " -"によって管理されるか、またはその影響を受けるホストの一覧をさらに制限するためのホストのパターンを指定します。複数のパターンが許可されます。パターンについての詳細およびサンプルについては、Ansible" -" ドキュメントを参照してください。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:116 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns can be separated by " -"%s %s or %s" -msgstr "" -"Playbook によって管理されるか、または影響されるホストの一覧をさらに制限するためのホストのパターンを指定してください。複数のパターンは %s " -"%s または %s で区切ることができます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:196 -msgid "Provide environment variables to pass to the custom inventory script." -msgstr "カスタムインベントリースクリプトに渡す環境変数を指定します。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:203 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:287 -msgid "" -"Provide the named URL encoded name or id of the remote Tower inventory to be" -" imported." -msgstr "インポートされるリモート Tower インベントリーの名前付き URL のエンコードされた名前または ID を指定します。" - -#: client/src/templates/job_templates/job-template.form.js:311 -#: client/src/templates/job_templates/job-template.form.js:319 -msgid "Provisioning Callback URL" -msgstr "プロビジョニングコールバック URL" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Purple" -msgstr "紫" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:14 -msgid "Queued. Click for details" -msgstr "キューに入れられました。クリックして詳細を確認してください。" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:112 -msgid "RADIUS" -msgstr "RADIUS" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:4 -msgid "RECENT JOB RUNS" -msgstr "最近のジョブの実行" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:40 -msgid "RECENTLY RUN JOBS" -msgstr "最近実行されたジョブ" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:50 -msgid "RECENTLY USED JOB TEMPLATES" -msgstr "最近使用されたジョブテンプレート" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:4 -msgid "RECENTLY USED TEMPLATES" -msgstr "最近使用されたテンプレート" - -#: client/src/activity-stream/streams.list.js:54 -#: client/src/inventories-hosts/hosts/host.list.js:102 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:46 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:113 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:54 -#: client/src/jobs/jobs.partial.html:15 -#: client/src/portal-mode/portal-mode-jobs.partial.html:20 -#: client/src/projects/projects.list.js:71 -#: client/src/scheduler/schedules.list.js:61 -msgid "REFRESH" -msgstr "更新" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:109 -msgid "REGIONS" -msgstr "リージョン" - -#: client/src/shared/smart-search/smart-search.partial.html:48 -msgid "RELATED FIELDS:" -msgstr "関連フィールド:" - -#: client/src/shared/directives.js:78 -msgid "REMOVE" -msgstr "削除" - -#: client/lib/components/components.strings.js:7 -msgid "REPLACE" -msgstr "置換" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:7 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:7 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:7 -msgid "RESULTS" -msgstr "結果" - -#: client/lib/components/components.strings.js:8 -#: client/src/job-submission/job-submission.partial.html:44 -#: client/src/job-submission/job-submission.partial.html:87 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:52 -msgid "REVERT" -msgstr "元に戻す" - -#: client/src/credentials/factories/become-method-change.factory.js:25 -#: client/src/credentials/factories/kind-change.factory.js:82 -msgid "RSA Private Key" -msgstr "RSA 秘密鍵" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.route.js:28 -msgid "RUN COMMAND" -msgstr "コマンドの実行" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:101 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:56 -msgid "RUN COMMANDS" -msgstr "コマンドの実行" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Random" -msgstr "ランダム" - -#: client/src/job-results/job-results.partial.html:411 -msgid "Read only view of extra variables added to the job template." -msgstr "追加変数の読み取り専用ビューがジョブテンプレートに追加されました。" - -#: client/src/workflow-results/workflow-results.partial.html:155 -msgid "Read only view of extra variables added to the workflow." -msgstr "追加変数の読み取り専用ビューがワークフローに追加されました。" - -#: client/src/notifications/notificationTemplates.list.js:26 -msgid "Recent Notifications" -msgstr "最近の通知" - -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:98 -msgid "Recipient List" -msgstr "受信者リスト" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Red" -msgstr "赤" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "" -"Refer to the Ansible Tower documentation for further syntax and examples." -msgstr "追加の構文およびサンプルについては、Ansible Tower ドキュメントを参照してください。" - -#: client/src/activity-stream/streams.list.js:51 -#: client/src/bread-crumb/bread-crumb.partial.html:6 -#: client/src/inventories-hosts/hosts/host.list.js:98 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:42 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:109 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:50 -#: client/src/projects/projects.list.js:67 -#: client/src/scheduler/schedules.list.js:57 -msgid "Refresh the page" -msgstr "ページの更新" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:177 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "Region:" -msgstr "リージョン:" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:131 -msgid "Regions" -msgstr "リージョン" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:65 -msgid "Related Groups" -msgstr "関連するグループ" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:77 -#: client/src/job-results/job-results.partial.html:29 -#: client/src/jobs/all-jobs.list.js:99 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:11 -#: client/src/templates/completed-jobs.list.js:78 -#: client/src/workflow-results/workflow-results.partial.html:29 -msgid "Relaunch using the same parameters" -msgstr "同一パラメーターによる起動" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:194 -msgid "Remediate Inventory" -msgstr "インベントリーの修復" - -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:96 -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:97 -#: client/src/teams/teams.form.js:142 client/src/users/users.form.js:222 -msgid "Remove" -msgstr "削除" - -#: client/src/projects/projects.form.js:158 -msgid "Remove any local modifications prior to performing an update." -msgstr "更新の実行前にローカルの変更を削除します。" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:149 -msgid "Repeat frequency" -msgstr "繰り返しの頻度" - -#: client/src/license/license.partial.html:89 -msgid "Request License" -msgstr "ライセンスの要求" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:291 -msgid "Required" -msgstr "必須" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:153 -msgid "Reset" -msgstr "リセット" - -#: client/src/job-results/job-results.partial.html:123 -msgid "Results Traceback" -msgstr "結果のトレースバック" - -#: client/src/shared/form-generator.js:690 -msgid "Revert" -msgstr "元に戻す" - -#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:59 -#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:95 -#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:34 -#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:87 -#: client/src/configuration/auth-form/sub-forms/auth-tacacs.form.js:47 -#: client/src/configuration/jobs-form/configuration-jobs.form.js:73 -#: client/src/configuration/system-form/sub-forms/system-activity-stream.form.js:26 -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:74 -#: client/src/configuration/system-form/sub-forms/system-misc.form.js:50 -#: client/src/configuration/ui-form/configuration-ui.form.js:36 -msgid "Revert all to default" -msgstr "すべてをデフォルトに戻す" - -#: client/src/job-results/job-results.partial.html:239 -#: client/src/projects/projects.list.js:50 -msgid "Revision" -msgstr "リビジョン" - -#: client/src/projects/add/projects-add.controller.js:146 -#: client/src/projects/edit/projects-edit.controller.js:281 -msgid "Revision #" -msgstr "リビジョン #" - -#: client/features/credentials/legacy.credentials.js:88 -#: client/src/credentials/credentials.form.js:461 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:148 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:149 -#: client/src/organizations/organizations.form.js:97 -#: client/src/projects/projects.form.js:255 client/src/teams/teams.form.js:135 -#: client/src/teams/teams.form.js:98 -#: client/src/templates/workflows.form.js:138 -#: client/src/users/users.form.js:205 -msgid "Role" -msgstr "ロール" - -#: client/src/instance-groups/instance-group.partial.html:14 -#: client/src/instance-groups/instance-groups.list.js:26 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:14 -#: client/src/instance-groups/instances/instances-list.partial.html:18 -#: client/src/instance-groups/instances/instances.list.js:24 -#: client/src/instance-groups/list/instance-groups-list.partial.html:29 -msgid "Running Jobs" -msgstr "実行中のジョブ" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:18 -msgid "Running! Click for details" -msgstr "実行中です! クリックして詳細を確認してください。" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:113 -msgid "SAML" -msgstr "SAML" - -#: client/lib/services/base-string.service.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:17 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:17 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:17 -#: client/src/partials/survey-maker-modal.html:87 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:18 -msgid "SAVE" -msgstr "保存" - -#: client/src/scheduler/main.js:331 -msgid "SCHEDULED" -msgstr "スケジュール済み" - -#: client/src/scheduler/scheduled-jobs.list.js:13 -msgid "SCHEDULED JOBS" -msgstr "スケジュール済みジョブ" - -#: client/src/activity-stream/get-target-title.factory.js:38 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:49 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:8 -#: client/src/management-jobs/scheduler/main.js:26 -#: client/src/management-jobs/scheduler/main.js:32 -#: client/src/scheduler/main.js:145 client/src/scheduler/main.js:183 -#: client/src/scheduler/main.js:235 client/src/scheduler/main.js:273 -#: client/src/scheduler/main.js:52 client/src/scheduler/main.js:90 -msgid "SCHEDULES" -msgstr "スケジュール" - -#: client/src/projects/add/projects-add.controller.js:118 -#: client/src/projects/edit/projects-edit.controller.js:254 -msgid "SCM Branch" -msgstr "SCM ブランチ" - -#: client/src/projects/add/projects-add.controller.js:137 -#: client/src/projects/edit/projects-edit.controller.js:272 -msgid "SCM Branch/Tag/Commit" -msgstr "SCM ブランチ/タグ/コミット" - -#: client/src/projects/add/projects-add.controller.js:158 -#: client/src/projects/edit/projects-edit.controller.js:293 -msgid "SCM Branch/Tag/Revision" -msgstr "SCM ブランチ/タグ/リビジョン" - -#: client/src/projects/projects.form.js:159 -msgid "SCM Clean" -msgstr "SCM クリーニング" - -#: client/src/projects/projects.form.js:170 -msgid "SCM Delete" -msgstr "SCM 削除" - -#: client/src/credentials/factories/become-method-change.factory.js:20 -#: client/src/credentials/factories/kind-change.factory.js:77 -msgid "SCM Private Key" -msgstr "SCM 秘密鍵" - -#: client/src/projects/projects.form.js:55 -msgid "SCM Type" -msgstr "SCM タイプ" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:49 -#: client/src/projects/projects.form.js:180 -msgid "SCM Update" -msgstr "SCM 更新" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "SCM Update Cancel" -msgstr "SCM 更新の取り消し" - -#: client/src/projects/projects.form.js:150 -msgid "SCM Update Options" -msgstr "SCM 更新オプション" - -#: client/src/projects/edit/projects-edit.controller.js:137 -#: client/src/projects/list/projects-list.controller.js:84 -msgid "SCM update currently running" -msgstr "現在実行中の SCM 更新" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js:35 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:70 -msgid "SELECT" -msgstr "選択" - -#: client/features/credentials/credentials.strings.js:20 -msgid "SELECT A CREDENTIAL TYPE" -msgstr "認証情報タイプの選択" - -#: client/features/credentials/credentials.strings.js:19 -msgid "SELECT AN ORGANIZATION" -msgstr "組織の選択" - -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:6 -msgid "SELECT GROUPS" -msgstr "グループの選択" - -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:6 -msgid "SELECT HOSTS" -msgstr "ホストの選択" - -#: client/src/job-submission/job-submission.partial.html:29 -#: client/src/job-submission/job-submission.partial.html:56 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:20 -msgid "SELECTED:" -msgstr "選択済み:" - -#: client/src/main-menu/main-menu.partial.html:59 -#: client/src/setup-menu/setup.route.js:9 -msgid "SETTINGS" -msgstr "設定" - -#: client/lib/components/components.strings.js:11 -msgid "SHOW" -msgstr "表示" - -#: client/src/login/loginModal/loginModal.partial.html:97 -msgid "SIGN IN" -msgstr "サインイン" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html:2 -msgid "SIGN IN WITH" -msgstr "サインイン:" - -#: client/src/inventories-hosts/hosts/host.list.js:110 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:32 -msgid "SMART INVENTORY" -msgstr "スマートインベントリー" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:102 -msgid "SOURCE" -msgstr "ソース" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js:26 -msgid "SOURCES" -msgstr "ソース" - -#: client/src/credentials/factories/become-method-change.factory.js:89 -#: client/src/credentials/factories/kind-change.factory.js:146 -msgid "SSH Key" -msgstr "SSH キー" - -#: client/src/credentials/credentials.form.js:255 -msgid "SSH key description" -msgstr "SSH キーの説明" - -#: client/src/notifications/notificationTemplates.form.js:375 -msgid "SSL Connection" -msgstr "SSL 接続" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:128 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:135 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:96 -msgid "STANDARD OUT" -msgstr "標準出力" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:32 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:65 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:45 -msgid "STARTED" -msgstr "開始" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:24 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:37 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:37 -msgid "STATUS" -msgstr "ステータス" - -#: client/src/credentials/credentials.form.js:119 -#: client/src/credentials/credentials.form.js:127 -msgid "STS Token" -msgstr "STS トークン" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:61 -msgid "SUCCESSFUL" -msgstr "成功" - -#: client/src/partials/survey-maker-modal.html:24 -msgid "SURVEY" -msgstr "Survey " - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:62 -msgid "SYNC ALL" -msgstr "すべてを同期する" - -#: client/src/system-tracking/system-tracking.route.js:18 -msgid "SYSTEM TRACKING" -msgstr "システムトラッキング" - -#: client/src/credentials/factories/become-method-change.factory.js:70 -#: client/src/credentials/factories/kind-change.factory.js:127 -msgid "Satellite 6 URL" -msgstr "Satellite 6 URL" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:110 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:193 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:157 -#: client/src/shared/form-generator.js:1691 -msgid "Save" -msgstr "保存" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:86 -#: client/src/configuration/configuration.controller.js:213 -#: client/src/configuration/configuration.controller.js:272 -#: client/src/configuration/system-form/configuration-system.controller.js:68 -msgid "Save changes" -msgstr "変更の保存" - -#: client/src/license/license.partial.html:127 -msgid "Save successful!" -msgstr "正常に保存が実行されました!" - -#: client/src/templates/templates.list.js:88 -msgid "Schedule" -msgstr "スケジュール" - -#: client/src/management-jobs/card/card.partial.html:28 -msgid "Schedule Management Job" -msgstr "管理ジョブのスケジュール" - -#: client/src/projects/list/projects-list.controller.js:75 -msgid "Schedule future SCM updates" -msgstr "SCM 更新のスケジュール" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:7 -msgid "Schedule future inventory syncs" -msgstr "インベントリー同期のスケジュール" - -#: client/src/templates/templates.list.js:91 -msgid "Schedule future job template runs" -msgstr "ジョブテンプレート実行のスケジュール" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:33 -#: client/src/jobs/jobs.partial.html:10 -msgid "Schedules" -msgstr "スケジュール" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:94 -msgid "Search" -msgstr "検索" - -#: client/src/credentials/credentials.form.js:104 -msgid "Secret Key" -msgstr "シークレットキー" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:259 -msgid "Security Group:" -msgstr "セキュリティーグループ:" - -#: client/src/credentials/credentials.form.js:124 -msgid "" -"Security Token Service (STS) is a web service that enables you to request " -"temporary, limited-privilege credentials for AWS Identity and Access " -"Management (IAM) users." -msgstr "" -"セキュリティートークンサービス (STS) は、AWS Identity and Access Management (IAM) " -"ユーザーの一時的な、権限の制限された認証情報を要求できる web サービスです。" - -#: client/src/shared/form-generator.js:1695 -msgid "Select" -msgstr "選択" - -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:5 -msgid "Select Instance Groups" -msgstr "インスタンスグループの選択" - -#: client/src/job-submission/job-submission.directive.js:64 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:46 -msgid "Select a credential" -msgstr "認証情報の選択" - -#: client/src/access/add-rbac-user-team/rbac-user-team.controller.js:68 -msgid "Select a role" -msgstr "ロールの選択" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or a selection of multiple groups." -msgstr "" -"チェックボックスをクリックしてインベントリーソースを選択します。インベントリーソースは単一グループにすることも、複数グループのセレクションにすることもできます。" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:98 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or host, a selection of multiple " -"hosts, or a selection of multiple groups." -msgstr "" -"チェックボックスをクリックしてインベントリーソースを選択します。インベントリーソースは単一グループや複数ホストのセレクション、または複数グループのセレクションにすることができます。" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:111 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single host or a selection of multiple hosts." -msgstr "" -"チェックボックスをクリックしてインベントリーソースを選択します。インベントリーソースは単一ホストにすることも、複数ホストのセレクションにすることもできます。" - -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:109 -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:134 -#: client/src/configuration/ui-form/configuration-ui.controller.js:95 -msgid "Select commands" -msgstr "コマンドの選択" - -#: client/src/templates/job_templates/job-template.form.js:133 -msgid "" -"Select credentials that allow Tower to access the nodes this job will be ran" -" against. You can only select one credential of each type. For machine " -"credentials (SSH), checking \"Prompt on launch\" without selecting " -"credentials will require you to select a machine credential at run time. If " -"you select credentials and check \"Prompt on launch\", the selected " -"credential(s) become the defaults that can be updated at run time." -msgstr "" -"Tower のこのジョブが実行されるノードへのアクセスを許可する認証情報を選択します。各タイプにつき 1 つの認証情報のみを選択できます。マシン認証情報" -" (SSH) " -"については、認証情報を選択せずに「起動プロンプト」を選択すると、実行時にマシン認証情報を選択する必要があります。認証情報を選択し、「起動プロンプト」にチェックを付けている場合、選択した認証情報が実行時に更新できるデフォルトになります。" - -#: client/src/projects/projects.form.js:98 -msgid "" -"Select from the list of directories found in the Project Base Path. Together" -" the base path and the playbook directory provide the full path used to " -"locate playbooks." -msgstr "" -"プロジェクトのベースパスにあるデイレクトリーの一覧から選択します。ベースパスと Playbook ディレクトリーは、Playbook " -"を見つけるために使用される完全なパスを提供します。" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:263 -#: client/src/configuration/auth-form/configuration-auth.controller.js:282 -msgid "Select group types" -msgstr "グループタイプの選択" - -#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:24 -msgid "Select roles" -msgstr "ロールの選択" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:74 -msgid "Select the Instance Groups for this Inventory to run on." -msgstr "このインベントリーが実行されるインスタンスグループを選択します。" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:80 -msgid "" -"Select the Instance Groups for this Inventory to run on. Refer to the " -"Ansible Tower documentation for more detail." -msgstr "" -"このインベントリーが実行されるインスタンスグループを選択します。詳細については、Ansible Tower ドキュメントを参照してください。" - -#: client/src/templates/job_templates/job-template.form.js:193 -msgid "Select the Instance Groups for this Job Template to run on." -msgstr "このジョブテンプレートが実行されるインスタンスグループを選択します。" - -#: client/src/organizations/organizations.form.js:40 -msgid "Select the Instance Groups for this Organization to run on." -msgstr "この組織が実行されるインスタンスグループを選択します。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:60 -msgid "" -"Select the credential you want the job to use when accessing the remote " -"hosts. Choose the credential containing the username and SSH key or " -"password that Ansible will need to log into the remote hosts." -msgstr "" -"リモートホストへのアクセス時にジョブが使用する認証情報を選択します。Ansible がリモートホストにログインするために必要なユーザー名および SSH " -"キーまたはパスワードが含まれる認証情報を選択します。 " - -#: client/src/templates/job_templates/job-template.form.js:79 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:81 -msgid "Select the inventory containing the hosts you want this job to manage." -msgstr "このジョブで管理するホストが含まれるインベントリーを選択してください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:122 -msgid "" -"Select the inventory file to be synced by this source. You can select from " -"the dropdown or enter a file within the input." -msgstr "このソースで同期されるインベントリーファイルを選択します。ドロップダウンから選択するか、入力にファイルを指定できます。" - -#: client/src/templates/job_templates/job-template.form.js:114 -msgid "Select the playbook to be executed by this job." -msgstr "このジョブで実行される Playbook を選択してください。" - -#: client/src/templates/job_templates/job-template.form.js:99 -msgid "" -"Select the project containing the playbook you want this job to execute." -msgstr "このジョブで実行する Playbook が含まれるプロジェクトを選択してください。" - -#: client/src/configuration/system-form/configuration-system.controller.js:197 -msgid "Select types" -msgstr "タイプの選択" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:170 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:251 -msgid "Select which groups to create automatically." -msgstr "自動作成するグループを選択します。" - -#: client/src/notifications/notificationTemplates.form.js:110 -msgid "Sender Email" -msgstr "送信者のメール" - -#: client/src/credentials/factories/become-method-change.factory.js:24 -#: client/src/credentials/factories/kind-change.factory.js:81 -msgid "Service Account Email Address" -msgstr "サービスアカウントのメールアドレス" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:101 -msgid "" -"Setting the type to %s will execute the playbook and store any scanned " -"facts for use with 's System Tracking feature." -msgstr "タイプを %s に設定すると Playbook が実行され、システムトラッキング機能で使用するスキャンされたファクトが保存されます。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:99 -msgid "" -"Setting the type to %s will not execute the playbook. Instead, %s will check" -" playbook syntax, test environment setup and report problems." -msgstr "" -"タイプを %s に設定すると Playbook は実行されません。その代わりに、%s は Playbook " -"構文、テスト環境セットアップおよびレポートの問題を検査します。" - -#: client/src/main-menu/main-menu.partial.html:147 -msgid "Settings" -msgstr "設定" - -#: client/src/job-submission/job-submission.partial.html:108 -#: client/src/job-submission/job-submission.partial.html:122 -#: client/src/job-submission/job-submission.partial.html:136 -#: client/src/job-submission/job-submission.partial.html:150 -#: client/src/job-submission/job-submission.partial.html:299 -#: client/src/shared/form-generator.js:876 -msgid "Show" -msgstr "表示" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:114 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:245 -#: client/src/templates/job_templates/job-template.form.js:248 -msgid "Show Changes" -msgstr "変更の表示" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:33 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:44 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:55 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:76 -msgid "Sign in with %s" -msgstr "%s でサインイン" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:63 -msgid "Sign in with %s Organizations" -msgstr "%s 組織でサインイン" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:61 -msgid "Sign in with %s Teams" -msgstr "%s チームでサインイン" - -#: client/src/job-results/job-results.partial.html:395 -#: client/src/job-submission/job-submission.partial.html:245 -#: client/src/templates/job_templates/job-template.form.js:217 -#: client/src/templates/job_templates/job-template.form.js:224 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:142 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:150 -msgid "Skip Tags" -msgstr "スキップタグ" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:148 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task." -msgstr "スキップタグは、Playbook のサイズが大きい場合にプレイまたはタスクの特定の部分をスキップする必要がある場合に役立ちます。" - -#: client/src/templates/job_templates/job-template.form.js:223 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task. Use commas to separate multiple tags. " -"Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"スキップタグは、Playbook " -"のサイズが大きい場合にプレイまたはタスクの特定の部分をスキップする必要がある場合に役立ちます。カンマを使って複数のタグを区切ります。タグの使用方法の詳細については、Ansible" -" Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:66 -msgid "Smart Host Filter" -msgstr "スマートホストフィルター" - -#: client/src/inventories-hosts/inventories/inventory.list.js:85 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/shared/form-generator.js:1456 -msgid "Smart Inventory" -msgstr "スマートインベントリー" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:44 -msgid "Solvable With Playbook" -msgstr "Playbook で解決可能" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:57 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:64 -msgid "Source" -msgstr "ソース" - -#: client/src/credentials/credentials.form.js:75 -msgid "Source Control" -msgstr "ソースコントロール" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:47 -#: client/src/projects/projects.form.js:25 -msgid "Source Details" -msgstr "ソース詳細" - -#: client/src/notifications/notificationTemplates.form.js:192 -#: client/src/notifications/notificationTemplates.form.js:193 -msgid "Source Phone Number" -msgstr "発信元の電話番号" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:136 -msgid "Source Regions" -msgstr "ソースリージョン" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:209 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:216 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:233 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:240 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:257 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:264 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:274 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:281 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:291 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:298 -msgid "Source Variables" -msgstr "ソース変数" - -#: client/src/partials/logviewer.html:9 -msgid "Source Vars" -msgstr "ソース変数" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:34 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:184 -msgid "Sources" -msgstr "ソース" - -#: client/src/notifications/notificationTemplates.form.js:330 -msgid "" -"Specify HTTP Headers in JSON format. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "JSON 形式で HTTP ヘッダーを指定します。構文のサンプルについては Ansible Tower ドキュメントを参照してください。" - -#: client/src/credentials/credentials.form.js:285 -msgid "" -"Specify a method for %s operations. This is equivalent to specifying the %s " -"parameter, where %s could be %s" -msgstr "%s 操作のメソッドを指定します。これは %s を指定することに相当します。%s は %s にすることができます。" - -#: client/src/notifications/notificationTemplates.form.js:292 -msgid "" -"Specify a notification color. Acceptable colors are: yellow, green, red " -"purple, gray or random." -msgstr "通知の色を指定します。使用できる色: 黄、緑、赤紫、灰色、またはランダム" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:199 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:283 -msgid "" -"Specify which groups to create automatically. Group names will be created " -"similar to the options selected. If blank, all groups above are created. " -"Refer to Ansible Tower documentation for more detail." -msgstr "" -"自動作成するグループを指定します。選択したオプションと同様のグループ名が作成されます。空白の場合は、上記のすべてのグループが作成されます。詳細については、Ansible" -" Tower ドキュメントを参照してください。" - -#: client/src/setup-menu/setup-menu.partial.html:17 -msgid "" -"Split up your organization to associate content and control permissions for " -"groups." -msgstr "組織を分割してコンテンツを関連付け、グループのパーミッションを制御します。" - -#: client/src/partials/logviewer.html:5 -msgid "Standard Out" -msgstr "標準出力" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:41 -msgid "Start Date" -msgstr "開始日" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:56 -msgid "Start Time" -msgstr "開始時間" - -#: client/src/portal-mode/portal-job-templates.list.js:39 -#: client/src/templates/templates.list.js:83 -msgid "Start a job using this template" -msgstr "このテンプレートを使用したジョブの開始" - -#: client/src/projects/edit/projects-edit.controller.js:134 -#: client/src/projects/list/projects-list.controller.js:74 -msgid "Start an SCM update" -msgstr "SCM 更新の開始" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:6 -msgid "Start sync process" -msgstr "同期プロセスの開始" - -#: client/src/job-results/job-results.partial.html:100 -msgid "Started" -msgstr "開始日時" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:53 -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:55 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:43 -#: client/src/job-results/job-results.partial.html:67 -#: client/src/job-results/parse-stdout.service.js:68 -#: client/src/notifications/notification-templates-list/list.controller.js:71 -#: client/src/partials/logviewer.html:4 -msgid "Status" -msgstr "ステータス" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:3 -msgid "Sub Category" -msgstr "サブカテゴリー" - -#: client/src/license/license.partial.html:126 -msgid "Submit" -msgstr "送信" - -#: client/src/jobs/factories/delete-job.factory.js:109 -msgid "Submit the request to cancel?" -msgstr "取り消す要求を送信しますか?" - -#: client/src/license/license.partial.html:27 -msgid "Subscription" -msgstr "サブスクリプション" - -#: client/src/credentials/credentials.form.js:151 -#: client/src/credentials/credentials.form.js:162 -msgid "Subscription ID" -msgstr "サブスクリプション ID" - -#: client/src/credentials/credentials.form.js:161 -msgid "Subscription ID is an Azure construct, which is mapped to a username." -msgstr "サブスクリプション ID は、ユーザー名にマップされる Azure コンストラクトです。" - -#: client/src/notifications/notifications.list.js:38 -msgid "Success" -msgstr "成功" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:21 -msgid "Success! Click for details" -msgstr "成功しました! クリックして詳細を確認してください。" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:77 -msgid "Successful" -msgstr "成功" - -#: client/src/job-submission/job-submission.partial.html:20 -msgid "Survey" -msgstr "Survey" - -#: client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js:60 -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:64 -msgid "" -"Surveys allow users to be prompted at job launch with a series of questions " -"related to the job. This allows for variables to be defined that affect the " -"playbook run at time of launch." -msgstr "" -"Survey により、ジョブに関連する一連の質問によるジョブ起動時のユーザーのプロモートが可能になります。これにより、起動時の Playbook " -"実行に影響を与える変数を定義できます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:58 -msgid "Sync all inventory sources" -msgstr "すべてのインベントリーソースの同期" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:29 -msgid "Sync canceled. Click to view log." -msgstr "同期が取り消されました。クリックしてログを表示します。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:35 -msgid "Sync completed. Click to view log." -msgstr "同期が完了しました。クリックしてログを表示します。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:32 -msgid "Sync failed. Click to view log." -msgstr "同期が失敗しました。クリックしてログを表示します。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "Sync not performed. Click" -msgstr "同期が実行されていません。次をクリックします。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:38 -msgid "Sync pending." -msgstr "同期が保留中です。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:45 -msgid "Sync running" -msgstr "同期が実行中です。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:46 -msgid "Sync running. Click to view log." -msgstr "同期が実行中です。クリックしてログを表示します。" - -#: client/src/configuration/configuration.partial.html:17 -msgid "System" -msgstr "システム" - -#: client/src/users/add/users-add.controller.js:12 -#: client/src/users/edit/users-edit.controller.js:12 -#: client/src/users/list/users-list.controller.js:12 -msgid "System Administrator" -msgstr "システム管理者" - -#: client/src/users/add/users-add.controller.js:11 -#: client/src/users/edit/users-edit.controller.js:11 -#: client/src/users/list/users-list.controller.js:11 -msgid "System Auditor" -msgstr "システム監査者" - -#: client/src/configuration/configuration.partial.html:3 -msgid "System auditors have read-only permissions in this section." -msgstr "システム監査者はこのセクションで読み取り専用パーミッションを持ちます。" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:114 -msgid "TACACS+" -msgstr "TACACS+" - -#: client/src/activity-stream/get-target-title.factory.js:23 -#: client/src/organizations/linkout/organizations-linkout.route.js:97 -#: client/src/organizations/list/organizations-list.controller.js:60 -#: client/src/teams/main.js:46 client/src/teams/teams.list.js:14 -#: client/src/teams/teams.list.js:15 -msgid "TEAMS" -msgstr "チーム" - -#: client/src/activity-stream/get-target-title.factory.js:44 -#: client/src/main-menu/main-menu.partial.html:113 -#: client/src/main-menu/main-menu.partial.html:35 -#: client/src/templates/list/templates-list.route.js:13 -#: client/src/templates/templates.list.js:15 -#: client/src/templates/templates.list.js:16 -msgid "TEMPLATES" -msgstr "テンプレート" - -#: client/src/instance-groups/instance-groups.list.js:8 -msgid "THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED" -msgstr "現時点で定義されたインスタンスグループはありません" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:104 -msgid "TIME" -msgstr "時間" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:61 -msgid "TOP" -msgstr "トップ" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:181 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:262 -msgid "Tag None:" -msgstr "タグ None:" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:133 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task." -msgstr "タグは、Playbook のサイズが大きい場合にプレイまたはタスクの特定の部分を実行する必要がある場合に役立ちます。" - -#: client/src/templates/job_templates/job-template.form.js:206 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task. Use commas to separate multiple tags. Refer" -" to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"タグは、Playbook " -"のサイズが大きい場合にプレイまたはタスクの特定の部分を実行する必要がある場合に役立ちます。カンマを使って複数のタグを区切ります。タグの使用方法の詳細については、Ansible" -" Tower ドキュメントを参照してください。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:179 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "Tags:" -msgstr "タグ:" - -#: client/src/notifications/notificationTemplates.form.js:309 -msgid "Target URL" -msgstr "ターゲット URL" - -#: client/src/job-results/job-results.partial.html:496 -msgid "Tasks" -msgstr "タスク" - -#: client/features/credentials/legacy.credentials.js:94 -#: client/src/credentials/credentials.form.js:467 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:154 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:155 -#: client/src/projects/projects.form.js:261 -#: client/src/templates/workflows.form.js:144 -msgid "Team Roles" -msgstr "チームロール" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:34 -#: client/src/organizations/linkout/organizations-linkout.route.js:108 -#: client/src/setup-menu/setup-menu.partial.html:16 -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/users/users.form.js:159 -msgid "Teams" -msgstr "チーム" - -#: client/src/job-results/job-results.partial.html:135 -#: client/src/templates/templates.list.js:14 -msgid "Template" -msgstr "テンプレート" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:35 -msgid "Templates" -msgstr "テンプレート" - -#: client/src/credentials/credentials.form.js:337 -msgid "Tenant ID" -msgstr "テナント ID" - -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:79 -msgid "Test" -msgstr "テスト" - -#: client/src/notifications/notificationTemplates.list.js:67 -msgid "Test notification" -msgstr "テスト通知" - -#: client/src/shared/form-generator.js:1386 -#: client/src/shared/form-generator.js:1392 -msgid "That value was not found. Please enter or select a valid value." -msgstr "値が見つかりませんでした。有効な値を入力または選択してください。" - -#: client/lib/components/components.strings.js:43 -msgid "That value was not found. Please enter or select a valid value." -msgstr "値が見つかりませんでした。有効な値を入力または選択してください。" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:66 -msgid "The Insights Credential for {{inventory.name}} was not found." -msgstr "{{inventory.name}} の Insights 認証情報が見つかりませんでした。" - -#: client/src/credentials/factories/become-method-change.factory.js:32 -#: client/src/credentials/factories/kind-change.factory.js:89 -msgid "" -"The Project ID is the GCE assigned identification. It is constructed as two " -"words followed by a three digit number. Such as:" -msgstr "プロジェクト ID は GCE によって割り当てられる識別情報です。これは、以下のように 2 語とそれに続く 3 桁の数字で構成されます。" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "The SCM update process is running." -msgstr "SCM 更新プロセスが実行中です。" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:70 -msgid "The credential used to run this command." -msgstr "このコマンドを実行するために使用される認証情報です。" - -#: client/src/credentials/credentials.form.js:190 -msgid "" -"The email address assigned to the Google Compute Engine %sservice account." -msgstr "Google Compute Engine %sサービスアカウントに割り当てられたメールアドレス。" - -#: client/src/job-results/job-results.partial.html:513 -msgid "The host count will update when the job is complete." -msgstr "ジョブの完了時にホスト数が更新されます。" - -#: client/src/credentials/factories/become-method-change.factory.js:62 -#: client/src/credentials/factories/kind-change.factory.js:119 -msgid "The host to authenticate with." -msgstr "認証するホスト。" - -#: client/src/credentials/factories/kind-change.factory.js:60 -msgid "The host value" -msgstr "ホスト値" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:61 -msgid "The inventory this command ran on." -msgstr "このコマンドが実行されるインベントリー。" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:101 -msgid "" -"The inventory will be in a pending status until the final delete is " -"processed." -msgstr "最終の削除が処理されるまでインベントリーは保留状態になります。" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:104 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Inputting no value will use the default value from the %sansible " -"configuration file%s." -msgstr "" -"Playbook の実行中に使用する並列または同時プロセスの数です。いずれの値も入力しないと、 %sansible 設定ファイル%s " -"のデフォルト値が使用されます。" - -#: client/src/templates/job_templates/job-template.form.js:152 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Value defaults to 0. Refer to the Ansible documentation for " -"details about the configuration file." -msgstr "" -"Playbook の実行中に使用する並列または同時プロセスの数です。デフォルト値は 0 になります。設定ファイルについての詳細は、Ansible " -"ドキュメントを参照してください。" - -#: client/src/job-results/job-results.controller.js:619 -msgid "The output is too large to display. Please download." -msgstr "出力が大きすぎて表示できません。ダウンロードしてください。" - -#: client/src/credentials/factories/kind-change.factory.js:59 -msgid "The project value" -msgstr "プロジェクト値" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "" -"The selected project is not configured for SCM. To configure for SCM, edit " -"the project and provide SCM settings, and then run an update." -msgstr "" -"選択されたプロジェクトは SCM に対して設定されていません。SCM の設定を行うには、プロジェクトを編集して SCM " -"設定を指定してから更新を実行します。" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:42 -msgid "" -"The standard output is too large to display. Please specify additional " -"filters to narrow the standard out." -msgstr "標準出力が大きすぎて表示できません。標準出力の範囲を制限するために追加のフィルターを指定してください。" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:52 -msgid "" -"The suggested format for variable names is lowercase and underscore-" -"separated (for example, foo_bar, user_id, host_name, etc.). Variable names " -"with spaces are not allowed." -msgstr "" -"推奨される変数名の形式は小文字のみを使用し、それらをアンダースコアで区切る形です (foo_bar、user_id、host_name " -"など)。スペースを含む変数名は許可されません。" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:124 -msgid "The time must be in HH24:MM:SS format." -msgstr "時間は HH24:MM:SS 形式で表示される必要があります。" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:79 -msgid "The user who ran this command." -msgstr "このコマンドを実行したユーザー。" - -#: client/src/activity-stream/streams.list.js:17 -msgid "There are no events to display at this time" -msgstr "現時点で表示できるイベントはありません" - -#: client/src/portal-mode/portal-job-templates.list.js:18 -msgid "There are no job templates to display at this time" -msgstr "現時点で表示できるジョブテンプレートはありません" - -#: client/src/portal-mode/portal-jobs.list.js:18 -msgid "There are no jobs to display at this time" -msgstr "現時点で表示できるジョブはありません" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "" -"There is no SCM update information available for this project. An update has" -" not yet been completed. If you have not already done so, start an update " -"for this project." -msgstr "" -"このプロジェクトに利用できる SCM " -"更新情報はありません。更新はまだ完了していません。まだ更新を実行していない場合は、このプロジェクトの更新を開始してください。" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:140 -msgid "There was an error deleting inventory source groups. Returned status:" -msgstr "インベントリーソースグループの削除中にエラーが発生しました。返されたステータス:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:130 -msgid "There was an error deleting inventory source hosts. Returned status:" -msgstr "インベントリーソースホストの削除中にエラーが発生しました。返されたステータス:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:167 -msgid "There was an error deleting inventory source. Returned status:" -msgstr "インベントリーソースの削除中にエラーが発生しました。返されたステータス:" - -#: client/src/configuration/configuration.controller.js:349 -msgid "There was an error resetting value. Returned status:" -msgstr "値のリセット中にエラーが発生しました。返されたステータス:" - -#: client/src/configuration/configuration.controller.js:531 -msgid "There was an error resetting values. Returned status:" -msgstr "値のリセット中にエラーが発生しました。返されたステータス:" - -#: client/src/configuration/system-form/configuration-system.controller.js:232 -msgid "There was an error testing the log aggregator. Returned status:" -msgstr "ログアグリゲーターのテスト中にエラーが発生しました。返されたステータス:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:29 -msgid "" -"These are the modules that {{BRAND_NAME}} supports running commands against." -msgstr "これらは {{BRAND_NAME}} がコマンドの実行をサポートするモジュールです。" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:26 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "This group contains" -msgstr "このグループには以下が含まれます。" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:168 -msgid "This is not a valid number." -msgstr "これは無効な数値です。" - -#: client/src/credentials/factories/become-method-change.factory.js:59 -#: client/src/credentials/factories/kind-change.factory.js:116 -msgid "" -"This is the tenant name. This value is usually the same as the username." -msgstr "これはテナント名です。通常、この値はユーザー名と同じです。" - -#: client/src/notifications/notifications.list.js:21 -msgid "" -"This list is populated by notification templates added from the " -"%sNotifications%s section" -msgstr "この一覧は、%s通知%s セクションで追加される通知テンプレートで事前に設定されます。" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:4 -msgid "" -"This machine has not checked in with Insights in {{last_check_in}} hours" -msgstr "このマシンは {{last_check_in}} 時間 Insights にチェックインしていません" - -#: client/src/shared/form-generator.js:746 -msgid "" -"This setting has been set manually in a settings file and is now disabled." -msgstr "この値は設定ファイルに手動で設定され、現在は無効にされています。" - -#: client/src/users/users.form.js:164 -msgid "This user is not a member of any teams" -msgstr "このユーザーはいずれのチームのメンバーでもありません。" - -#: client/src/shared/form-generator.js:856 -#: client/src/shared/form-generator.js:951 -msgid "" -"This value does not match the password you entered previously. Please " -"confirm that password." -msgstr "この値は以前に入力されたパスワードと一致しません。パスワードを確認してください。" - -#: client/src/configuration/configuration.controller.js:556 -msgid "" -"This will reset all configuration values to their factory defaults. Are you " -"sure you want to proceed?" -msgstr "これにより、すべての設定値が出荷時の設定にリセットされます。本当に続行してもよいですか?" - -#: client/src/activity-stream/streams.list.js:25 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:14 -#: client/src/notifications/notification-templates-list/list.controller.js:72 -msgid "Time" -msgstr "時間" - -#: client/src/license/license.partial.html:45 -msgid "Time Remaining" -msgstr "残りの時間" - -#: client/src/projects/projects.form.js:196 -msgid "" -"Time in seconds to consider a project to be current. During job runs and " -"callbacks the task system will evaluate the timestamp of the latest project " -"update. If it is older than Cache Timeout, it is not considered current, and" -" a new project update will be performed." -msgstr "" -"プロジェクトが最新であることを判別するために使用される時間 (秒単位) " -"です。タスクシステムは、ジョブ実行およびコールバック時にプロジェクト更新の最新のタイムスタンプを検証します。これがキャッシュタイムアウトよりも古い場合は最新とは見なされず、新規のプロジェクト更新が実行されます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:387 -msgid "" -"Time in seconds to consider an inventory sync to be current. During job runs" -" and callbacks the task system will evaluate the timestamp of the latest " -"sync. If it is older than Cache Timeout, it is not considered current, and a" -" new inventory sync will be performed." -msgstr "" -"インベントリーの同期が最新の状態であることを判別するために使用される時間 (秒単位) " -"です。ジョブの実行およびコールバック時に、タスクシステムは最新の同期のタイムスタンプを評価します。これがキャッシュタイムアウトよりも古い場合は最新とは見なされず、インベントリーの同期が新たに実行されます。" - -#: client/src/credentials/credentials.form.js:125 -msgid "" -"To learn more about the IAM STS Token, refer to the %sAmazon " -"documentation%s." -msgstr "IAM STS トークンについての詳細は、%sAmazon ドキュメント%s を参照してください。" - -#: client/src/shared/form-generator.js:881 -msgid "Toggle the display of plaintext." -msgstr "プレーンテキストの表示を切り替えます。" - -#: client/src/notifications/shared/type-change.service.js:34 -#: client/src/notifications/shared/type-change.service.js:40 -msgid "Token" -msgstr "トークン" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:44 -msgid "Too much previous output to display. Showing running standard output." -msgstr "直前の出力が大きすぎて表示できません。実行中の標準出力を表示しています。" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:10 -msgid "Total Issues" -msgstr "問題の合計" - -#: client/src/partials/logviewer.html:6 -msgid "Traceback" -msgstr "トレースバック" - -#: client/src/credentials/credentials.form.js:60 -#: client/src/credentials/credentials.form.js:84 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:52 -#: client/src/instance-groups/jobs/jobs.list.js:51 -#: client/src/inventories-hosts/inventories/inventory.list.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:52 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:41 -#: client/src/jobs/all-jobs.list.js:59 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:39 -#: client/src/notifications/notifications.list.js:31 -#: client/src/projects/projects.list.js:44 -#: client/src/scheduler/scheduled-jobs.list.js:42 -#: client/src/teams/teams.form.js:130 -#: client/src/templates/completed-jobs.list.js:53 -#: client/src/templates/templates.list.js:31 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:27 -#: client/src/users/users.form.js:200 -msgid "Type" -msgstr "タイプ" - -#: client/features/credentials/credentials.strings.js:18 -#: client/src/credentials/credentials.form.js:23 -#: client/src/notifications/notificationTemplates.form.js:26 -msgid "Type Details" -msgstr "タイプの詳細" - -#: client/src/projects/add/projects-add.controller.js:169 -#: client/src/projects/edit/projects-edit.controller.js:304 -msgid "URL popover text" -msgstr "URL ポップオーバーテキスト" - -#: client/src/login/loginModal/loginModal.partial.html:49 -msgid "USERNAME" -msgstr "ユーザー名" - -#: client/src/activity-stream/get-target-title.factory.js:20 -#: client/src/organizations/linkout/organizations-linkout.route.js:42 -#: client/src/organizations/list/organizations-list.controller.js:54 -#: client/src/users/main.js:46 client/src/users/users.list.js:18 -#: client/src/users/users.list.js:19 -msgid "USERS" -msgstr "ユーザー" - -#: client/lib/components/components.strings.js:20 -msgid "Unable to Submit" -msgstr "送信できません" - -#: client/lib/components/components.strings.js:52 -msgid "Unavailable to run jobs." -msgstr "ジョブの実行に使用できません。" - -#: client/lib/components/components.strings.js:22 -msgid "Unexpected Error" -msgstr "予期しないエラー" - -#: client/lib/components/components.strings.js:21 -msgid "Unexpected server error. View the console for more information" -msgstr "予期しないサーバーエラーが発生しました。コンソールで詳細情報を表示してください。" - -#: client/lib/components/components.strings.js:34 -msgid "Unsupported display model type" -msgstr "サポートされない表示モデルタイプ" - -#: client/lib/components/components.strings.js:26 -msgid "Unsupported input type" -msgstr "サポートされない入力タイプ" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "Update Not Found" -msgstr "更新が見つかりません" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:321 -msgid "Update Options" -msgstr "オプションの更新" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "Update in Progress" -msgstr "更新が進行中です" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:352 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:357 -#: client/src/projects/projects.form.js:177 -msgid "Update on Launch" -msgstr "起動時の更新" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:364 -msgid "Update on Project Change" -msgstr "プロジェクト変更時の更新" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:370 -msgid "Update on Project Update" -msgstr "プロジェクト更新時の更新" - -#: client/src/license/license.partial.html:71 -msgid "Upgrade" -msgstr "アップグレード" - -#: client/src/templates/job_templates/job-template.form.js:299 -#: client/src/templates/job_templates/job-template.form.js:304 -msgid "Use Fact Cache" -msgstr "ファクトのキャッシュの使用" - -#: client/src/notifications/notificationTemplates.form.js:395 -msgid "Use SSL" -msgstr "SSL の使用" - -#: client/src/notifications/notificationTemplates.form.js:390 -msgid "Use TLS" -msgstr "TLS の使用" - -#: client/src/instance-groups/instance-group.partial.html:10 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:10 -#: client/src/instance-groups/instances/instances-list.partial.html:21 -#: client/src/instance-groups/list/instance-groups-list.partial.html:32 -msgid "Used Capacity" -msgstr "使用済み容量" - -#: client/src/credentials/credentials.form.js:76 -msgid "" -"Used to check out and synchronize playbook repositories with a remote source" -" control management system such as Git, Subversion (svn), or Mercurial (hg)." -" These credentials are used by Projects." -msgstr "" -"Git、Subversion (svn)、または Mercurial (hg) などのリモートソースコントロール管理システムで Playbook " -"リポジトリーをチェックアウトし、同期するために使用されます。これらの認証情報はプロジェクトで使用されます。" - -#: client/features/credentials/legacy.credentials.js:83 -#: client/src/credentials/credentials.form.js:456 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:143 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:144 -#: client/src/organizations/organizations.form.js:92 -#: client/src/projects/projects.form.js:250 client/src/teams/teams.form.js:93 -#: client/src/templates/workflows.form.js:133 -msgid "User" -msgstr "ユーザー" - -#: client/src/configuration/configuration.partial.html:18 -msgid "User Interface" -msgstr "ユーザーインターフェース" - -#: client/src/users/users.form.js:95 -msgid "User Type" -msgstr "ユーザータイプ" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:30 -#: client/src/credentials/factories/become-method-change.factory.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:38 -#: client/src/credentials/factories/kind-change.factory.js:17 -#: client/src/credentials/factories/kind-change.factory.js:41 -#: client/src/credentials/factories/kind-change.factory.js:74 -#: client/src/credentials/factories/kind-change.factory.js:95 -#: client/src/notifications/notificationTemplates.form.js:64 -#: client/src/users/users.form.js:58 client/src/users/users.list.js:29 -msgid "Username" -msgstr "ユーザー名" - -#: client/src/credentials/credentials.form.js:80 -msgid "" -"Usernames, passwords, and access keys for authenticating to the specified " -"cloud or infrastructure provider. These are used for smart inventory sources" -" and for cloud provisioning and deployment in playbook runs." -msgstr "" -"指定されたクラウドまたはインフラストラクチャープロバイダーに対する認証を行うためのユーザー名、パスワード、およびアクセスキーです。これらはスマートインベントリーソース、および" -" Playbook 実行におけるクラウドプロビジョニングおよびデプロイメントに使用されます。" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:36 -#: client/src/organizations/organizations.form.js:74 -#: client/src/setup-menu/setup-menu.partial.html:10 -#: client/src/teams/teams.form.js:75 -msgid "Users" -msgstr "ユーザー" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:7 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:7 -msgid "VIEW ALL" -msgstr "すべてを表示" - -#: client/src/main-menu/main-menu.partial.html:75 -msgid "VIEW DOCUMENTATION" -msgstr "ドキュメントの表示" - -#: client/src/shared/paginate/paginate.partial.html:48 -msgid "VIEW PER PAGE" -msgstr "ページ別のビュー" - -#: client/src/main-menu/main-menu.partial.html:51 -msgid "VIEW USER PAGE FOR {{ $root.current_user.username | uppercase }}" -msgstr "{{ $root.current_user.username | uppercase }} のユーザーページの表示" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:180 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:261 -msgid "VPC ID:" -msgstr "VPC ID:" - -#: client/src/license/license.partial.html:10 -msgid "Valid License" -msgstr "有効なライセンス" - -#: client/src/inventories-hosts/hosts/host.form.js:68 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:46 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:67 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:67 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:81 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:88 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:94 -msgid "Variables" -msgstr "変数" - -#: client/src/job-submission/job-submission.partial.html:364 -msgid "Vault" -msgstr "Vault" - -#: client/src/job-results/job-results.partial.html:321 -msgid "Vault Credential" -msgstr "Vault 認証情報" - -#: client/src/credentials/credentials.form.js:391 -#: client/src/job-submission/job-submission.partial.html:146 -msgid "Vault Password" -msgstr "Vault パスワード" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:81 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:90 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:307 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:314 -#: client/src/job-results/job-results.partial.html:358 -#: client/src/job-submission/job-submission.partial.html:183 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:99 -#: client/src/templates/job_templates/job-template.form.js:174 -#: client/src/templates/job_templates/job-template.form.js:181 -msgid "Verbosity" -msgstr "詳細" - -#: client/src/license/license.partial.html:15 -msgid "Version" -msgstr "バージョン" - -#: client/src/activity-stream/streams.list.js:63 -#: client/src/credential-types/credential-types.list.js:64 -#: client/src/credentials/credentials.list.js:75 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:58 -#: client/src/inventories-hosts/inventories/inventory.list.js:104 -#: client/src/inventory-scripts/inventory-scripts.list.js:62 -#: client/src/notifications/notificationTemplates.list.js:82 -#: client/src/scheduler/schedules.list.js:83 client/src/teams/teams.list.js:64 -#: client/src/templates/templates.list.js:112 -#: client/src/users/users.list.js:70 -msgid "View" -msgstr "表示" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "View Activity Stream" -msgstr "アクティビティーストリームの表示" - -#: client/src/main-menu/main-menu.partial.html:173 -msgid "View Documentation" -msgstr "ドキュメントの表示" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:79 -msgid "View Insights Data" -msgstr "Insights データの表示" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:202 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:226 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:250 -msgid "View JSON examples at" -msgstr "JSON サンプルの表示: " - -#: client/src/inventories-hosts/hosts/host.form.js:78 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:77 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:77 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:91 -msgid "View JSON examples at %s" -msgstr "JSON サンプルを %s に表示" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:13 -msgid "View Less" -msgstr "簡易表示" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:11 -msgid "View More" -msgstr "詳細表示" - -#: client/src/shared/form-generator.js:1719 -#: client/src/templates/job_templates/job-template.form.js:436 -#: client/src/templates/workflows.form.js:161 -msgid "View Survey" -msgstr "Survey の表示" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:203 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:227 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:251 -msgid "View YAML examples at" -msgstr "YAML サンプルの表示: " - -#: client/src/inventories-hosts/hosts/host.form.js:79 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:78 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:78 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:92 -msgid "View YAML examples at %s" -msgstr "YAML サンプルを %s に表示" - -#: client/src/setup-menu/setup-menu.partial.html:72 -msgid "View Your License" -msgstr "ライセンスの表示" - -#: client/src/setup-menu/setup-menu.partial.html:73 -msgid "View and edit your license information." -msgstr "ライセンス情報を表示し、編集します。" - -#: client/src/credentials/credentials.list.js:77 -msgid "View credential" -msgstr "認証情報の表示" - -#: client/src/credential-types/credential-types.list.js:66 -msgid "View credential type" -msgstr "認証情報タイプの表示" - -#: client/src/activity-stream/streams.list.js:67 -msgid "View event details" -msgstr "イベント詳細の表示" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:93 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:103 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:91 -msgid "View group" -msgstr "グループの表示" - -#: client/src/inventories-hosts/hosts/host.list.js:89 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:93 -msgid "View host" -msgstr "ホストの表示" - -#: client/src/setup-menu/setup-menu.partial.html:67 -msgid "View information about this version of Ansible {{BRAND_NAME}}." -msgstr "本バージョンの Ansible {{BRAND_NAME}} についての情報を表示します。" - -#: client/src/inventories-hosts/inventories/inventory.list.js:106 -msgid "View inventory" -msgstr "インベントリーの表示" - -#: client/src/inventory-scripts/inventory-scripts.list.js:64 -msgid "View inventory script" -msgstr "インベントリースクリプトの表示" - -#: client/src/setup-menu/setup-menu.partial.html:55 -msgid "View list and capacity of {{BRAND_NAME}} instances." -msgstr "{{BRAND_NAME}} インスタンスの一覧および容量を表示します。" - -#: client/src/notifications/notificationTemplates.list.js:84 -msgid "View notification" -msgstr "通知の表示" - -#: client/src/job-results/job-results.partial.html:222 -msgid "View project sync results" -msgstr "プロジェクトの同期結果の表示" - -#: client/src/scheduler/schedules.list.js:85 -msgid "View schedule" -msgstr "スケジュールの表示" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:118 -msgid "View source" -msgstr "ソースの表示" - -#: client/src/teams/teams.list.js:67 -msgid "View team" -msgstr "チームの表示" - -#: client/src/templates/templates.list.js:114 -msgid "View template" -msgstr "テンプレートの表示" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "View the" -msgstr "次の表示:" - -#: client/src/jobs/all-jobs.list.js:92 -msgid "View the job" -msgstr "ジョブの表示" - -#: client/src/projects/projects.list.js:111 -msgid "View the project" -msgstr "プロジェクトの表示" - -#: client/src/scheduler/scheduled-jobs.list.js:74 -msgid "View the schedule" -msgstr "スケジュールの表示" - -#: client/src/users/users.list.js:73 -msgid "View user" -msgstr "ユーザーの表示" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:42 -#: client/src/instance-groups/jobs/jobs.list.js:41 -#: client/src/job-results/job-results.partial.html:145 -#: client/src/jobs/all-jobs.list.js:49 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:25 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:25 -msgid "View workflow results" -msgstr "ワークフロー結果の表示" - -#: client/src/templates/workflows.form.js:20 -msgid "WORKFLOW" -msgstr "ワークフロー" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:73 -#: client/src/configuration/configuration.controller.js:200 -#: client/src/configuration/configuration.controller.js:262 -#: client/src/configuration/system-form/configuration-system.controller.js:55 -msgid "Warning: Unsaved Changes" -msgstr "警告: 変更が保存されていません" - -#: client/src/license/license.partial.html:78 -msgid "" -"Welcome to Ansible Tower! Please complete the steps below to acquire a " -"license." -msgstr "Ansible Tower へようこそ! ライセンスを取得するために以下のステップを完了してください。" - -#: client/src/login/loginModal/loginModal.partial.html:17 -msgid "Welcome to Ansible {{BRAND_NAME}}!  Please sign in." -msgstr "Ansible {{BRAND_NAME}} へようこそ!  サインインしてください。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:344 -msgid "" -"When not checked, a merge will be performed, combining local variables with " -"those found on the external source." -msgstr "チェックが付けられていない場合、ローカル変数と外部ソースにあるものを組み合わせるマージが実行されます。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:332 -msgid "" -"When not checked, local child hosts and groups not found on the external " -"source will remain untouched by the inventory update process." -msgstr "" -"チェックが付けられていない場合、外部ソースにないローカルの子ホストおよびグループは、インベントリーの更新プロセスによって処理されないままになります。" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:97 -msgid "" -"When this template is submitted as a job, setting the type to %s will " -"execute the playbook, running tasks on the selected hosts." -msgstr "" -"このテンプレートがジョブとして送信される場合、タイプを %s に設定すると Playbook が実行され、選択されたホストでタスクが実行されます。" - -#: client/src/shared/form-generator.js:1723 -#: client/src/templates/workflows.form.js:187 -msgid "Workflow Editor" -msgstr "ワークフローエディター" - -#: client/src/templates/templates.list.js:66 -msgid "Workflow Template" -msgstr "ワークフローテンプレート" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:41 -msgid "Workflow Templates" -msgstr "ワークフローテンプレート" - -#: client/src/job-submission/job-submission.partial.html:171 -msgid "YAML" -msgstr "YAML" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:200 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:224 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:248 -msgid "YAML:" -msgstr "YAML:" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Yellow" -msgstr "黄" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:56 -msgid "" -"You can create a job template here." -msgstr "ジョブテンプレートの作成はここから実行できます。" - -#: client/src/projects/edit/projects-edit.controller.js:62 -msgid "You do not have access to view this property" -msgstr "これを適切に表示するためのアクセス権がありません。" - -#: client/src/projects/add/projects-add.controller.js:29 -msgid "You do not have permission to add a project." -msgstr "プロジェクトを追加するパーミッションがありません。" - -#: client/src/users/add/users-add.controller.js:43 -msgid "You do not have permission to add a user." -msgstr "ユーザーを追加するパーミッションがありません。" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:28 -msgid "You do not have sufficient permissions to edit the host filter." -msgstr "ホストフィルターの編集に必要なパーミッションがありません。" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:72 -#: client/src/configuration/configuration.controller.js:199 -#: client/src/configuration/configuration.controller.js:261 -#: client/src/configuration/system-form/configuration-system.controller.js:54 -msgid "" -"You have unsaved changes. Would you like to proceed without" -" saving?" -msgstr "保存されていない変更があります。変更せずに次に進みますか?" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "Your request to cancel the update was submitted to the task manager." -msgstr "更新を取り消す要求がタスクマネージャーに送信されました。" - -#: client/src/login/loginModal/loginModal.partial.html:22 -msgid "Your session timed out due to inactivity. Please sign in." -msgstr "アイドル時間によりセッションがタイムアウトしました。サインインしてください。" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/shared/form-generator.js:1193 -msgid "and" -msgstr "and" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "characters long." -msgstr "文字の長さ。" - -#: client/src/shared/smart-search/smart-search.partial.html:53 -msgid "documentation" -msgstr "ドキュメント" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:193 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:275 -msgid "for a complete list of supported filters." -msgstr "サポートされるフィルターの詳細の一覧" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "from the" -msgstr " 削除元:" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -#: client/src/inventories-hosts/inventory-hosts.strings.js:8 -msgid "group" -msgid_plural "groups" -msgstr[0] "グループ" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "groups" -msgstr "グループ" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -msgid "groups and" -msgstr "グループおよび" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:9 -msgid "host" -msgid_plural "hosts" -msgstr[0] "ホスト" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -msgid "hosts" -msgstr "ホスト" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:58 -msgid "hosts with failures. Click for details." -msgstr "障害のあるホストです。クリックして詳細を確認してください。" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:21 -msgid "name" -msgstr "名前" - -#: client/src/shared/paginate/paginate.partial.html:34 -msgid "of" -msgstr " /" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "of the filters match." -msgstr "フィルターの一致:" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:24 -msgid "organization" -msgstr "組織" - -#: client/src/shared/form-generator.js:1069 -msgid "playbook" -msgstr "Playbook" - -#: client/src/credentials/credentials.form.js:138 -#: client/src/credentials/credentials.form.js:364 -msgid "set in helpers/credentials" -msgstr "ヘルパー/認証情報で設定" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:43 -msgid "sources with sync failures. Click for details" -msgstr "同期が失敗しているソースです。クリックして詳細を確認してください。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "test" -msgstr "テスト" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "to" -msgstr " " - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "" -"to include all regions. Only Hosts associated with the selected regions will" -" be updated." -msgstr "すべてのリージョンが含まれます。選択したリージョンに関連付けられたホストのみが更新されます。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "to start it now." -msgstr "すぐに開始します。" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "to update." -msgstr "更新します。" - -#: client/src/credentials/credentials.form.js:381 -msgid "v2 URLs%s - leave blank" -msgstr "v2 URL%s - 空白にする" - -#: client/src/credentials/credentials.form.js:382 -msgid "v3 default%s - set to 'default'" -msgstr "v3 デフォルト%s - 「デフォルト」に設定" - -#: client/src/credentials/credentials.form.js:383 -msgid "v3 multi-domain%s - your domain name" -msgstr "v3 マルチドメイン%s - ドメイン名" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:220 -msgid "view ec2.ini in the Ansible github repo." -msgstr "ec2.ini を Ansible github リポジトリーで表示します。" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:244 -msgid "view vmware_inventory.ini in the Ansible github repo." -msgstr "vmware_inventory.ini を Ansible github リポジトリーで表示します。" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "when" -msgstr "日付" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:171 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:252 -msgid "" -"will create group names similar to the following examples based on the " -"options selected:" -msgstr "選択されたオプションに基づいて以下のサンプルと同様のグループ名が作成されます。" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:11 -msgid "with failed jobs." -msgstr "ジョブの失敗" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs-list.route.js:9 -msgid "{{ breadcrumb.instance_name }}" -msgstr "{{ breadcrumb.instance_name }}" - -#: client/lib/components/input/label.partial.html:5 -msgid "{{::state._hint}}" -msgstr "{{::state._hint}}" - -#: client/src/instance-groups/instances/instances-list.route.js:10 -msgid "{{breadcrumb.instance_group_name}}" -msgstr "{{breadcrumb.instance_group_name}}" - -#: client/src/shared/paginate/paginate.partial.html:55 -msgid "{{pageSize}}" -msgstr "{{pageSize}}" diff --git a/awx/ui/po/nl.po b/awx/ui/po/nl.po deleted file mode 100644 index a914aa446889..000000000000 --- a/awx/ui/po/nl.po +++ /dev/null @@ -1,6074 +0,0 @@ -# Froebel Flores , 2017. #zanata -# helena , 2017. #zanata -# helena02 , 2017. #zanata -msgid "" -msgstr "" -"Project-Id-Version: \n" -"PO-Revision-Date: 2017-12-06 02:10+0000\n" -"Last-Translator: helena \n" -"Language-Team: Dutch\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nl\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"X-Generator: Zanata 4.3.2\n" - -#: client/src/projects/add/projects-add.controller.js:153 -#: client/src/projects/edit/projects-edit.controller.js:288 -msgid "" -"%sNote:%s Mercurial does not support password authentication for SSH. Do not" -" put the username and key in the URL. If using Bitbucket and SSH, do not " -"supply your Bitbucket username." -msgstr "" -"%sLet op:%s wachtwoordauthenticatie voor SSH wordt niet ondersteund door " -"Mercurial. Zet de gebruikersnaam en sleutel niet in de URL. Indien u " -"Bitbucket en SSH gebruikt, noem uw Bitbucket-gebruikersnaam dan niet." - -#: client/src/projects/add/projects-add.controller.js:132 -#: client/src/projects/edit/projects-edit.controller.js:267 -msgid "" -"%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key " -"only, do not enter a username (other than git). Additionally, GitHub and " -"Bitbucket do not support password authentication when using SSH. GIT read " -"only protocol (git://) does not use username or password information." -msgstr "" -"%sLet op:%s als u een SSH-protocol gebruikt voor GitHub of Bitbucket, voer " -"dan alleen een SSH-sleutel in. Voer geen gebruikersnaam in (behalve git). " -"Daarnaast ondersteunen GitHub en Bitbucket geen wachtwoordauthenticatie bij " -"gebruik van SSH. Het GIT-alleen-lezen-protocol (git://) gebruikt geen " -"gebruikersnaam- of wachtwoordinformatie." - -#: client/src/credentials/credentials.form.js:287 -msgid "(defaults to %s)" -msgstr "(wordt standaard %s)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -msgid "(seconds)" -msgstr "(seconden)" - -#: client/src/organizations/list/organizations-list.partial.html:20 -msgid "+ ADD" -msgstr "+ TOEVOEGEN" - -#: client/src/shared/paginate/paginate.partial.html:66 -msgid "100" -msgstr "100" - -#: client/src/shared/paginate/paginate.partial.html:60 -msgid "20" -msgstr "20" - -#: client/src/shared/paginate/paginate.partial.html:63 -msgid "50" -msgstr "50" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:33 -msgid "A schedule name is required." -msgstr "Een naam voor het schema is vereist." - -#: client/src/users/add/users-add.controller.js:102 -msgid "A value is required" -msgstr "Een waarde is vereist" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:167 -msgid "A value is required." -msgstr "Een waarde is vereist." - -#: client/src/about/about.route.js:10 -msgid "ABOUT" -msgstr "OVER" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 -msgid "ACTION" -msgstr "ACTIE" - -#: client/src/activity-stream/activity-detail.form.js:23 -msgid "ACTIVITY DETAIL" -msgstr "ACTIVITEITSGEGEVENS" - -#: client/src/activity-stream/activitystream.route.js:28 -#: client/src/activity-stream/streams.list.js:14 -#: client/src/activity-stream/streams.list.js:15 -msgid "ACTIVITY STREAM" -msgstr "ACTIVITEITENLOGBOEK" - -#: client/features/credentials/legacy.credentials.js:76 -#: client/src/credential-types/credential-types.list.js:44 -#: client/src/credentials/credentials.form.js:449 -#: client/src/credentials/credentials.list.js:54 -#: client/src/inventories-hosts/inventories/inventory.list.js:77 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:71 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:120 -#: client/src/inventory-scripts/inventory-scripts.list.js:42 -#: client/src/notifications/notificationTemplates.list.js:54 -#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 -#: client/src/organizations/organizations.form.js:84 -#: client/src/projects/projects.form.js:243 -#: client/src/projects/projects.list.js:78 -#: client/src/scheduler/schedules.list.js:68 client/src/teams/teams.form.js:85 -#: client/src/teams/teams.list.js:45 -#: client/src/templates/job_templates/job-template.form.js:397 -#: client/src/templates/templates.list.js:58 -#: client/src/templates/workflows.form.js:125 -#: client/src/users/users.list.js:50 -msgid "ADD" -msgstr "TOEVOEGEN" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:71 -msgid "ADD GROUP" -msgstr "GROEP TOEVOEGEN" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:125 -msgid "ADD HOST" -msgstr "HOST TOEVOEGEN" - -#: client/src/teams/teams.form.js:157 client/src/users/users.form.js:216 -msgid "ADD PERMISSIONS" -msgstr "MACHTIGINGEN TOEVOEGEN" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:70 -msgid "ADD SOURCE" -msgstr "BRON TOEVOEGEN" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:16 -msgid "ADD SURVEY PROMPT" -msgstr "MELDING VRAGENLIJST TOEVOEGEN" - -#: client/src/shared/smart-search/smart-search.partial.html:51 -msgid "ADDITIONAL INFORMATION" -msgstr "AANVULLENDE INFORMATIE" - -#: client/src/organizations/linkout/organizations-linkout.route.js:330 -#: client/src/organizations/list/organizations-list.controller.js:84 -msgid "ADMINS" -msgstr "BEHEERDERS" - -#: client/src/activity-stream/get-target-title.factory.js:4 -msgid "ALL ACTIVITY" -msgstr "ALLE ACTIVITEIT" - -#: client/src/jobs/all-jobs.list.js:14 -msgid "ALL JOBS" -msgstr "ALLE TAKEN" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "ANY" -msgstr "IEDERE" - -#: client/src/credentials/credentials.form.js:198 -msgid "API Key" -msgstr "API-sleutel" - -#: client/src/notifications/notificationTemplates.form.js:243 -msgid "API Service/Integration Key" -msgstr "Service-/integratiesleutel API" - -#: client/src/notifications/shared/type-change.service.js:52 -msgid "API Token" -msgstr "API-token" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:71 -msgid "ASSOCIATE GROUP" -msgstr "GROEP VERBINDEN" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.route.js:19 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.route.js:19 -msgid "ASSOCIATED GROUPS" -msgstr "VERBONDEN GROEPEN" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.route.js:19 -msgid "ASSOCIATED HOSTS" -msgstr "VERBONDEN HOSTS" - -#: client/src/setup-menu/setup-menu.partial.html:66 -msgid "About {{BRAND_NAME}}" -msgstr "Over {{BRAND_NAME}}" - -#: client/src/credentials/credentials.form.js:91 -msgid "Access Key" -msgstr "Toegangssleutel" - -#: client/src/notifications/notificationTemplates.form.js:221 -msgid "Account SID" -msgstr "SID account" - -#: client/src/notifications/notificationTemplates.form.js:180 -msgid "Account Token" -msgstr "Accounttoken" - -#: client/src/activity-stream/activity-detail.form.js:36 -msgid "Action" -msgstr "Actie" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/inventories-hosts/hosts/hosts.partial.html:47 -#: client/src/shared/list-generator/list-generator.factory.js:573 -msgid "Actions" -msgstr "Acties" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:17 -#: client/src/templates/templates.list.js:36 -msgid "Activity" -msgstr "Activiteit" - -#: client/src/configuration/system-form/configuration-system.controller.js:88 -msgid "Activity Stream" -msgstr "Activiteitenlogboek" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:131 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:132 -#: client/src/organizations/organizations.form.js:81 -#: client/src/teams/teams.form.js:82 -#: client/src/templates/workflows.form.js:122 -msgid "Add" -msgstr "Toevoegen" - -#: client/src/credentials/credentials.list.js:14 -msgid "Add Credentials" -msgstr "Toegangsgegevens toevoegen" - -#: client/src/inventories-hosts/inventories/inventory.list.js:13 -msgid "Add Inventories" -msgstr "Inventarissen toevoegen" - -#: client/src/shared/stateDefinitions.factory.js:288 -msgid "Add Permissions" -msgstr "Machtigingen toevoegen" - -#: client/src/projects/projects.list.js:13 -msgid "Add Project" -msgstr "Project toevoegen" - -#: client/src/shared/form-generator.js:1711 -#: client/src/templates/job_templates/job-template.form.js:445 -#: client/src/templates/workflows.form.js:170 -msgid "Add Survey" -msgstr "Vragenlijst toevoegen" - -#: client/src/teams/teams.list.js:13 -msgid "Add Team" -msgstr "Team toevoegen" - -#: client/src/teams/teams.form.js:83 -msgid "Add User" -msgstr "Gebruiker toevoegen" - -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/shared/stateDefinitions.factory.js:578 -#: client/src/users/users.list.js:17 -msgid "Add Users" -msgstr "Gebruikers toevoegen" - -#: client/src/organizations/organizations.form.js:82 -msgid "Add Users to this organization." -msgstr "Gebruikers toevoegen aan deze organisatie." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:69 -msgid "Add a group" -msgstr "Een groep toevoegen" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:118 -msgid "Add a host" -msgstr "Een host toevoegen" - -#: client/src/scheduler/schedules.list.js:66 -msgid "Add a new schedule" -msgstr "Een nieuw schema toevoegen" - -#: client/features/credentials/legacy.credentials.js:74 -#: client/src/credentials/credentials.form.js:447 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:133 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:134 -#: client/src/projects/projects.form.js:241 -#: client/src/templates/job_templates/job-template.form.js:395 -#: client/src/templates/workflows.form.js:123 -msgid "Add a permission" -msgstr "Een machtiging toevoegen" - -#: client/src/setup-menu/setup-menu.partial.html:23 -msgid "" -"Add passwords, SSH keys, and other credentials to use when launching jobs " -"against machines, or when syncing inventories or projects." -msgstr "" -"Wachtwoorden, SSH-sleutels en andere toegangsgegevens toevoegen voor gebruik" -" bij het starten van taken m.b.t. machines of bij het synchroniseren van " -"inventarissen of projecten." - -#: client/src/shared/form-generator.js:1446 -msgid "Admin" -msgstr "Beheerder" - -#: client/src/organizations/linkout/organizations-linkout.route.js:354 -msgid "Admins" -msgstr "Beheerders" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:367 -msgid "" -"After every project update where the SCM revision changes, refresh the " -"inventory from the selected source before executing job tasks. This is " -"intended for static content, like the Ansible inventory .ini file format." -msgstr "" -"Na iedere projectupdate waarbij de SCM-revisie verandert, dient het " -"inventaris vernieuwd te worden vanuit de geselecteerde bron voordat de " -"opdrachten die bij de taak horen uitgevoerd worden. Dit is bedoeld voor " -"statische content, zoals .ini, het inventarisbestandsformaat van Ansible." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:37 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:43 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:65 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:74 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "All" -msgstr "Alle" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 -msgid "All Activity" -msgstr "Alle activiteit" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:10 -#: client/src/portal-mode/portal-mode-layout.partial.html:17 -msgid "All Jobs" -msgstr "Alle taken" - -#: client/src/templates/job_templates/job-template.form.js:275 -#: client/src/templates/job_templates/job-template.form.js:282 -msgid "Allow Provisioning Callbacks" -msgstr "Provisioning terugkoppelingen toestaan" - -#: client/src/setup-menu/setup-menu.partial.html:11 -msgid "" -"Allow others to sign into {{BRAND_NAME}} and own the content they create." -msgstr "" -"Anderen toestaan zich aan te melden bij {{BRAND_NAME}} en eigenaar te " -"blijven van de content die ze aanmaken." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:43 -msgid "Always" -msgstr "Altijd" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "" -"An SCM update does not appear to be running for project: %s. Click the " -"%sRefresh%s button to view the latest status." -msgstr "" -"Het lijkt er op dat er geen SCM-update bezig is voor project: %s. Klik op de" -" knop %sVernieuwen%s om de nieuwste status in te zien." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:62 -#: client/src/templates/survey-maker/shared/question-definition.form.js:68 -msgid "Answer Type" -msgstr "Antwoordtype" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:44 -#: client/src/templates/survey-maker/shared/question-definition.form.js:53 -msgid "Answer Variable Name" -msgstr "Antwoord naam variabele" - -#: client/src/job-results/job-results.service.js:144 -msgid "Are you sure you want to cancel the job below?" -msgstr "Weet je zeker dat u de onderstaande taak wilt annuleren?" - -#: client/src/credentials/list/credentials-list.controller.js:133 -msgid "Are you sure you want to delete the credential below?" -msgstr "Weet u zeker dat u onderstaande toegangsgegevens wilt verwijderen?" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:100 -msgid "Are you sure you want to delete the inventory below?" -msgstr "Weet u zeker dat u onderstaande inventaris wilt verwijderen?" - -#: client/src/job-results/job-results.service.js:95 -#: client/src/jobs/factories/delete-job.factory.js:110 -msgid "Are you sure you want to delete the job below?" -msgstr "Weet u zeker dat u onderstaande taak wilt verwijderen?" - -#: client/src/notifications/notification-templates-list/list.controller.js:190 -msgid "Are you sure you want to delete the notification template below?" -msgstr "Weet u zeker dat u onderstaand berichtsjabloon wilt verwijderen?" - -#: client/src/organizations/list/organizations-list.controller.js:172 -msgid "Are you sure you want to delete the organization below?" -msgstr "Weet u zeker dat u onderstaande organisatie wilt verwijderen?" - -#: client/src/projects/list/projects-list.controller.js:208 -msgid "Are you sure you want to delete the project below?" -msgstr "Weet u zeker dat u onderstaand project wilt verwijderen?" - -#: client/src/templates/list/templates-list.controller.js:103 -msgid "Are you sure you want to delete the template below?" -msgstr "Weet je zeker dat u het onderstaande sjabloon wilt verwijderen?" - -#: client/src/users/list/users-list.controller.js:90 -msgid "Are you sure you want to delete the user below?" -msgstr "Weet u zeker dat u onderstaande gebruiker wilt verwijderen?" - -#: client/src/partials/survey-maker-modal.html:13 -msgid "Are you sure you want to delete this {{deleteMode}}?" -msgstr "Weet u zeker dat u deze {{deleteMode}} wilt verwijderen?" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:25 -msgid "Are you sure you want to disassociate the group below from" -msgstr "Weet u zeker dat u onderstaande groep los wilt koppelen van" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:23 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:26 -msgid "Are you sure you want to disassociate the host below from" -msgstr "Weet u zeker dat u onderstaande host los wilt koppelen van" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:47 -msgid "" -"Are you sure you want to permanently delete the group below from the " -"inventory?" -msgstr "" -"Weet u zeker dat u onderstaande groep permanent wilt verwijderen uit de " -"inventaris?" - -#: client/src/inventories-hosts/inventories/related/hosts/list/host-list.controller.js:106 -msgid "" -"Are you sure you want to permanently delete the host below from the " -"inventory?" -msgstr "Weet u zeker dat u onderstaande host permanent wilt verwijderen?" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:69 -msgid "" -"Are you sure you want to permanently delete the inventory source below from " -"the inventory?" -msgstr "" -"Weet u zeker dat u onderstaande inventarisbron permanent wilt verwijderen " -"uit de inventaris?" - -#: client/src/projects/edit/projects-edit.controller.js:244 -msgid "Are you sure you want to remove the %s below from %s?" -msgstr "Weet u zeker dat u onderstaande %s wilt verwijderen uit de %s?" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:39 -msgid "Arguments" -msgstr "Argumenten" - -#: client/src/credentials/credentials.form.js:232 -#: client/src/credentials/credentials.form.js:271 -#: client/src/credentials/credentials.form.js:311 -#: client/src/credentials/credentials.form.js:397 -msgid "Ask at runtime?" -msgstr "Vragen bij runtime?" - -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:69 -msgid "Associate an existing group" -msgstr "Een bestaande groep verbinden" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:51 -msgid "Associate this host with a new group" -msgstr "Deze host verbinden met een nieuwe groep" - -#: client/src/shared/form-generator.js:1448 -msgid "Auditor" -msgstr "Auditor" - -#: client/src/configuration/configuration.partial.html:15 -msgid "Authentication" -msgstr "Authenticatie" - -#: client/src/credentials/credentials.form.js:72 -msgid "" -"Authentication for network device access. This can include SSH keys, " -"usernames, passwords, and authorize information. Network credentials are " -"used when submitting jobs to run playbooks against network devices." -msgstr "" -"Authenticatie voor toegang tot het netwerkapparaat. Hieronder kunnen vallen:" -" SSH-sleutels, gebruikersnamen, wachtwoorden en autorisatie-informatie. " -"Netwerktoegangsgegevens worden gebruikt voor het indienen van taken die " -"draaiboeken afspelen tegen netwerkapparaten." - -#: client/src/credentials/credentials.form.js:68 -msgid "" -"Authentication for remote machine access. This can include SSH keys, " -"usernames, passwords, and sudo information. Machine credentials are used " -"when submitting jobs to run playbooks against remote hosts." -msgstr "" -"Authenticatie voor machinetoegang op afstand. Hieronder kunnen vallen: SSH-" -"sleutels, gebruikersnamen, wachtwoorden en sudo-informatie. " -"Machinetoegangsgegevens worden gebruikt voor het indienen van taken die " -"draaiboeken afspelen tegen hosts op afstand." - -#: client/src/credentials/credentials.form.js:343 -msgid "Authorize" -msgstr "Autoriseren" - -#: client/src/credentials/credentials.form.js:351 -msgid "Authorize Password" -msgstr "Wachtwoord autoriseren" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:172 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:253 -msgid "Availability Zone:" -msgstr "Beschikbaarheidsgebied:" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:106 -msgid "Azure AD" -msgstr "Azure AD" - -#: client/src/shared/directives.js:75 -msgid "BROWSE" -msgstr "BLADEREN" - -#: client/src/projects/projects.form.js:80 -msgid "" -"Base path used for locating playbooks. Directories found inside this path " -"will be listed in the playbook directory drop-down. Together the base path " -"and selected playbook directory provide the full path used to locate " -"playbooks." -msgstr "" -"Basispad dat gebruikt wordt voor het vinden van draaiboeken. Mappen die " -"binnen dit pad gevonden worden, zullen in het uitklapbare menu van de " -"draaiboekmap genoemd worden. Het basispad en de gekozen draaiboekmap bieden " -"samen het volledige pad dat gebruikt wordt om draaiboeken te vinden." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:128 -msgid "Become Privilege Escalation" -msgstr "Verhoging van rechten worden" - -#: client/src/license/license.partial.html:107 -msgid "Browse" -msgstr "Bladeren" - -#: client/lib/services/base-string.service.js:61 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:28 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:29 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:73 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:16 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:16 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:16 -#: client/src/job-submission/job-submission.partial.html:370 -#: client/src/partials/survey-maker-modal.html:17 -#: client/src/partials/survey-maker-modal.html:85 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:17 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:65 -msgid "CANCEL" -msgstr "ANNULEREN" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 -msgid "CHANGES" -msgstr "WIJZIGINGEN" - -#: client/src/shared/smart-search/smart-search.partial.html:30 -msgid "CLEAR ALL" -msgstr "ALLES WISSEN" - -#: client/src/partials/survey-maker-modal.html:86 -msgid "CLOSE" -msgstr "SLUITEN" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:19 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js:19 -#: client/src/templates/completed-jobs.list.js:20 -msgid "COMPLETED JOBS" -msgstr "VOLTOOIDE TAKEN" - -#: client/src/configuration/configuration.partial.html:10 -msgid "CONFIGURE {{BRAND_NAME}}" -msgstr "{{BRAND_NAME}} CONFIGUREREN" - -#: client/src/shared/stateDefinitions.factory.js:157 -msgid "CREATE %s" -msgstr "%s AANMAKEN" - -#: client/features/credentials/credentials.strings.js:8 -#: client/src/credentials/credentials.form.js:16 -msgid "CREATE CREDENTIAL" -msgstr "TOEGANGSGEGEVENS AANMAKEN" - -#: client/src/inventories-hosts/inventories/related/groups/add/groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:16 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:16 -msgid "CREATE GROUP" -msgstr "GROEP AANMAKEN" - -#: client/src/inventories-hosts/hosts/host.form.js:17 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:17 -#: client/src/inventories-hosts/inventories/related/hosts/add/host-add.route.js:8 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:17 -msgid "CREATE HOST" -msgstr "HOST AANMAKEN" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.route.js:8 -msgid "CREATE INVENTORY SOURCE" -msgstr "INVENTARISBRON AANMAKEN" - -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js:8 -#: client/src/scheduler/main.js:113 client/src/scheduler/main.js:206 -#: client/src/scheduler/main.js:290 -msgid "CREATE SCHEDULE" -msgstr "SCHEMA AANMAKEN" - -#: client/src/management-jobs/scheduler/main.js:81 -msgid "CREATE SCHEDULED JOB" -msgstr "GEPLANDE TAAK AANMAKEN" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:32 -msgid "CREATE SOURCE" -msgstr "BRON AANMAKEN" - -#: client/src/job-submission/job-submission.partial.html:351 -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:93 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:82 -msgid "CREDENTIAL" -msgstr "TOEGANGSGEGEVENS" - -#: client/src/credential-types/credential-types.form.js:21 -msgid "CREDENTIAL TYPE" -msgstr "SOORT TOEGANGSGEGEVENS" - -#: client/src/job-submission/job-submission.partial.html:92 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:56 -msgid "CREDENTIAL TYPE:" -msgstr "SOORT TOEGANGSGEGEVENS:" - -#: client/src/activity-stream/get-target-title.factory.js:11 -#: client/src/credential-types/credential-types.list.js:12 -#: client/src/credential-types/main.js:45 -msgid "CREDENTIAL TYPES" -msgstr "SOORTEN TOEGANGSGEGEVENS" - -#: client/features/credentials/legacy.credentials.js:14 -#: client/src/activity-stream/get-target-title.factory.js:17 -#: client/src/credentials/credentials.list.js:15 -#: client/src/credentials/credentials.list.js:16 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:5 -msgid "CREDENTIALS" -msgstr "TOEGANGSGEGEVENS" - -#: client/features/credentials/credentials.strings.js:28 -msgid "CREDENTIALS PERMISSIONS" -msgstr "MACHTIGINGEN TOEGANGSGEGEVENS" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:378 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:390 -#: client/src/projects/projects.form.js:199 -msgid "Cache Timeout" -msgstr "Cache time-out" - -#: client/src/projects/projects.form.js:188 -msgid "Cache Timeout%s (seconds)%s" -msgstr "Cache time-out %s (seconden)%s" - -#: client/src/projects/list/projects-list.controller.js:199 -#: client/src/users/list/users-list.controller.js:83 -msgid "Call to %s failed. DELETE returned status:" -msgstr "Oproepen %s mislukt. Geretourneerde status VERWIJDEREN:" - -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:263 -msgid "Call to %s failed. GET status:" -msgstr "Oproepen %s mislukt. Status OPHALEN:" - -#: client/src/projects/edit/projects-edit.controller.js:238 -msgid "Call to %s failed. POST returned status:" -msgstr "Oproepen %s mislukt. Geretourneerde status POSTEN:" - -#: client/src/projects/list/projects-list.controller.js:225 -msgid "Call to %s failed. POST status:" -msgstr "Oproepen %s mislukt. Status POSTEN:" - -#: client/src/management-jobs/card/card.controller.js:29 -msgid "Call to %s failed. Return status: %d" -msgstr "Oproepen %s mislukt. Status retourneren: %d" - -#: client/src/projects/list/projects-list.controller.js:272 -msgid "Call to get project failed. GET status:" -msgstr "Oproep om project op te halen mislukt. Status OPHALEN:" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:105 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:188 -#: client/src/configuration/configuration.controller.js:541 -#: client/src/job-results/job-results.partial.html:42 -#: client/src/jobs/factories/delete-job.factory.js:33 -#: client/src/shared/form-generator.js:1699 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:12 -#: client/src/workflow-results/workflow-results.partial.html:42 -msgid "Cancel" -msgstr "Annuleren" - -#: client/src/job-results/job-results.service.js:142 -msgid "Cancel Job" -msgstr "Taak annuleren" - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "Cancel Not Allowed" -msgstr "Annuleren niet toegestaan" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:93 -msgid "Cancel sync process" -msgstr "Synchronisatieproces annuleren" - -#: client/src/projects/projects.list.js:124 -msgid "Cancel the SCM update" -msgstr "SCM-update annuleren" - -#: client/src/jobs/all-jobs.list.js:106 -msgid "Cancel the job" -msgstr "Taak annuleren" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:30 -#: client/src/projects/list/projects-list.controller.js:79 -msgid "Canceled. Click for details" -msgstr "Geannuleerd. Klik voor meer informatie" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:91 -msgid "Cannot search running job" -msgstr "Kan taak in uitvoering niet zoeken" - -#: client/src/instance-groups/instance-groups.list.js:22 -#: client/src/instance-groups/instances/instances.list.js:20 -msgid "Capacity" -msgstr "Capaciteit" - -#: client/src/projects/projects.form.js:82 -msgid "Change %s under \"Configure {{BRAND_NAME}}\" to change this location." -msgstr "" -"Wijzig %s onder \"{{BRAND_NAME}} configureren\" om deze locatie te wijzigen." - -#: client/src/activity-stream/activity-detail.form.js:41 -msgid "Changes" -msgstr "Wijzigingen" - -#: client/src/shared/form-generator.js:1071 -msgid "Choose a %s" -msgstr "Kies een %s" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:64 -msgid "Choose an answer type" -msgstr "Kies een antwoordtype" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:67 -msgid "" -"Choose an answer type or format you want as the prompt for the user. Refer " -"to the Ansible Tower Documentation for more additional information about " -"each option." -msgstr "" -"Kies een antwoordtype of -formaat dat u als melding voor de gebruiker wilt. " -"Raadpleeg de documentatie van Ansible Tower voor meer informatie over iedere" -" optie." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:112 -msgid "Choose an inventory file" -msgstr "Kies een inventarisbestand" - -#: client/src/shared/directives.js:76 -msgid "Choose file" -msgstr "Bestand kiezen" - -#: client/src/license/license.partial.html:97 -msgid "" -"Choose your license file, agree to the End User License Agreement, and click" -" submit." -msgstr "" -"Kies uw licentiebestand, ga akkoord met de Licentie-overeenkomst voor " -"eindgebruikers en klik op indienen." - -#: client/src/projects/projects.form.js:156 -msgid "Clean" -msgstr "Opschonen" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:299 -msgid "Clear" -msgstr "Wissen" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:64 -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Click for details" -msgstr "Klik voor meer informatie" - -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:63 -msgid "Click here to open the workflow graph editor." -msgstr "Klik hier om de editor voor de workflow-grafiek te openen." - -#: client/src/inventories-hosts/inventories/inventory.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new inventory." -msgstr "" -"Klik op een rij om deze te selecteren en klik op Klaar wanneer u klaar bent." -" Klik op de knop %s om een nieuwe inventaris aan te maken." - -#: client/src/teams/teams.list.js:16 -msgid "" -"Click on a row to select it, and click Finished when done. Click the %s " -"button to create a new team." -msgstr "" -"Klik op een rij om deze te selecteren en klik op Klaar wanneer u klaar bent." -" Klik op de knop %s om een nieuw team aan te maken." - -#: client/src/templates/templates.list.js:17 -msgid "" -"Click on a row to select it, and click Finished when done. Use the %s button" -" to create a new job template." -msgstr "" -"Klik op een rij om deze te selecteren en klik op Klaar wanneer u klaar bent." -" Klik op de knop %s om een nieuw taaksjabloon aan te maken." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:138 -msgid "" -"Click on the regions field to see a list of regions for your cloud provider." -" You can select multiple regions, or choose" -msgstr "" -"Klik op de regiovelden om een lijst van regio's voor uw cloudprovider in te " -"zien. U kunt meerdere regio's selecteren, of kiezen" - -#: client/src/credentials/credentials.form.js:321 -msgid "Client ID" -msgstr "Klant-ID" - -#: client/src/notifications/notificationTemplates.form.js:254 -msgid "Client Identifier" -msgstr "Klant-identificeerder" - -#: client/src/credentials/credentials.form.js:330 -msgid "Client Secret" -msgstr "Klant-geheim" - -#: client/src/shared/form-generator.js:1703 -msgid "Close" -msgstr "Sluiten" - -#: client/src/job-results/job-results.partial.html:291 -msgid "Cloud Credential" -msgstr "Cloudtoegangsgegevens" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:26 -msgid "Cloud source not configured." -msgstr "Cloudbron niet geconfigureerd." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "Cloud source not configured. Click" -msgstr "Cloudbron niet geconfigureerd. Klik op" - -#: client/src/credentials/factories/become-method-change.factory.js:80 -#: client/src/credentials/factories/kind-change.factory.js:137 -msgid "CloudForms URL" -msgstr "CloudForms URL" - -#: client/src/job-results/job-results.controller.js:226 -#: client/src/standard-out/standard-out.controller.js:243 -#: client/src/workflow-results/workflow-results.controller.js:118 -msgid "Collapse Output" -msgstr "Output samenvouwen" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:13 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:21 -msgid "Completed Jobs" -msgstr "Voltooide taken" - -#: client/src/management-jobs/card/card.partial.html:34 -msgid "Configure Notifications" -msgstr "Notificaties configureren" - -#: client/src/setup-menu/setup-menu.partial.html:60 -msgid "Configure {{BRAND_NAME}}" -msgstr "{{BRAND_NAME}} configureren" - -#: client/src/users/users.form.js:81 -msgid "Confirm Password" -msgstr "Wachtwoord bevestigen" - -#: client/src/configuration/configuration.controller.js:548 -msgid "Confirm Reset" -msgstr "Reset bevestigen" - -#: client/src/configuration/configuration.controller.js:557 -msgid "Confirm factory reset" -msgstr "Reset naar fabrieksinstellingen bevestigen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:120 -msgid "" -"Confirm that you want to permanently delete the inventory source below from " -"the inventory. Deleting this inventory source also deletes its associated " -"groups and hosts." -msgstr "" -"Bevestig dat u de onderstaande inventarisbron permanent wilt verwijderen uit" -" de inventaris. Wanneer u deze inventaris verwijdert, worden alle " -"bijbehorende groepen en hosts eveneens verwijderd." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "Confirm the removal of the" -msgstr "Bevestig het verwijderen van de" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:134 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:149 -msgid "" -"Consult the Ansible documentation for further details on the usage of tags." -msgstr "" -"Raadpleeg documentatie van Ansible voor meer informatie over het gebruik van" -" tags." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:18 -msgid "Contains 0 hosts." -msgstr "Bevat 0 hosts." - -#: client/src/templates/job_templates/job-template.form.js:180 -msgid "" -"Control the level of output ansible will produce as the playbook executes." -msgstr "" -"Stel in hoeveel output Ansible produceert bij het uitvoeren van het " -"draaiboek." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:313 -msgid "" -"Control the level of output ansible will produce for inventory source update" -" jobs." -msgstr "" -"Stel in hoeveel output Ansible produceert bij taken die de inventarisbron " -"updaten." - -#: client/lib/components/components.strings.js:48 -msgid "Copied to clipboard." -msgstr "Gekopieerd naar klembord." - -#: client/src/templates/templates.list.js:95 -msgid "Copy" -msgstr "Kopiëren" - -#: client/lib/components/components.strings.js:47 -msgid "Copy full revision to clipboard." -msgstr "Volledige herziening kopiëren naar klembord." - -#: client/src/templates/templates.list.js:98 -msgid "Copy template" -msgstr "Sjabloon kopiëren" - -#: client/src/about/about.partial.html:27 -msgid "" -"Copyright © 2017 Red Hat, Inc.
\n" -" Visit Ansible.com for more information.
" -msgstr "" -"Auteursrechten © 2017 Red Hat, Inc.
\n" -" Ga voor meer informatie naar Ansible.com.
" - -#: client/src/users/users.list.js:44 -msgid "Create New" -msgstr "Nieuw aanmaken" - -#: client/src/credentials/credentials.list.js:52 -msgid "Create a new credential" -msgstr "Nieuwe toegangsgegevens aanmaken" - -#: client/src/credential-types/credential-types.list.js:42 -msgid "Create a new credential type" -msgstr "Een nieuwe soort toegangsgegevens aanmaken" - -#: client/src/inventory-scripts/inventory-scripts.list.js:40 -msgid "Create a new custom inventory" -msgstr "Een nieuwe aangepaste inventaris aanmaken" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:69 -msgid "Create a new group" -msgstr "Een nieuwe groep aanmaken" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:123 -msgid "Create a new host" -msgstr "Een nieuwe host aanmaken" - -#: client/src/inventories-hosts/inventories/inventory.list.js:75 -msgid "Create a new inventory" -msgstr "Een nieuwe inventaris aanmaken" - -#: client/src/notifications/notificationTemplates.list.js:52 -msgid "Create a new notification template" -msgstr "Een nieuw berichtsjabloon aanmaken" - -#: client/src/organizations/list/organizations-list.partial.html:21 -msgid "Create a new organization" -msgstr "Een nieuwe organisatie aanmaken" - -#: client/src/projects/projects.list.js:76 -msgid "Create a new project" -msgstr "Een nieuw project aanmaken" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:68 -msgid "Create a new source" -msgstr "Een nieuwe bron aanmaken" - -#: client/src/teams/teams.list.js:43 -msgid "Create a new team" -msgstr "Een nieuw team aanmaken" - -#: client/src/templates/templates.list.js:56 -msgid "Create a new template" -msgstr "Een nieuw sjabloon aanmaken" - -#: client/src/users/users.list.js:48 -msgid "Create a new user" -msgstr "Een nieuwe gebruiker aanmaken" - -#: client/src/setup-menu/setup-menu.partial.html:42 -msgid "Create and edit scripts to dynamically load hosts from any source." -msgstr "" -"Scripts aanmaken en bewerken zodat ze van iedere bron dynamisch hosts laden." - -#: client/src/setup-menu/setup-menu.partial.html:30 -msgid "" -"Create custom credential types to be used for authenticating to network " -"hosts and cloud sources" -msgstr "" -"Aangepaste soorten toegangsgegevens aanmaken voor gebruik bij het " -"authenticeren van netwerkhosts en cloudbronnen" - -#: client/src/setup-menu/setup-menu.partial.html:49 -msgid "" -"Create templates for sending notifications with Email, HipChat, Slack, and " -"SMS." -msgstr "" -"Sjablonen aanmaken voor het versturen van berichten via e-mail, HipChat, " -"Slack en sms." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:72 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:74 -#: client/src/job-submission/job-submission.partial.html:18 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:67 -#: client/src/templates/job_templates/job-template.form.js:121 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:53 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:62 -msgid "Credential" -msgstr "Toegangsgegevens" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:32 -#: client/src/setup-menu/setup-menu.partial.html:29 -msgid "Credential Types" -msgstr "Soorten toegangsgegevens" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:129 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:58 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 -#: client/src/setup-menu/setup-menu.partial.html:22 -#: client/src/templates/job_templates/job-template.form.js:134 -msgid "Credentials" -msgstr "Toegangsgegevens" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:17 -msgid "Critical" -msgstr "Cruciaal" - -#: client/src/shared/directives.js:77 -msgid "Current Image:" -msgstr "Huidige afbeelding:" - -#: client/src/job-results/job-results.controller.js:271 -msgid "Currently following standard out as it comes in. Click to unfollow." -msgstr "" -"Standaardoutput wordt op dit moment gevolgd zodra het binnenkomt. Klik om te" -" stoppen met volgen." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:171 -msgid "Custom Inventory Script" -msgstr "Aangepast inventarisscript" - -#: client/src/inventory-scripts/inventory-scripts.form.js:50 -#: client/src/inventory-scripts/inventory-scripts.form.js:60 -msgid "Custom Script" -msgstr "Aangepast script" - -#: client/src/home/home.route.js:21 -msgid "DASHBOARD" -msgstr "DASHBOARD" - -#: client/src/credentials/list/credentials-list.controller.js:135 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:103 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:52 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:74 -#: client/src/job-results/job-results.service.js:119 -#: client/src/jobs/factories/delete-job.factory.js:115 -#: client/src/notifications/notification-templates-list/list.controller.js:195 -#: client/src/organizations/list/organizations-list.controller.js:174 -#: client/src/partials/survey-maker-modal.html:18 -#: client/src/projects/edit/projects-edit.controller.js:246 -#: client/src/templates/list/templates-list.controller.js:154 -#: client/src/users/list/users-list.controller.js:92 -msgid "DELETE" -msgstr "VERWIJDEREN" - -#: client/src/partials/survey-maker-modal.html:84 -msgid "DELETE SURVEY" -msgstr "VRAGENLIJST VERWIJDEREN" - -#: client/src/job-results/job-results.partial.html:16 -msgid "DETAILS" -msgstr "MEER INFORMATIE" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:29 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:30 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:31 -msgid "DISASSOCIATE" -msgstr "LOSKOPPELEN" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:5 -msgid "DYNAMIC HOSTS" -msgstr "DYNAMISCHE HOSTS" - -#: client/src/credential-types/credential-types.list.js:73 -#: client/src/credentials/credentials.list.js:85 -#: client/src/credentials/list/credentials-list.controller.js:132 -#: client/src/inventories-hosts/inventories/inventory.list.js:111 -#: client/src/inventory-scripts/inventory-scripts.list.js:71 -#: client/src/job-results/job-results.partial.html:54 -#: client/src/jobs/factories/delete-job.factory.js:37 -#: client/src/notifications/notification-templates-list/list.controller.js:192 -#: client/src/notifications/notificationTemplates.list.js:91 -#: client/src/organizations/list/organizations-list.controller.js:171 -#: client/src/projects/edit/projects-edit.controller.js:243 -#: client/src/projects/list/projects-list.controller.js:207 -#: client/src/scheduler/schedules.list.js:90 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:13 -#: client/src/teams/teams.list.js:72 -#: client/src/templates/list/templates-list.controller.js:102 -#: client/src/templates/templates.list.js:120 -#: client/src/users/list/users-list.controller.js:89 -#: client/src/users/users.list.js:79 -#: client/src/workflow-results/workflow-results.partial.html:54 -msgid "Delete" -msgstr "Verwijderen" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:6 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:6 -msgid "Delete Group" -msgstr "Groep verwijderen" - -#: client/src/job-results/job-results.service.js:93 -msgid "Delete Job" -msgstr "Taak verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:175 -msgid "Delete Source" -msgstr "Bron verwijderen" - -#: client/src/credentials/credentials.list.js:87 -msgid "Delete credential" -msgstr "Toegangsgegevens verwijderen" - -#: client/src/credential-types/credential-types.list.js:75 -msgid "Delete credential type" -msgstr "Soort toegangsgegevens verwijderen" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:101 -#: client/src/inventories-hosts/inventory-hosts.strings.js:19 -msgid "Delete group" -msgid_plural "Delete groups" -msgstr[0] "Groep verwijderen" -msgstr[1] "Groepen verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:48 -msgid "Delete groups" -msgstr "Groepen verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:37 -msgid "Delete groups and hosts" -msgstr "Groepen en hosts verwijderen" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:100 -#: client/src/inventories-hosts/inventory-hosts.strings.js:21 -msgid "Delete host" -msgid_plural "Delete hosts" -msgstr[0] "Host verwijderen" -msgstr[1] "Hosts verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:59 -msgid "Delete hosts" -msgstr "Hosts verwijderen" - -#: client/src/inventories-hosts/inventories/inventory.list.js:113 -msgid "Delete inventory" -msgstr "Inventaris verwijderen" - -#: client/src/inventory-scripts/inventory-scripts.list.js:73 -msgid "Delete inventory script" -msgstr "Inventarisscript verwijderen" - -#: client/src/notifications/notificationTemplates.list.js:93 -msgid "Delete notification" -msgstr "Bericht verwijderen" - -#: client/src/projects/projects.form.js:166 -msgid "Delete on Update" -msgstr "Verwijderen bij update" - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:27 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:27 -msgid "Delete or promote the group's children?" -msgstr "De kinderen van de groep verwijderen of promoveren?" - -#: client/src/scheduler/schedules.list.js:93 -msgid "Delete schedule" -msgstr "Schema verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:125 -msgid "Delete source" -msgstr "Bron verwijderen" - -#: client/src/teams/teams.list.js:76 -msgid "Delete team" -msgstr "Team verwijderen" - -#: client/src/templates/templates.list.js:123 -msgid "Delete template" -msgstr "Sjabloon verwijderen" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:84 -#: client/src/jobs/all-jobs.list.js:113 -#: client/src/templates/completed-jobs.list.js:85 -msgid "Delete the job" -msgstr "De taak verwijderen" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Delete the local repository in its entirety prior to performing an update." -msgstr "" -"De lokale opslagplaats dient volledig verwijderd te worden voordat een " -"update uitgevoerd wordt." - -#: client/src/projects/projects.list.js:118 -msgid "Delete the project" -msgstr "Het project verwijderen" - -#: client/src/scheduler/scheduled-jobs.list.js:81 -msgid "Delete the schedule" -msgstr "Het schema verwijderen" - -#: client/src/users/users.list.js:83 -msgid "Delete user" -msgstr "Gebruiker verwijderen" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:14 -msgid "Delete {{ group }} and {{ host }}" -msgstr "{{ group }} en {{ host }} verwijderen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:23 -msgid "Deleting group" -msgstr "Groep wordt verwijderd" - -#: client/src/projects/projects.form.js:168 -msgid "" -"Depending on the size of the repository this may significantly increase the " -"amount of time required to complete an update." -msgstr "" -"Afhankelijk van het formaat van de opslagplaats kan de tijd die nodig is om " -"een update uit te voeren hierdoor sterk verlengd worden." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "Describe Instances documentation" -msgstr "Documentatie Instances beschrijven" - -#: client/src/credential-types/credential-types.form.js:34 -#: client/src/credentials/credentials.form.js:39 -#: client/src/inventories-hosts/hosts/host.form.js:63 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:39 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:62 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:62 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:58 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:46 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:53 -#: client/src/inventory-scripts/inventory-scripts.form.js:35 -#: client/src/notifications/notificationTemplates.form.js:39 -#: client/src/organizations/organizations.form.js:33 -#: client/src/projects/projects.form.js:36 client/src/teams/teams.form.js:32 -#: client/src/templates/job_templates/job-template.form.js:41 -#: client/src/templates/survey-maker/shared/question-definition.form.js:36 -#: client/src/templates/workflows.form.js:39 -#: client/src/users/users.form.js:145 client/src/users/users.form.js:171 -msgid "Description" -msgstr "Omschrijving" - -#: client/src/notifications/notificationTemplates.form.js:136 -#: client/src/notifications/notificationTemplates.form.js:140 -#: client/src/notifications/notificationTemplates.form.js:152 -#: client/src/notifications/notificationTemplates.form.js:156 -msgid "Destination Channels" -msgstr "Bestemmingskanalen" - -#: client/src/notifications/notificationTemplates.form.js:359 -#: client/src/notifications/notificationTemplates.form.js:363 -msgid "Destination Channels or Users" -msgstr "Bestemmingskanalen of -gebruikers" - -#: client/src/notifications/notificationTemplates.form.js:205 -#: client/src/notifications/notificationTemplates.form.js:206 -msgid "Destination SMS Number" -msgstr "Sms-nummer bestemming" - -#: client/features/credentials/credentials.strings.js:13 -#: client/src/license/license.partial.html:5 -#: client/src/shared/form-generator.js:1481 -msgid "Details" -msgstr "Meer informatie" - -#: client/src/job-submission/job-submission.partial.html:263 -msgid "Diff Mode" -msgstr "Diff-modus" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Group From Group" -msgstr "Groep van groep loskoppelen" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.partial.html:6 -msgid "Disassociate Host" -msgstr "Host loskoppelen" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:6 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-disassociate.partial.html:6 -msgid "Disassociate Host From Group" -msgstr "Host van groep loskoppelen" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:65 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:110 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:98 -msgid "Disassociate group" -msgstr "Groep loskoppelen" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:87 -msgid "Disassociate host" -msgstr "Host loskoppelen" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:75 -#: client/src/configuration/configuration.controller.js:202 -#: client/src/configuration/configuration.controller.js:264 -#: client/src/configuration/system-form/configuration-system.controller.js:57 -msgid "Discard changes" -msgstr "Wijzigingen annuleren" - -#: client/src/teams/teams.form.js:146 -msgid "Dissasociate permission from team" -msgstr "Machtiging loskoppelen van team" - -#: client/src/users/users.form.js:225 -msgid "Dissasociate permission from user" -msgstr "Machtiging loskoppelen van gebruiker" - -#: client/src/credentials/credentials.form.js:384 -#: client/src/credentials/factories/become-method-change.factory.js:54 -#: client/src/credentials/factories/kind-change.factory.js:111 -msgid "Domain Name" -msgstr "Domeinnaam" - -#: client/src/job-results/job-results.controller.js:15 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:134 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:141 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:102 -msgid "Download Output" -msgstr "Download output" - -#: client/src/inventory-scripts/inventory-scripts.form.js:59 -msgid "" -"Drag and drop your custom inventory script file here or create one in the " -"field to import your custom inventory. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Sleep uw aangepaste inventarisscriptbestand hierheen of maak een nieuwe aan " -"in het veld om uw aangepaste inventaris te importeren. Raadpleeg de " -"documentatie van Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/partials/survey-maker-modal.html:77 -msgid "Drop question here to reorder" -msgstr "Sleep een vraag hierheen om opnieuw te ordenen" - -#: client/src/configuration/configuration.route.js:30 -msgid "EDIT CONFIGURATION" -msgstr "CONFIGURATIE WIJZIGEN" - -#: client/features/credentials/credentials.strings.js:9 -msgid "EDIT CREDENTIAL" -msgstr "TOEGANGSGEGEVENS WIJZIGEN" - -#: client/src/management-jobs/scheduler/main.js:95 -msgid "EDIT SCHEDULED JOB" -msgstr "GEPLANDE TAAK WIJZIGEN" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:17 -msgid "EDIT SURVEY PROMPT" -msgstr "MELDING VRAGENLIJST WIJZIGEN" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:46 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:79 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:59 -msgid "ELAPSED" -msgstr "VERLOPEN" - -#: client/lib/components/components.strings.js:9 -msgid "ENCRYPTED" -msgstr "VERSLEUTELD" - -#: client/src/shared/smart-search/smart-search.partial.html:39 -msgid "EXAMPLES:" -msgstr "VOORBEELDEN:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:15 -msgid "EXECUTE COMMAND" -msgstr "COMMANDO UITVOEREN" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:46 -msgid "EXPLANATION" -msgstr "UITLEG" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:355 -msgid "" -"Each time a job runs using this inventory, refresh the inventory from the " -"selected source before executing job tasks." -msgstr "" -"Elke keer dat een taak uitgevoerd wordt met dit inventaris, dient het " -"inventaris vernieuwd te worden vanuit de geselecteerde bron voordat de " -"opdrachten van de taak uitgevoerd worden." - -#: client/src/projects/projects.form.js:179 -msgid "" -"Each time a job runs using this project, perform an update to the local " -"repository prior to starting the job." -msgstr "" -"Voer iedere keer dat een taak uitgevoerd wordt met dit project een update " -"uit voor de lokale opslagplaats voordat u de taak start." - -#: client/src/credential-types/credential-types.list.js:56 -#: client/src/credentials/credentials.list.js:66 -#: client/src/inventories-hosts/inventories/inventory.list.js:97 -#: client/src/inventory-scripts/inventory-scripts.list.js:54 -#: client/src/notifications/notificationTemplates.list.js:65 -#: client/src/notifications/notificationTemplates.list.js:74 -#: client/src/scheduler/schedules.list.js:75 client/src/teams/teams.list.js:55 -#: client/src/templates/templates.list.js:103 -#: client/src/users/users.list.js:60 -msgid "Edit" -msgstr "Wijzigen" - -#: client/src/shared/form-generator.js:1715 -#: client/src/templates/job_templates/job-template.form.js:452 -#: client/src/templates/workflows.form.js:177 -msgid "Edit Survey" -msgstr "Vragenlijst wijzigen" - -#: client/src/credential-types/credential-types.list.js:58 -msgid "Edit credenital type" -msgstr "Soort toegangsgegevens wijzigen" - -#: client/src/credentials/credentials.list.js:68 -msgid "Edit credential" -msgstr "Toegangsgegevens wijzigen" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:85 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:96 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:84 -msgid "Edit group" -msgstr "Groep wijzigen" - -#: client/src/inventories-hosts/hosts/host.list.js:83 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:73 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:87 -msgid "Edit host" -msgstr "Host wijzigen" - -#: client/src/inventories-hosts/inventories/inventory.list.js:99 -msgid "Edit inventory" -msgstr "Inventaris wijzigen" - -#: client/src/inventory-scripts/inventory-scripts.list.js:56 -msgid "Edit inventory script" -msgstr "Inventarisscript wijzigen" - -#: client/src/notifications/notificationTemplates.list.js:76 -msgid "Edit notification" -msgstr "Bericht wijzigen" - -#: client/src/scheduler/schedules.list.js:78 -msgid "Edit schedule" -msgstr "Schema wijzigen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:111 -msgid "Edit source" -msgstr "Bron wijzigen" - -#: client/src/teams/teams.list.js:59 -msgid "Edit team" -msgstr "Team wijzigen" - -#: client/src/templates/templates.list.js:105 -msgid "Edit template" -msgstr "Sjabloon wijzigen" - -#: client/src/job-results/job-results.partial.html:191 -msgid "Edit the Schedule" -msgstr "Het schema wijzigen" - -#: client/src/job-results/job-results.partial.html:175 -#: client/src/workflow-results/workflow-results.partial.html:124 -msgid "Edit the User" -msgstr "De gebruiker wijzigen" - -#: client/src/job-results/job-results.partial.html:265 -#: client/src/job-results/job-results.partial.html:280 -#: client/src/job-results/job-results.partial.html:296 -#: client/src/job-results/job-results.partial.html:311 -#: client/src/job-results/job-results.partial.html:326 -msgid "Edit the credential" -msgstr "De toegangsgegevens wijzigen" - -#: client/src/job-results/job-results.partial.html:206 -msgid "Edit the inventory" -msgstr "De inventaris wijzigen" - -#: client/src/job-results/job-results.partial.html:140 -msgid "Edit the job template" -msgstr "De taaksjabloon wijzigen" - -#: client/src/job-results/job-results.partial.html:229 -#: client/src/projects/projects.list.js:105 -msgid "Edit the project" -msgstr "Het project wijzigen" - -#: client/src/scheduler/scheduled-jobs.list.js:67 -msgid "Edit the schedule" -msgstr "Het schema wijzigen" - -#: client/src/users/users.list.js:64 -msgid "Edit user" -msgstr "Gebruiker wijzigen" - -#: client/src/setup-menu/setup-menu.partial.html:61 -msgid "Edit {{BRAND_NAME}}'s configuration." -msgstr "Configuratie van {{BRAND_NAME}} wijzigen." - -#: client/src/projects/list/projects-list.controller.js:241 -msgid "" -"Either you do not have access or the SCM update process completed. Click the" -" %sRefresh%s button to view the latest status." -msgstr "" -"U heeft mogelijk geen toegang, of het SCM-updateproces is al voltooid. Klik " -"op de knop %sVernieuwen%s om de nieuwste status te zien." - -#: client/src/job-results/job-results.partial.html:520 -msgid "Elapsed" -msgstr "Verlopen" - -#: client/src/credentials/credentials.form.js:191 -#: client/src/users/users.form.js:51 -msgid "Email" -msgstr "E-mail" - -#: client/src/templates/job_templates/job-template.form.js:288 -#: client/src/templates/job_templates/job-template.form.js:293 -msgid "Enable Concurrent Jobs" -msgstr "Gelijktijdige taken inschakelen" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:123 -#: client/src/templates/job_templates/job-template.form.js:264 -#: client/src/templates/job_templates/job-template.form.js:269 -msgid "Enable Privilege Escalation" -msgstr "Verhoging van rechten inschakelen" - -#: client/src/templates/job_templates/job-template.form.js:279 -msgid "" -"Enables creation of a provisioning callback URL. Using the URL a host can " -"contact {{BRAND_NAME}} and request a configuration update using this job " -"template." -msgstr "" -"Maakt het mogelijk een provisioning terugkoppelings-URL aan te maken. Met " -"deze URL kan een host contact opnemen met {{BRAND_NAME}} en een verzoek " -"indienen voor een configuratie-update met behulp van dit taaksjabloon." - -#: client/src/credentials/factories/credential-form-save.factory.js:73 -msgid "Encrypted credentials are not supported." -msgstr "Versleutelde toegangsgegevens worden niet ondersteund." - -#: client/src/license/license.partial.html:113 -msgid "End User License Agreement" -msgstr "Licentie-overeenkomst voor eindgebruikers" - -#: client/src/inventories-hosts/hosts/host.form.js:73 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:72 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:86 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two." -msgstr "" -"Voer variabelen van de inventaris in met JSON- of YAML-syntaxis. Gebruik de " -"radioknop om tussen de twee te wisselen." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:93 -msgid "" -"Enter inventory variables using either JSON or YAML syntax. Use the radio " -"button to toggle between the two. Refer to the Ansible Tower documentation " -"for example syntax." -msgstr "" -"Voer de variabelen van het inventaris in met JSON- of YAML-syntax. Gebruik " -"de radio-knop om tussen de twee te wisselen. Raadpleeg de documentatie van " -"Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/notifications/notificationTemplates.form.js:155 -msgid "" -"Enter one HipChat channel per line. The pound symbol (#) is not required." -msgstr "" -"Voer één HipChat-kanaal per regel in. Het hekje (#) is hierbij niet vereist." - -#: client/src/notifications/notificationTemplates.form.js:362 -msgid "" -"Enter one IRC channel or username per line. The pound symbol (#) for " -"channels, and the at (@) symbol for users, are not required." -msgstr "" -"Voer één IRC-kanaal of gebruikersnaam per regel in. Het hekje (#) voor " -"kanalen en het apenstaartje (@) voor gebruikers zijn hierbij niet vereist." - -#: client/src/notifications/notificationTemplates.form.js:139 -msgid "" -"Enter one Slack channel per line. The pound symbol (#) is not required." -msgstr "" -"Voer één Slack-kanaal per regel in. Het hekje (#) is hierbij niet vereist." - -#: client/src/notifications/notificationTemplates.form.js:97 -msgid "" -"Enter one email address per line to create a recipient list for this type of" -" notification." -msgstr "" -"Voer één e-mailadres per regel in om een lijst met ontvangers te maken voor " -"dit type bericht." - -#: client/src/notifications/notificationTemplates.form.js:209 -msgid "" -"Enter one phone number per line to specify where to route SMS messages." -msgstr "" -"Voer één telefoonnummer per regel in om aan te geven waar SMS-berichten " -"naartoe gestuurd moeten worden." - -#: client/src/credentials/factories/become-method-change.factory.js:81 -#: client/src/credentials/factories/kind-change.factory.js:138 -msgid "" -"Enter the URL for the virtual machine which %scorresponds to your CloudForm " -"instance. %sFor example, %s" -msgstr "" -"Voer de URL in voor de virtuele machine die %sovereenkomt met uw CloudForm-" -"instantie. %sBijvoorbeeld %s" - -#: client/src/credentials/factories/become-method-change.factory.js:71 -#: client/src/credentials/factories/kind-change.factory.js:128 -msgid "" -"Enter the URL which corresponds to your %sRed Hat Satellite 6 server. %sFor " -"example, %s" -msgstr "" -"Voer de URL in die overeenkomt met uw %sRed Had Satellite 6-server. " -"%sBijvoorbeeld %s" - -#: client/src/credentials/factories/become-method-change.factory.js:49 -#: client/src/credentials/factories/kind-change.factory.js:106 -msgid "" -"Enter the hostname or IP address which corresponds to your VMware vCenter." -msgstr "" -"Voer de hostnaam of het IP-adres in dat overeenkomt met uw VMware vCenter." - -#: client/src/notifications/notificationTemplates.form.js:195 -msgid "" -"Enter the number associated with the \"Messaging Service\" in Twilio in the " -"format +18005550199." -msgstr "" -"Voer het telefoonnummer in dat hoort bij de 'Berichtenservice' in Twilio in " -"de indeling +18005550199." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:197 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:221 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:245 -msgid "" -"Enter variables using either JSON or YAML syntax. Use the radio button to " -"toggle between the two." -msgstr "" -"Voer variabelen in met JSON- of YAML-syntaxis. Gebruik de radioknop om " -"tussen de twee te wisselen." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:187 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:194 -msgid "Environment Variables" -msgstr "Omgevingsvariabelen" - -#: client/src/configuration/configuration.controller.js:348 -#: client/src/configuration/configuration.controller.js:449 -#: client/src/configuration/configuration.controller.js:483 -#: client/src/configuration/configuration.controller.js:530 -#: client/src/configuration/system-form/configuration-system.controller.js:231 -#: client/src/credentials/factories/credential-form-save.factory.js:77 -#: client/src/credentials/factories/credential-form-save.factory.js:93 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:129 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:139 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:166 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:194 -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:213 -#: client/src/management-jobs/card/card.controller.js:140 -#: client/src/management-jobs/card/card.controller.js:230 -#: client/src/management-jobs/card/card.controller.js:28 -#: client/src/projects/add/projects-add.controller.js:108 -#: client/src/projects/edit/projects-edit.controller.js:156 -#: client/src/projects/edit/projects-edit.controller.js:222 -#: client/src/projects/edit/projects-edit.controller.js:238 -#: client/src/projects/list/projects-list.controller.js:169 -#: client/src/projects/list/projects-list.controller.js:198 -#: client/src/projects/list/projects-list.controller.js:225 -#: client/src/projects/list/projects-list.controller.js:246 -#: client/src/projects/list/projects-list.controller.js:262 -#: client/src/projects/list/projects-list.controller.js:271 -#: client/src/users/add/users-add.controller.js:99 -#: client/src/users/edit/users-edit.controller.js:180 -#: client/src/users/edit/users-edit.controller.js:80 -#: client/src/users/list/users-list.controller.js:82 -msgid "Error!" -msgstr "Fout!" - -#: client/src/activity-stream/streams.list.js:40 -msgid "Event" -msgstr "Gebeurtenis" - -#: client/src/job-results/parse-stdout.service.js:68 -msgid "Event ID" -msgstr "Gebeurtenis-ID" - -#: client/src/activity-stream/factories/build-description.factory.js:120 -msgid "Event summary not available" -msgstr "Samenvatting van de gebeurtenis niet beschikbaar" - -#: client/src/projects/add/projects-add.controller.js:129 -#: client/src/projects/edit/projects-edit.controller.js:265 -msgid "Example URLs for GIT SCM include:" -msgstr "Voorbeelden van URL's voor GIT SCM zijn onder andere:" - -#: client/src/projects/add/projects-add.controller.js:150 -#: client/src/projects/edit/projects-edit.controller.js:285 -msgid "Example URLs for Mercurial SCM include:" -msgstr "Voorbeelden van URL's voor Mercurial SCM zijn onder andere:" - -#: client/src/projects/add/projects-add.controller.js:141 -#: client/src/projects/edit/projects-edit.controller.js:276 -msgid "Example URLs for Subversion SCM include:" -msgstr "Voorbeelden van URL's voor Subversion SCM zijn onder andere:" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Example: ansible_facts.ansible_distribution:\"RedHat\"" -msgstr "Voorbeeld: ansible_facts.ansible_distribution:\"RedHat\"" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:76 -msgid "Existing Group" -msgstr "Bestaande groep" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:125 -msgid "Existing Host" -msgstr "Bestaande host" - -#: client/src/job-results/job-results.controller.js:18 -#: client/src/job-results/job-results.controller.js:228 -#: client/src/standard-out/standard-out.controller.js:24 -#: client/src/standard-out/standard-out.controller.js:245 -#: client/src/workflow-results/workflow-results.controller.js:120 -#: client/src/workflow-results/workflow-results.controller.js:76 -msgid "Expand Output" -msgstr "Output uitklappen" - -#: client/src/license/license.partial.html:39 -msgid "Expires On" -msgstr "Verloopt op" - -#: client/src/job-results/job-results.partial.html:81 -msgid "Explanation" -msgstr "Uitleg" - -#: client/src/job-results/job-results.partial.html:275 -msgid "Extra Credentials" -msgstr "Extra toegangsgegevens" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:132 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:144 -#: client/src/job-results/job-results.partial.html:409 -#: client/src/job-submission/job-submission.partial.html:165 -#: client/src/partials/logviewer.html:8 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:105 -#: client/src/templates/job_templates/job-template.form.js:342 -#: client/src/templates/job_templates/job-template.form.js:349 -#: client/src/templates/workflows.form.js:74 -#: client/src/templates/workflows.form.js:81 -msgid "Extra Variables" -msgstr "Extra variabelen" - -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html:4 -#: client/src/inventories-hosts/shared/ansible-facts/ansible-facts.route.js:7 -msgid "FACTS" -msgstr "FEITEN" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:64 -msgid "FAILED" -msgstr "MISLUKT" - -#: client/src/shared/smart-search/smart-search.partial.html:45 -msgid "FIELDS:" -msgstr "VELDEN:" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:39 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:72 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:52 -msgid "FINISHED" -msgstr "VOLTOOID" - -#: client/src/inventories-hosts/hosts/host.form.js:107 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:106 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:107 -msgid "Facts" -msgstr "Feiten" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:80 -msgid "Failed" -msgstr "Mislukt" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:44 -msgid "Failed Hosts" -msgstr "Mislukte hosts" - -#: client/src/users/add/users-add.controller.js:99 -msgid "Failed to add new user. POST returned status:" -msgstr "Nieuwe gebruiker toevoegen mislukt. Geretourneerde statut POSTEN:" - -#: client/src/credentials/factories/credential-form-save.factory.js:78 -msgid "Failed to create new Credential. POST status:" -msgstr "Nieuwe toegangsgegevens aanmaken mislukt. Status POSTEN:" - -#: client/src/projects/add/projects-add.controller.js:109 -msgid "Failed to create new project. POST returned status:" -msgstr "Nieuw project aanmaken mislukt. Geretourneerde status POSTEN:" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:214 -msgid "Failed to retrieve job template extra variables." -msgstr "Extra variabelen van taaksjabloon ophalen mislukt." - -#: client/src/projects/edit/projects-edit.controller.js:157 -msgid "Failed to retrieve project: %s. GET status:" -msgstr "Project ophalen mislukt: %s. status OPHALEN:" - -#: client/src/users/edit/users-edit.controller.js:181 -#: client/src/users/edit/users-edit.controller.js:81 -msgid "Failed to retrieve user: %s. GET status:" -msgstr "Gebruiker ophalen mislukt: %s. Status OPHALEN:" - -#: client/src/configuration/configuration.controller.js:450 -msgid "Failed to save settings. Returned status:" -msgstr "Instellingen opslaan mislukt. Geretourneerde status:" - -#: client/src/configuration/configuration.controller.js:484 -msgid "Failed to save toggle settings. Returned status:" -msgstr "Instellingen wisselen mislukt. Geretourneerde status:" - -#: client/src/credentials/factories/credential-form-save.factory.js:94 -msgid "Failed to update Credential. PUT status:" -msgstr "Toegangsgegevens updaten mislukt. Status PLAATSEN:" - -#: client/src/projects/edit/projects-edit.controller.js:222 -msgid "Failed to update project: %s. PUT status:" -msgstr "Project updaten mislukt: %s. Status PLAATSEN:" - -#: client/src/job-submission/job-submission-factories/launchjob.factory.js:195 -#: client/src/management-jobs/card/card.controller.js:141 -#: client/src/management-jobs/card/card.controller.js:231 -msgid "Failed updating job %s with variables. POST returned: %d" -msgstr "Taak %s met variabelen bijwerken mislukt. Geretourneerde POSTEN: %d" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:24 -msgid "Failed. Click for details" -msgstr "Mislukt. Klik voor meer informatie" - -#: client/src/notifications/notifications.list.js:48 -msgid "Failure" -msgstr "Mislukking" - -#: client/src/scheduler/schedules.list.js:48 -msgid "Final Run" -msgstr "Laatste uitvoering" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:59 -#: client/src/instance-groups/jobs/jobs.list.js:57 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:54 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:58 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:44 -#: client/src/job-results/job-results.partial.html:111 -#: client/src/jobs/all-jobs.list.js:66 -#: client/src/portal-mode/portal-jobs.list.js:40 -#: client/src/templates/completed-jobs.list.js:59 -msgid "Finished" -msgstr "Voltooid" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:21 -#: client/src/users/users.form.js:26 client/src/users/users.list.js:33 -msgid "First Name" -msgstr "Voornaam" - -#: client/src/scheduler/schedules.list.js:38 -msgid "First Run" -msgstr "Eerste uitvoering" - -#: client/src/shared/smart-search/smart-search.partial.html:52 -msgid "" -"For additional information on advanced search search syntax please see the " -"Ansible Tower" -msgstr "" -"Zie de Ansible Tower voor meer informatie over geavanceerde zoeksyntaxis" - -#: client/src/credentials/factories/become-method-change.factory.js:63 -#: client/src/credentials/factories/kind-change.factory.js:120 -msgid "For example, %s" -msgstr "Bijvoorbeeld %s" - -#: client/src/inventories-hosts/hosts/host.form.js:36 -#: client/src/inventories-hosts/hosts/host.list.js:36 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:35 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:32 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:35 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:31 -msgid "" -"For hosts that are part of an external inventory, this flag cannot be " -"changed. It will be set by the inventory sync process." -msgstr "" -"Deze vlag kan niet aangepast worden bij hosts die onderdeel zijn van een " -"externe inventaris. Hij wordt ingesteld door het synchronisatieproces van de" -" inventaris." - -#: client/src/templates/job_templates/job-template.form.js:54 -msgid "" -"For job templates, select run to execute the playbook. Select check to only " -"check playbook syntax, test environment setup, and report problems without " -"executing the playbook." -msgstr "" -"Voor taaksjablonen selecteer \"uitvoeren\" om het draaiboek uit te voeren. " -"Selecteer \"controleren\" om slechts de syntaxis van het draaiboek te " -"controleren, de installatie van de omgeving te testen en problemen te " -"rapporteren zonder het draaiboek uit te voeren." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:118 -msgid "" -"For more information and examples see %sthe Patterns topic at " -"docs.ansible.com%s." -msgstr "" -"Zie %shet thema Patronen op docs.ansible.com%s voor meer informatie en " -"voorbeelden." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:109 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:96 -#: client/src/job-results/job-results.partial.html:336 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:87 -#: client/src/templates/job_templates/job-template.form.js:144 -#: client/src/templates/job_templates/job-template.form.js:154 -msgid "Forks" -msgstr "Vorken" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:172 -msgid "Frequency Details" -msgstr "Frequentie-informatie" - -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.route.js:45 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js:46 -msgid "GROUPS" -msgstr "GROEPEN" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:107 -msgid "GitHub" -msgstr "GitHub" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:108 -msgid "GitHub Org" -msgstr "GitHub Org" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:109 -msgid "GitHub Team" -msgstr "GitHub Team" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:110 -msgid "Google OAuth2" -msgstr "Google OAuth2" - -#: client/src/teams/teams.form.js:155 client/src/users/users.form.js:214 -msgid "Grant Permission" -msgstr "Machtiging toekennen" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Gray" -msgstr "Grijs" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Green" -msgstr "Groen" - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:51 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:52 -msgid "Group Variables" -msgstr "Variabelen ordenen" - -#: client/src/setup-menu/setup-menu.partial.html:5 -msgid "" -"Group all of your content to manage permissions across departments in your " -"company." -msgstr "" -"Orden al uw content om machtigingen van verschillende afdelingen binnen uw " -"bedrijf te beheren." - -#: client/src/inventories-hosts/hosts/host.form.js:115 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:31 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:89 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:88 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:115 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:32 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:167 -msgid "Groups" -msgstr "Groepen" - -#: client/lib/components/components.strings.js:12 -msgid "HIDE" -msgstr "VERBERGEN" - -#: client/lib/components/components.strings.js:39 -msgid "HINT: Drag and drop an SSH private key file on the field below." -msgstr "TIP: sleep een SSH-privésleutelbestand naar het onderstaande veld." - -#: client/src/activity-stream/get-target-title.factory.js:41 -#: client/src/inventories-hosts/hosts/hosts.partial.html:9 -#: client/src/inventories-hosts/hosts/main.js:80 -#: client/src/inventories-hosts/inventories/inventories.partial.html:14 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.route.js:18 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-hosts.route.js:17 -msgid "HOSTS" -msgstr "HOSTS" - -#: client/src/notifications/notificationTemplates.form.js:320 -#: client/src/notifications/notificationTemplates.form.js:321 -msgid "HTTP Headers" -msgstr "HTTP-koppen" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "Hide Activity Stream" -msgstr "Activiteitenlogboek verbergen" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:23 -msgid "High" -msgstr "Hoog" - -#: client/src/credentials/credentials.form.js:139 -#: client/src/notifications/notificationTemplates.form.js:83 -msgid "Host" -msgstr "Host" - -#: client/src/credentials/factories/become-method-change.factory.js:52 -#: client/src/credentials/factories/kind-change.factory.js:109 -msgid "Host (Authentication URL)" -msgstr "Host (authenticatie-URL)" - -#: client/src/templates/job_templates/job-template.form.js:324 -#: client/src/templates/job_templates/job-template.form.js:333 -msgid "Host Config Key" -msgstr "Configuratiesleutel host" - -#: client/src/inventories-hosts/hosts/host.form.js:40 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:39 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:39 -msgid "Host Enabled" -msgstr "Host ingeschakeld" - -#: client/src/inventories-hosts/hosts/host.form.js:46 -#: client/src/inventories-hosts/hosts/host.form.js:57 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:45 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:56 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:45 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:56 -msgid "Host Name" -msgstr "Hostnaam" - -#: client/src/inventories-hosts/hosts/host.form.js:80 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:79 -msgid "Host Variables" -msgstr "Hostvariabelen" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is available" -msgstr "Host is beschikbaar" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is available. Click to toggle." -msgstr "Host is beschikbaar. Klik om te wisselen." - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:6 -msgid "Host is not available" -msgstr "Host is niet beschikbaar" - -#: client/src/inventories-hosts/shared/factories/set-enabled-msg.factory.js:10 -msgid "Host is not available. Click to toggle." -msgstr "Host is niet beschikbaar. Klik om te wisselen." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:39 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:98 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:57 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:56 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:167 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:176 -#: client/src/job-results/job-results.partial.html:504 -msgid "Hosts" -msgstr "Hosts" - -#: client/src/license/license.partial.html:52 -msgid "Hosts Available" -msgstr "Beschikbare hosts" - -#: client/src/license/license.partial.html:64 -msgid "Hosts Remaining" -msgstr "Overgebleven hosts" - -#: client/src/license/license.partial.html:58 -msgid "Hosts Used" -msgstr "Gebruikte hosts" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "Hosts are imported to" -msgstr "Hosts worden geïmporteerd naar" - -#: client/src/license/license.partial.html:121 -msgid "I agree to the End User License Agreement" -msgstr "Ik ga akkoord met de licentie-overeenkomst voor eindgebruikers" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:27 -#: client/src/instance-groups/jobs/jobs.list.js:26 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:38 -msgid "ID" -msgstr "ID" - -#: client/src/partials/job-template-details.html:2 -msgid "INFO" -msgstr "INFO" - -#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 -msgid "INITIATED BY" -msgstr "GESTART DOOR" - -#: client/src/inventories-hosts/inventories/insights/insights.route.js:7 -msgid "INSIGHTS" -msgstr "INZICHTEN" - -#: client/src/instance-groups/instance-groups.list.js:6 -#: client/src/instance-groups/instance-groups.list.js:7 -#: client/src/instance-groups/instance-groups.route.js:10 -#: client/src/instance-groups/list/instance-groups-list.partial.html:3 -msgid "INSTANCE GROUPS" -msgstr "INSTANTIEGROEPEN" - -#: client/src/instance-groups/instance-group.partial.html:27 -msgid "INSTANCES" -msgstr "INSTANTIES" - -#: client/src/activity-stream/get-target-title.factory.js:14 -#: client/src/inventories-hosts/hosts/hosts.partial.html:8 -#: client/src/inventories-hosts/inventories/inventories.partial.html:13 -#: client/src/inventories-hosts/inventories/inventories.route.js:8 -#: client/src/inventories-hosts/inventories/inventory.list.js:14 -#: client/src/inventories-hosts/inventories/inventory.list.js:15 -#: client/src/main-menu/main-menu.partial.html:104 -#: client/src/main-menu/main-menu.partial.html:27 -#: client/src/organizations/linkout/organizations-linkout.route.js:143 -#: client/src/organizations/list/organizations-list.controller.js:66 -msgid "INVENTORIES" -msgstr "INVENTARISSEN" - -#: client/src/job-submission/job-submission.partial.html:346 -#: client/src/partials/job-template-details.html:2 -msgid "INVENTORY" -msgstr "INVENTARIS" - -#: client/src/inventory-scripts/inventory-scripts.form.js:23 -msgid "INVENTORY SCRIPT" -msgstr "INVENTARISSCRIPT" - -#: client/src/activity-stream/get-target-title.factory.js:35 -#: client/src/inventory-scripts/inventory-scripts.list.js:12 -#: client/src/inventory-scripts/main.js:66 -msgid "INVENTORY SCRIPTS" -msgstr "INVENTARISSCRIPTS" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js:8 -msgid "INVENTORY SOURCES" -msgstr "INVENTARISBRONNEN" - -#: client/src/notifications/notificationTemplates.form.js:348 -msgid "IRC Nick" -msgstr "IRC-bijnaam" - -#: client/src/notifications/notificationTemplates.form.js:337 -msgid "IRC Server Address" -msgstr "IRC-serveradres" - -#: client/src/notifications/shared/type-change.service.js:58 -msgid "IRC Server Password" -msgstr "IRC-serverwachtwoord" - -#: client/src/notifications/shared/type-change.service.js:57 -msgid "IRC Server Port" -msgstr "IRC-serverpoort" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:79 -msgid "ISSUE: {{report.rule.description}}" -msgstr "PROBLEEM: {{report.rule.description}}" - -#: client/src/shared/paginate/paginate.partial.html:43 -msgid "ITEMS" -msgstr "ITEMS" - -#: client/src/login/authenticationServices/timer.factory.js:157 -msgid "Idle Session" -msgstr "Inactieve sessie" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "If blank, all groups above are created except" -msgstr "" -"Als dit vakje leeg wordt gelaten, worden alle bovenstaande groepen " -"aangemaakt, behalve" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:343 -msgid "" -"If checked, all variables for child groups and hosts will be removed and " -"replaced by those found on the external source." -msgstr "" -"Als dit vakje aangevinkt is, worden alle variabelen voor onderliggende " -"groepen en hosts verwijderd en worden ze vervangen door de variabelen die " -"aangetroffen worden in de externe bron." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:331 -msgid "" -"If checked, any hosts and groups that were previously present on the " -"external source but are now removed will be removed from the Tower " -"inventory. Hosts and groups that were not managed by the inventory source " -"will be promoted to the next manually created group or if there is no " -"manually created group to promote them into, they will be left in the " -"\"all\" default group for the inventory." -msgstr "" -"Als dit vakje aangevinkt is, worden alle groepen en hosts die eerder " -"aanwezig waren in de externe bron, maar die nu verwijderd zijn, verwijderd " -"uit de inventaris. Hosts en groepen die niet beheerd werden door de " -"inventarisbron, worden omhoog verplaatst naar de volgende handmatig gemaakte" -" groep. Als er geen handmatig gemaakte groep is waar ze naartoe kunnen " -"worden verplaatst, blijven ze staan in de standaard inventarisgroep 'Alle'." - -#: client/src/templates/job_templates/job-template.form.js:267 -msgid "If enabled, run this playbook as an administrator." -msgstr "" -"Als deze optie ingeschakeld is, wordt het draaiboek uitgevoerd als " -"beheerder." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:120 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Als deze mogelijkheid ingeschakeld is, worden de wijzigingen die aangebracht" -" zijn door Ansible-taken weergegeven, waar ondersteund. Dit staat gelijk aan" -" de diff-modus van Ansible." - -#: client/src/templates/job_templates/job-template.form.js:251 -msgid "" -"If enabled, show the changes made by Ansible tasks, where supported. This is" -" equivalent to Ansible’s --diff mode." -msgstr "" -"Als deze mogelijkheid ingeschakeld is, worden de wijzigingen die aangebracht" -" zijn door Ansible-taken weergegeven, waar ondersteund. Dit staat gelijk aan" -" de diff-modus van Ansible." - -#: client/src/templates/job_templates/job-template.form.js:291 -msgid "If enabled, simultaneous runs of this job template will be allowed." -msgstr "" -"Indien deze mogelijkheid ingeschakeld is, zijn gelijktijdige uitvoeringen " -"van deze taaksjabloon toegestaan." - -#: client/src/templates/job_templates/job-template.form.js:302 -msgid "" -"If enabled, use cached facts if available and store discovered facts in the " -"cache." -msgstr "" -"Gebruik gecachete feiten als deze beschikbaar zijn en sla feiten die ontdekt" -" zijn op in de cache, indien deze mogelijkheid ingeschakeld is." - -#: client/src/credentials/credentials.form.js:52 -msgid "" -"If no organization is given, the credential can only be used by the user " -"that creates the credential. Organization admins and system administrators " -"can assign an organization so that roles for the credential can be assigned " -"to users and teams in that organization." -msgstr "" -"Als er geen organisatie opgegeven is, kunnen de toegangsgegevens alleen " -"gebruikt worden door de gebruiker die de toegangsgegevens aangemaakt heeft. " -"Beheerders van organisaties en systeembeheerders kunnen een organisatie " -"toewijzen zodat rollen voor de toegangsgegevens toegewezen kunnen worden aan" -" gebruikers en teams binnen die organisatie." - -#: client/src/license/license.partial.html:70 -msgid "" -"If you are ready to upgrade, please contact us by clicking the button below" -msgstr "" -"Neem zodra u klaar bent om te updaten contact met ons op door op de " -"onderstaande knop te klikken" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:173 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:254 -msgid "Image ID:" -msgstr "Afbeelding-ID:" - -#: client/src/inventories-hosts/hosts/host.form.js:34 -#: client/src/inventories-hosts/hosts/host.list.js:34 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:33 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:30 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:33 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:29 -msgid "" -"Indicates if a host is available and should be included in running jobs." -msgstr "" -"Geeft aan of een host beschikbaar is, moet opgenomen worden in taken die in " -"uitvoering zijn." - -#: client/src/activity-stream/activity-detail.form.js:31 -#: client/src/activity-stream/streams.list.js:33 -msgid "Initiated by" -msgstr "Gestart door" - -#: client/src/credential-types/credential-types.form.js:53 -#: client/src/credential-types/credential-types.form.js:61 -msgid "Injector Configuration" -msgstr "Configuratie-injector" - -#: client/src/credential-types/credential-types.form.js:39 -#: client/src/credential-types/credential-types.form.js:47 -msgid "Input Configuration" -msgstr "Configuratie-input" - -#: client/src/inventories-hosts/hosts/host.form.js:123 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:122 -msgid "Insights" -msgstr "Inzichten" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:69 -msgid "Insights Credential" -msgstr "Inzichten toegangsgegevens" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:145 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:148 -msgid "Instance Filters" -msgstr "Instantiefilters" - -#: client/src/job-results/job-results.partial.html:369 -msgid "Instance Group" -msgstr "Instantiegroep" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:72 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:75 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:78 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:81 -#: client/src/organizations/organizations.form.js:38 -#: client/src/organizations/organizations.form.js:41 -#: client/src/setup-menu/setup-menu.partial.html:54 -#: client/src/templates/job_templates/job-template.form.js:191 -#: client/src/templates/job_templates/job-template.form.js:194 -msgid "Instance Groups" -msgstr "Instantiegroepen" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:182 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:263 -msgid "Instance ID" -msgstr "Instantie-ID" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:174 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:255 -msgid "Instance ID:" -msgstr "Instantie-ID:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:175 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:256 -msgid "Instance Type:" -msgstr "Instantietype:" - -#: client/src/license/license.partial.html:11 -msgid "Invalid License" -msgstr "Ongeldige licentie" - -#: client/src/license/license.controller.js:63 -#: client/src/license/license.controller.js:70 -msgid "Invalid file format. Please upload valid JSON." -msgstr "Ongeldige bestandsindeling. Upload een geldige JSON." - -#: client/lib/components/components.strings.js:16 -msgid "Invalid input for this type." -msgstr "Ongeldige input voor dit type." - -#: client/src/login/loginModal/loginModal.partial.html:34 -msgid "Invalid username and/or password. Please try again." -msgstr "Ongeldige gebruikersnaam en/of wachtwoord. Probeer het opnieuw." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:122 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:52 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:50 -#: client/src/organizations/linkout/organizations-linkout.route.js:155 -msgid "Inventories" -msgstr "Inventarissen" - -#: client/src/inventories-hosts/hosts/host.list.js:69 -#: client/src/inventories-hosts/inventories/inventory.list.js:80 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/job-results/job-results.partial.html:201 -#: client/src/job-submission/job-submission.partial.html:17 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:58 -#: client/src/templates/job_templates/job-template.form.js:66 -#: client/src/templates/job_templates/job-template.form.js:80 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:72 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:82 -msgid "Inventory" -msgstr "Inventaris" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:110 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:124 -msgid "Inventory File" -msgstr "Inventarisbestand" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 -#: client/src/setup-menu/setup-menu.partial.html:41 -msgid "Inventory Scripts" -msgstr "Inventarisscript" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:46 -msgid "Inventory Sync" -msgstr "Inventarissynchronisatie" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:55 -msgid "Inventory Sync Failures" -msgstr "Fouten bij inventarissynchronisatie" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:93 -msgid "Inventory Variables" -msgstr "Inventarisvariabelen" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:66 -msgid "Inventory contains 0 hosts." -msgstr "Inventaris bevat 0 hosts." - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:4 -msgid "JOB STATUS" -msgstr "TAAKSTATUS" - -#: client/src/templates/job_templates/job-template.form.js:22 -msgid "JOB TEMPLATE" -msgstr "TAAKSJABLOON" - -#: client/src/organizations/linkout/organizations-linkout.route.js:256 -#: client/src/organizations/list/organizations-list.controller.js:78 -#: client/src/portal-mode/portal-job-templates.list.js:13 -#: client/src/portal-mode/portal-job-templates.list.js:14 -msgid "JOB TEMPLATES" -msgstr "TAAKSJABLONEN" - -#: client/src/activity-stream/get-target-title.factory.js:32 -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:118 -#: client/src/instance-groups/instance-group.partial.html:28 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:27 -#: client/src/instance-groups/jobs/jobs-list.route.js:9 -#: client/src/jobs/jobs.route.js:15 -#: client/src/main-menu/main-menu.partial.html:122 -#: client/src/main-menu/main-menu.partial.html:43 -#: client/src/portal-mode/portal-jobs.list.js:13 -#: client/src/portal-mode/portal-jobs.list.js:17 -msgid "JOBS" -msgstr "TAKEN" - -#: client/src/job-submission/job-submission.partial.html:173 -msgid "JSON" -msgstr "JSON" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:198 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:222 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:246 -msgid "JSON:" -msgstr "JSON:" - -#: client/src/job-results/job-results.partial.html:384 -#: client/src/job-submission/job-submission.partial.html:228 -#: client/src/templates/job_templates/job-template.form.js:200 -#: client/src/templates/job_templates/job-template.form.js:207 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:127 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:135 -msgid "Job Tags" -msgstr "Taaktags" - -#: client/src/templates/templates.list.js:61 -msgid "Job Template" -msgstr "Taaksjabloon" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:36 -#: client/src/organizations/linkout/organizations-linkout.route.js:268 -msgid "Job Templates" -msgstr "Taaksjablonen" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:32 -#: client/src/job-results/job-results.partial.html:159 -#: client/src/job-submission/job-submission.partial.html:202 -#: client/src/templates/job_templates/job-template.form.js:47 -#: client/src/templates/job_templates/job-template.form.js:55 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:103 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:92 -msgid "Job Type" -msgstr "Soort taak" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:46 -msgid "" -"Job details are not available for this job. Please download to view " -"standard out." -msgstr "" -"Taakinformatie is niet beschikbaar voor deze taak. Download om de " -"standaardoutput te bekijken." - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 -#: client/src/configuration/configuration.partial.html:16 -#: client/src/jobs/jobs.partial.html:7 -msgid "Jobs" -msgstr "Taken" - -#: client/src/job-results/job-results.controller.js:269 -#: client/src/job-results/job-results.controller.js:366 -msgid "Jump to last line of standard out." -msgstr "Meteen naar de laatste regel van de standaardoutput gaan." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:61 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:154 -#: client/src/shared/smart-search/smart-search.partial.html:14 -msgid "Key" -msgstr "Sleutel" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:176 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:257 -msgid "Key Name:" -msgstr "Naam sleutel:" - -#: client/src/credential-types/credential-types.list.js:31 -#: client/src/credentials/credentials.list.js:33 -msgid "Kind" -msgstr "Type" - -#: client/src/job-submission/job-submission.partial.html:6 -msgid "LAUNCH JOB" -msgstr "TAAK STARTEN" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:86 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:66 -msgid "LAUNCH TYPE" -msgstr "SOORT STARTEN" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:111 -msgid "LDAP" -msgstr "LDAP" - -#: client/src/license/license.route.js:19 -msgid "LICENSE" -msgstr "LICENTIE" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:58 -msgid "LICENSE ERROR" -msgstr "LICENTIEFOUT" - -#: client/src/main-menu/main-menu.partial.html:83 -msgid "LOG OUT" -msgstr "AFMELDEN" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:68 -#: client/src/instance-groups/jobs/jobs.list.js:66 -#: client/src/job-results/job-results.partial.html:434 -#: client/src/job-results/job-results.partial.html:443 -#: client/src/jobs/all-jobs.list.js:74 -#: client/src/templates/job_templates/job-template.form.js:234 -#: client/src/templates/job_templates/job-template.form.js:238 -#: client/src/templates/templates.list.js:43 -#: client/src/templates/workflows.form.js:62 -#: client/src/templates/workflows.form.js:67 -msgid "Labels" -msgstr "Labels" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:25 -#: client/src/users/users.form.js:33 client/src/users/users.list.js:37 -msgid "Last Name" -msgstr "Achternaam" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:56 -msgid "Last Sync" -msgstr "Laatste synchronisatie" - -#: client/src/projects/projects.list.js:56 -msgid "Last Updated" -msgstr "Laatst geüpdatet" - -#: client/src/portal-mode/portal-job-templates.list.js:36 -#: client/src/shared/form-generator.js:1707 -#: client/src/templates/templates.list.js:80 -msgid "Launch" -msgstr "Starten" - -#: client/src/management-jobs/card/card.partial.html:23 -msgid "Launch Management Job" -msgstr "Beheertaak starten" - -#: client/src/job-results/job-results.partial.html:170 -#: client/src/job-results/job-results.partial.html:185 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:76 -msgid "Launched By" -msgstr "Gestart door" - -#: client/src/job-submission/job-submission.partial.html:99 -msgid "" -"Launching this job requires the passwords listed below. Enter and confirm " -"each password before continuing." -msgstr "" -"Voor het starten van deze taak zijn onderstaande wachtwoorden nodig. Ieder " -"wachtwoord dient ingevoerd en bevestigd te worden voordat u verdergaat." - -#: client/features/credentials/legacy.credentials.js:357 -msgid "Legacy state configuration for does not exist" -msgstr "Er bestaat geen oude staat van configuratie voor" - -#: client/src/license/license.controller.js:40 -#: client/src/license/license.partial.html:8 -msgid "License" -msgstr "Licentie" - -#: client/src/license/license.partial.html:104 -msgid "License File" -msgstr "Licentiebestand" - -#: client/src/license/license.partial.html:33 -msgid "License Key" -msgstr "Licentiesleutel" - -#: client/src/license/license.controller.js:40 -msgid "License Management" -msgstr "Licentiebeheer" - -#: client/src/license/license.partial.html:21 -msgid "License Type" -msgstr "Licentiesoort" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:45 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:55 -#: client/src/job-results/job-results.partial.html:347 -#: client/src/job-submission/job-submission.partial.html:220 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:92 -#: client/src/templates/job_templates/job-template.form.js:160 -#: client/src/templates/job_templates/job-template.form.js:164 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:113 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:120 -msgid "Limit" -msgstr "Limiet" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:186 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:268 -msgid "Limit to hosts having a tag:" -msgstr "Beperken tot hosts met een tag:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:188 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:270 -msgid "Limit to hosts using either key pair:" -msgstr "Beperken tot hosts die één van de sleutelparen gebruiken:" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "Limit to hosts where the Name tag begins with" -msgstr "Beperken tot hosts waarvan de naam begint met" - -#: client/src/shared/socket/socket.service.js:168 -msgid "Live events: attempting to connect to the server." -msgstr "" -"Livegebeurtenissen: er wordt geprobeerd verbinding met de server te maken." - -#: client/src/shared/socket/socket.service.js:172 -msgid "" -"Live events: connected. Pages containing job status information will " -"automatically update in real-time." -msgstr "" -"Livegebeurtenissen: verbonden. Pagina's met informatie over de status van " -"taken worden automatisch geüpdatet in realtime." - -#: client/src/shared/socket/socket.service.js:176 -msgid "Live events: error connecting to the server." -msgstr "Livegebeurtenissen: fout bij het verbinding maken met de server." - -#: client/src/shared/form-generator.js:1983 -msgid "Loading..." -msgstr "Laden..." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:133 -msgid "Local Time Zone" -msgstr "Lokale tijdzone" - -#: client/src/main-menu/main-menu.partial.html:188 -msgid "Log Out" -msgstr "Afmelden" - -#: client/src/configuration/system-form/configuration-system.controller.js:225 -msgid "Log aggregator test failed.
Detail:" -msgstr "Log aggregator-test mislukt.
Details:" - -#: client/src/configuration/system-form/configuration-system.controller.js:218 -msgid "Log aggregator test successful." -msgstr "Log aggregator-test gelukt." - -#: client/src/configuration/system-form/configuration-system.controller.js:89 -msgid "Logging" -msgstr "Bezig met dataregistratie" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:35 -msgid "Low" -msgstr "Laag" - -#: client/src/management-jobs/card/card.partial.html:6 -#: client/src/management-jobs/card/card.route.js:21 -msgid "MANAGEMENT JOBS" -msgstr "BEHEERDERSTAKEN" - -#: client/src/portal-mode/portal-mode.route.js:12 -msgid "MY VIEW" -msgstr "MIJN BEELD" - -#: client/src/credentials/credentials.form.js:67 -#: client/src/job-submission/job-submission.partial.html:356 -msgid "Machine" -msgstr "Machine" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:60 -#: client/src/job-results/job-results.partial.html:260 -msgid "Machine Credential" -msgstr "Toegangsgegevens machine" - -#: client/src/setup-menu/setup-menu.partial.html:36 -msgid "" -"Manage the cleanup of old job history, activity streams, data marked for " -"deletion, and system tracking info." -msgstr "" -"Het opschonen van oude taakgeschiedenis, activiteitenlogboeken, gegevens die" -" verwijderd moeten worden en trackinginformatie van het systeem." - -#: client/src/setup-menu/setup-menu.partial.html:35 -msgid "Management Jobs" -msgstr "Beheerderstaken" - -#: client/src/projects/list/projects-list.controller.js:89 -msgid "Manual projects do not require a schedule" -msgstr "Voor handmatige projecten is geen schema nodig" - -#: client/src/projects/edit/projects-edit.controller.js:141 -#: client/src/projects/list/projects-list.controller.js:88 -msgid "Manual projects do not require an SCM update" -msgstr "Voor handmatige projecten is geen SCM-update nodig" - -#: client/src/login/loginModal/loginModal.partial.html:28 -msgid "Maximum per-user sessions reached. Please sign in." -msgstr "Maximaal aantal sessies per gebruiker bereikt. Meld u aan." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:29 -msgid "Medium" -msgstr "Medium" - -#: client/src/configuration/system-form/configuration-system.controller.js:90 -msgid "Misc. System" -msgstr "Overig systeem" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:27 -msgid "Missing. Click for details" -msgstr "Ontbreekt. Klik voor informatie" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:22 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:30 -msgid "Module" -msgstr "Module" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:53 -msgid "Module Args" -msgstr "Module Args" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:25 -msgid "Most recent job failed. Click to view jobs." -msgstr "Meest recente taak is mislukt. Klik om taken te bekijken." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:29 -msgid "Most recent job successful. Click to view jobs." -msgstr "Meest recente taak is gelukt. Klik om taken te bekijken." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:77 -msgid "Multiple Choice Options" -msgstr "Meerkeuze-opties" - -#: client/src/portal-mode/portal-mode-jobs.partial.html:4 -#: client/src/portal-mode/portal-mode-layout.partial.html:11 -msgid "My Jobs" -msgstr "Mijn taken" - -#: client/src/main-menu/main-menu.partial.html:160 -msgid "My View" -msgstr "Mijn beeld" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:19 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:19 -msgid "NAME" -msgstr "NAAM" - -#: client/features/credentials/credentials.strings.js:24 -msgid "NEW CREDENTIAL" -msgstr "NIEUWE TOEGANGSGEGEVENS" - -#: client/src/credential-types/credential-types.form.js:16 -msgid "NEW CREDENTIAL TYPE" -msgstr "NIEUWE SOORT TOEGANGSGEGEVENS" - -#: client/src/inventory-scripts/inventory-scripts.form.js:16 -msgid "NEW CUSTOM INVENTORY" -msgstr "NIEUWE AANGEPASTE INVENTARIS" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:34 -msgid "NEW INVENTORY" -msgstr "NIEUWE INVENTARIS" - -#: client/src/templates/job_templates/job-template.form.js:19 -msgid "NEW JOB TEMPLATE" -msgstr "NIEUWE TAAKSJABLOON" - -#: client/src/notifications/notificationTemplates.form.js:16 -msgid "NEW NOTIFICATION TEMPLATE" -msgstr "NIEUWE BERICHTSJABLOON" - -#: client/src/organizations/organizations.form.js:18 -msgid "NEW ORGANIZATION" -msgstr "NIEUWE ORGANISATIE" - -#: client/src/projects/projects.form.js:16 -msgid "NEW PROJECT" -msgstr "NIEUW PROJECT" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:28 -msgid "NEW SMART INVENTORY" -msgstr "NIEUW SMART-INVENTARIS" - -#: client/src/teams/teams.form.js:16 -msgid "NEW TEAM" -msgstr "NIEUW TEAM" - -#: client/src/users/users.form.js:16 -msgid "NEW USER" -msgstr "NIEUWE GEBRUIKER" - -#: client/src/templates/workflows.form.js:17 -msgid "NEW WORKFLOW JOB TEMPLATE" -msgstr "NIEUWE WORKFLOW-TAAKSJABLOON" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:38 -msgid "NO HOSTS HAVE BEEN CREATED" -msgstr "GEEN HOSTS AANGEMAAKT" - -#: client/lib/components/components.strings.js:35 -msgid "NO OPTIONS AVAILABLE" -msgstr "GEEN OPTIES BESCHIKBAAR" - -#: client/src/login/loginModal/loginModal.partial.html:89 -msgid "NOTICE" -msgstr "MEDEDELING" - -#: client/src/notifications/notificationTemplates.form.js:21 -msgid "NOTIFICATION TEMPLATE" -msgstr "BERICHTSJABLOON" - -#: client/src/activity-stream/get-target-title.factory.js:26 -#: client/src/notifications/notificationTemplates.list.js:14 -msgid "NOTIFICATION TEMPLATES" -msgstr "BERICHTSJABLONEN" - -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-notifications.route.js:9 -#: client/src/management-jobs/notifications/notification.route.js:46 -#: client/src/notifications/main.js:43 client/src/notifications/main.js:91 -msgid "NOTIFICATIONS" -msgstr "BERICHTEN" - -#: client/src/credential-types/credential-types.form.js:27 -#: client/src/credential-types/credential-types.list.js:24 -#: client/src/credentials/credentials.form.js:32 -#: client/src/credentials/credentials.list.js:26 -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:14 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:13 -#: client/src/instance-groups/instance-groups.list.js:15 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:35 -#: client/src/instance-groups/instances/instances-list.partial.html:15 -#: client/src/instance-groups/instances/instances.list.js:14 -#: client/src/instance-groups/jobs/jobs.list.js:34 -#: client/src/instance-groups/list/instance-groups-list.partial.html:26 -#: client/src/inventories-hosts/hosts/host.list.js:61 -#: client/src/inventories-hosts/inventories/inventory.list.js:47 -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:45 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:32 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:33 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:51 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:39 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:45 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:45 -#: client/src/inventory-scripts/inventory-scripts.form.js:28 -#: client/src/inventory-scripts/inventory-scripts.list.js:20 -#: client/src/jobs/all-jobs.list.js:43 -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 -#: client/src/notifications/notificationTemplates.form.js:32 -#: client/src/notifications/notificationTemplates.list.js:32 -#: client/src/notifications/notifications.list.js:26 -#: client/src/organizations/organizations.form.js:26 -#: client/src/portal-mode/portal-job-templates.list.js:23 -#: client/src/portal-mode/portal-jobs.list.js:35 -#: client/src/projects/projects.form.js:29 -#: client/src/projects/projects.list.js:37 -#: client/src/scheduler/scheduled-jobs.list.js:31 -#: client/src/scheduler/schedules.list.js:33 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:19 -#: client/src/teams/teams.form.js:124 client/src/teams/teams.form.js:25 -#: client/src/teams/teams.list.js:23 -#: client/src/templates/completed-jobs.list.js:46 -#: client/src/templates/job_templates/job-template.form.js:34 -#: client/src/templates/templates.list.js:24 -#: client/src/templates/workflows.form.js:32 -#: client/src/users/users.form.js:142 client/src/users/users.form.js:168 -#: client/src/users/users.form.js:194 -msgid "Name" -msgstr "Naam" - -#: client/src/credentials/credentials.form.js:71 -msgid "Network" -msgstr "Netwerk" - -#: client/src/job-results/job-results.partial.html:306 -msgid "Network Credential" -msgstr "Netwerktoegangsgegevens" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:81 -msgid "New Group" -msgstr "Nieuwe groep" - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:130 -msgid "New Host" -msgstr "Nieuwe host" - -#: client/src/users/add/users-add.controller.js:91 -msgid "New user successfully created!" -msgstr "Nieuwe gebruiker aanmaken gelukt!" - -#: client/src/scheduler/scheduled-jobs.list.js:51 -#: client/src/scheduler/schedules.list.js:43 -msgid "Next Run" -msgstr "Volgende uitvoering" - -#: client/src/credentials/credentials.list.js:21 -msgid "No Credentials Have Been Created" -msgstr "Nog geen toegangsgegevens aangemaakt" - -#: client/src/job-submission/lists/credential/job-sub-cred-list.controller.js:44 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:140 -msgid "No Credentials Matching This Type Have Been Created" -msgstr "Nog geen toegangsgegevens die overeenkomen met deze soort aangemaakt" - -#: client/src/job-results/host-event/host-event-codemirror.partial.html:3 -msgid "No JSON data returned by the module" -msgstr "Module heeft geen JSON-gegevens geretourneerd" - -#: client/src/projects/projects.list.js:20 -msgid "No Projects Have Been Created" -msgstr "Nog geen projecten aangemaakt" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:50 -msgid "No Remediation Playbook Available" -msgstr "Geen draaiboek voor herstel beschikbaar" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "No SCM Configuration" -msgstr "Geen SCM-configuratie" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:9 -msgid "No SCM updates have run for this project" -msgstr "Geen SCM-updates uitgevoerd voor dit project" - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:17 -msgid "No Teams exist" -msgstr "Er bestaan geen teams" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "No Updates Available" -msgstr "Er zijn geen updates beschikbaar" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:18 -msgid "No Users exist" -msgstr "Er bestaan geen gebruikers" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:23 -#: client/src/templates/completed-jobs.list.js:24 -msgid "No completed jobs" -msgstr "Geen voltooide taken" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:63 -msgid "No data is available. There are no issues to report." -msgstr "Geen gegevens beschikbaar. Er zijn geen problemen om te rapporteren." - -#: client/src/license/license.controller.js:39 -msgid "No file selected." -msgstr "Geen bestand geselecteerd." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:62 -msgid "No hosts with failures. Click for details." -msgstr "Geen host met mislukkingen. Klik voor meer informatie." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:47 -msgid "No inventory sync failures. Click for details." -msgstr "Geen mislukte inventarissynchronisaties. Klik voor meer informatie." - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:16 -msgid "No job data" -msgstr "Geen taakgegevens" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:75 -msgid "No job data available." -msgstr "Geen taakgegevens beschikbaar." - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:22 -msgid "No job failures" -msgstr "Geen mislukte taken" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:54 -msgid "No job templates were recently used." -msgstr "Geen taaksjablonen die recent gebruikt zijn." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:9 -#: client/src/instance-groups/jobs/jobs.list.js:9 -#: client/src/jobs/all-jobs.list.js:18 -msgid "No jobs have yet run." -msgstr "Er zijn nog geen taken uitgevoerd." - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:44 -msgid "No jobs were recently run." -msgstr "Er zijn recent geen taken uitgevoerd." - -#: client/src/teams/teams.form.js:121 client/src/users/users.form.js:191 -msgid "No permissions have been granted" -msgstr "Geen machtigingen toegekend" - -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:17 -msgid "No recent job data available for this host." -msgstr "Er zijn geen recente taakgegevens beschikbaar voor deze host." - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:75 -msgid "No recent job data available for this inventory." -msgstr "Er zijn geen recente taakgegevens beschikbaar voor dit inventaris." - -#: client/src/notifications/notification-templates-list/list.controller.js:86 -msgid "No recent notifications." -msgstr "Geen recente berichten." - -#: client/src/inventories-hosts/hosts/hosts.partial.html:36 -#: client/src/shared/form-generator.js:1879 -#: client/src/shared/list-generator/list-generator.factory.js:240 -msgid "No records matched your search." -msgstr "Er zijn geen gegevens die overeenkomen met uw zoekopdracht." - -#: client/src/scheduler/scheduled-jobs.list.js:16 -msgid "No schedules exist" -msgstr "Er bestaan geen schema's" - -#: client/src/job-submission/job-submission.partial.html:348 -#: client/src/job-submission/job-submission.partial.html:353 -msgid "None selected" -msgstr "Geen geselecteerd" - -#: client/src/users/add/users-add.controller.js:10 -#: client/src/users/edit/users-edit.controller.js:10 -#: client/src/users/list/users-list.controller.js:10 -msgid "Normal User" -msgstr "Normale gebruiker" - -#: client/src/projects/list/projects-list.controller.js:91 -msgid "Not configured for SCM" -msgstr "Niet geconfigureerd voor SCM" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:52 -msgid "Not configured for inventory sync." -msgstr "Niet geconfigureerd voor inventarissynchronisatie." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate.partial.html:25 -msgid "" -"Note that only hosts directly in this group can be disassociated. Hosts in " -"sub-groups must be disassociated directly from the sub-group level that they" -" belong." -msgstr "" -"Let op: Alleen hosts die zich direct in deze groep bevinden, kunnen worden " -"losgekoppeld. Hosts in subgroepen moeten rechtstreeks worden losgekoppeld " -"van het subgroepniveau waar ze bij horen." - -#: client/src/notifications/notificationTemplates.form.js:288 -#: client/src/notifications/notificationTemplates.form.js:289 -msgid "Notification Color" -msgstr "Berichtkleur" - -#: client/src/notifications/notification-templates-list/list.controller.js:113 -msgid "Notification Failed." -msgstr "Bericht mislukt" - -#: client/src/notifications/notificationTemplates.form.js:277 -msgid "Notification Label" -msgstr "Berichtlabel" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 -msgid "Notification Templates" -msgstr "Berichtsjablonen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:20 -#: client/src/management-jobs/notifications/notification.route.js:21 -#: client/src/notifications/notifications.list.js:17 -#: client/src/setup-menu/setup-menu.partial.html:48 -msgid "Notifications" -msgstr "Berichten" - -#: client/src/notifications/notificationTemplates.form.js:302 -msgid "Notify Channel" -msgstr "Bericht naar kanaal sturen" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:55 -#: client/src/job-submission/job-submission.partial.html:269 -#: client/src/partials/survey-maker-modal.html:27 -#: client/src/shared/form-generator.js:542 -#: client/src/shared/form-generator.js:773 -#: client/src/shared/generator-helpers.js:551 -msgid "OFF" -msgstr "UIT" - -#: client/lib/services/base-string.service.js:63 -#: client/src/jobs/factories/delete-job.factory.js:115 -msgid "OK" -msgstr "OK" - -#: client/src/inventories-hosts/hosts/hosts.partial.html:54 -#: client/src/job-submission/job-submission.partial.html:267 -#: client/src/partials/survey-maker-modal.html:26 -#: client/src/shared/form-generator.js:538 -#: client/src/shared/form-generator.js:771 -#: client/src/shared/generator-helpers.js:547 -msgid "ON" -msgstr "AAN" - -#: client/lib/components/components.strings.js:10 -msgid "OPTIONS" -msgstr "OPTIES" - -#: client/src/activity-stream/get-target-title.factory.js:29 -#: client/src/organizations/list/organizations-list.partial.html:6 -#: client/src/organizations/main.js:52 -msgid "ORGANIZATIONS" -msgstr "ORGANISATIES" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:116 -msgid "OVERWRITE" -msgstr "OVERSCHRIJVEN" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:123 -msgid "OVERWRITE VARS" -msgstr "VARIABELEN OVERSCHRIJVEN" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:38 -msgid "On Failure" -msgstr "Bij mislukken" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:33 -msgid "On Success" -msgstr "Bij slagen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:157 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:162 -msgid "Only Group By" -msgstr "Alleen ordenen op" - -#: client/src/credentials/credentials.form.js:379 -msgid "" -"OpenStack domains define administrative boundaries. It is only needed for " -"Keystone v3 authentication URLs. Common scenarios include:" -msgstr "" -"Domeinen van OpenStack bepalen administratieve grenzen. Het is alleen nodig " -"voor Keystone v3 authenticatie-URL's. Veel voorkomende scenario's zijn:" - -#: client/src/templates/job_templates/job-template.form.js:240 -#: client/src/templates/workflows.form.js:69 -msgid "" -"Optional labels that describe this job template, such as 'dev' or 'test'. " -"Labels can be used to group and filter job templates and completed jobs." -msgstr "" -"Optionele labels die de taaksjabloon beschrijven, zoals 'dev' of 'test'. " -"Labels kunnen gebruikt worden om taaksjablonen en uitgevoerde taken te " -"ordenen en filteren." - -#: client/src/notifications/notificationTemplates.form.js:382 -#: client/src/partials/logviewer.html:7 -#: client/src/templates/job_templates/job-template.form.js:259 -msgid "Options" -msgstr "Opties" - -#: client/src/credentials/credentials.form.js:46 -#: client/src/credentials/credentials.form.js:53 -#: client/src/inventories-hosts/inventories/inventory.list.js:60 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:51 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:58 -#: client/src/inventory-scripts/inventory-scripts.form.js:40 -#: client/src/inventory-scripts/inventory-scripts.list.js:27 -#: client/src/notifications/notificationTemplates.form.js:44 -#: client/src/projects/projects.form.js:41 -#: client/src/projects/projects.form.js:47 client/src/teams/teams.form.js:37 -#: client/src/teams/teams.list.js:30 client/src/templates/workflows.form.js:45 -#: client/src/templates/workflows.form.js:51 client/src/users/users.form.js:40 -msgid "Organization" -msgstr "Organisatie" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:136 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:64 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:30 -#: client/src/setup-menu/setup-menu.partial.html:4 -#: client/src/users/users.form.js:132 -msgid "Organizations" -msgstr "Organisaties" - -#: client/src/job-submission/job-submission.partial.html:19 -msgid "Other Prompts" -msgstr "Overige meldingen" - -#: client/src/credentials/credentials.form.js:79 -msgid "Others (Cloud Providers)" -msgstr "Overigen (cloudproviders)" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:283 -msgid "" -"Override variables found in cloudforms.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view cloudforms.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variabelen overschrijven die zijn aangetroffen in cloudforms.ini en die gebruikt worden door het script van de inventarisupdate. Zie voor een voorbeeld van de configuratie van de variabele \n" -" \n" -" cloudfroms.ini in de Ansible github repo.Voer de variabelen van de inventaris in met JSON- of YAML-syntaxis. Gebruik de radio-knop om tussen de twee de wisselen. Raadpleeg de documentatie van Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:218 -msgid "" -"Override variables found in ec2.ini and used by the inventory update script." -" For a detailed description of these variables" -msgstr "" -"Variabelen overschrijven die aangetroffen zijn in ec2.ini en die gebruikt " -"worden door het script van de inventarisupdate. Voor een gedetailleerde " -"beschrijving van deze variabelen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:300 -msgid "" -"Override variables found in foreman.ini and used by the inventory update script. For an example variable configuration\n" -" \n" -" view foreman.ini in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variabelen overschrijven die aangetroffen zijn in foreman.ini en die gebruikt worden door het script van de inventarisupdate. Zie voor een voorbeeld van de configuratie van de variabelen\n" -" \n" -" foreman.ini in de Ansible github repo.Voer de variabelen van de inventaris in met JSON- of YAML-syntaxis. Gebruik de radioknop om tussen de twee te wisselen. Raadpleeg de documentatie van Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:266 -msgid "" -"Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration\n" -" \n" -" view openstack.yml in the Ansible github repo. Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax." -msgstr "" -"Variabelen overschrijven die aangetroffen zijn in openstack.yml en die gebruikt worden door het script van de inventarisupdate. Zie voor een voorbeeld van de configuratie van de variabelen\n" -" \n" -" openstack.yml in de Ansible github repo.Voer de variabelen van de inventaris in met JSON- of YAML-syntaxis. Gebruik de radioknop om tussen de twee te wisselen. Raadpleeg de documentatie van Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:242 -msgid "" -"Override variables found in vmware.ini and used by the inventory update " -"script. For a detailed description of these variables" -msgstr "" -"Variabelen overschrijven die aangetroffen zijn in vmware.ini en die gebruikt" -" worden in het script van de inventarisupdate. Voor een gedetailleerde " -"beschrijving van deze variabelen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:328 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:333 -msgid "Overwrite" -msgstr "Overschrijven" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:340 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:345 -msgid "Overwrite Variables" -msgstr "Variabelen overschrijven" - -#: client/src/credentials/credentials.list.js:40 -msgid "Owners" -msgstr "Eigenaren" - -#: client/src/login/loginModal/loginModal.partial.html:68 -msgid "PASSWORD" -msgstr "WACHTWOORD" - -#: client/features/credentials/legacy.credentials.js:122 -msgid "PERMISSIONS" -msgstr "MACHTIGINGEN" - -#: client/src/partials/job-template-details.html:2 -msgid "PLAYBOOK" -msgstr "DRAAIBOEK" - -#: client/src/partials/survey-maker-modal.html:45 -msgid "PLEASE ADD A SURVEY PROMPT." -msgstr "VOEG EEN MELDING VOOR DE VRAGENLIJST TOE." - -#: client/src/instance-groups/instances/instances-list.partial.html:6 -#: client/src/instance-groups/list/instance-groups-list.partial.html:16 -#: client/src/organizations/list/organizations-list.partial.html:47 -#: client/src/shared/form-generator.js:1885 -#: client/src/shared/list-generator/list-generator.factory.js:248 -msgid "PLEASE ADD ITEMS TO THIS LIST" -msgstr "VOEG ITEMS AAN DEZE LIJST TOE" - -#: client/src/main-menu/main-menu.partial.html:67 -msgid "PORTAL MODE" -msgstr "PORTAALMODUS" - -#: client/src/partials/survey-maker-modal.html:43 -msgid "PREVIEW" -msgstr "VOORVERTONING" - -#: client/src/job-results/job-results.service.js:166 -msgid "PROCEED" -msgstr "DOORGAAN" - -#: client/src/partials/job-template-details.html:2 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:73 -msgid "PROJECT" -msgstr "PROJECT" - -#: client/src/activity-stream/get-target-title.factory.js:8 -#: client/src/main-menu/main-menu.partial.html:19 -#: client/src/main-menu/main-menu.partial.html:95 -#: client/src/organizations/linkout/organizations-linkout.route.js:195 -#: client/src/organizations/list/organizations-list.controller.js:72 -#: client/src/projects/main.js:73 client/src/projects/projects.list.js:14 -#: client/src/projects/projects.list.js:15 -msgid "PROJECTS" -msgstr "PROJECTEN" - -#: client/src/shared/paginate/paginate.partial.html:33 -msgid "Page" -msgstr "Pagina" - -#: client/src/notifications/notificationTemplates.form.js:232 -msgid "Pagerduty subdomain" -msgstr "Subdomein Pagerduty" - -#: client/src/templates/job_templates/job-template.form.js:348 -msgid "" -"Pass extra command line variables to the playbook. Provide key/value pairs " -"using either YAML or JSON. Refer to the Ansible Tower documentation for " -"example syntax." -msgstr "" -"Geef extra commandoregelvariabelen op in het draaiboek. Geef sleutel/waarde-" -"paren op met YAML of JSON. Raadpleeg de documentatie van Ansible Tower voor " -"voorbeeldsyntaxis." - -#: client/src/templates/workflows.form.js:80 -msgid "" -"Pass extra command line variables to the playbook. This is the -e or " -"--extra-vars command line parameter for ansible-playbook. Provide key/value " -"pairs using either YAML or JSON. Refer to the Ansible Tower documentaton for" -" example syntax." -msgstr "" -"Geef extra commandoregelvariabelen op in het draaiboek. Dit is de " -"commandoregelparameter -e of --extra-vars voor het ansible-draaiboek. Geef " -"sleutel/waarde-paren op met YAML of JSON. Raadpleeg de documentatie van " -"Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:138 -msgid "" -"Pass extra command line variables. This is the %s or %s command line " -"parameter for %s. Provide key/value pairs using either YAML or JSON." -msgstr "" -"Geef extra commandoregelvariabelen op. Dit is de %s of %s " -"commandoregelparameter voor %s. Geef sleutel/waarde-paren op met YAML of " -"JSON." - -#: client/src/credentials/credentials.form.js:226 -#: client/src/credentials/factories/become-method-change.factory.js:21 -#: client/src/credentials/factories/become-method-change.factory.js:40 -#: client/src/credentials/factories/become-method-change.factory.js:48 -#: client/src/credentials/factories/become-method-change.factory.js:68 -#: client/src/credentials/factories/become-method-change.factory.js:78 -#: client/src/credentials/factories/become-method-change.factory.js:88 -#: client/src/credentials/factories/kind-change.factory.js:105 -#: client/src/credentials/factories/kind-change.factory.js:125 -#: client/src/credentials/factories/kind-change.factory.js:135 -#: client/src/credentials/factories/kind-change.factory.js:145 -#: client/src/credentials/factories/kind-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:78 -#: client/src/credentials/factories/kind-change.factory.js:97 -#: client/src/job-submission/job-submission.partial.html:104 -#: client/src/notifications/shared/type-change.service.js:28 -#: client/src/users/users.form.js:68 -msgid "Password" -msgstr "Wachtwoord" - -#: client/src/credentials/factories/kind-change.factory.js:58 -msgid "Password (API Key)" -msgstr "Wachtwoord (API-sleutel)" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:20 -msgid "Past 24 Hours" -msgstr "Afgelopen 24 uur" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:15 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:26 -msgid "Past Month" -msgstr "Afgelopen maand" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:23 -msgid "Past Week" -msgstr "Afgelopen week" - -#: client/src/credentials/factories/become-method-change.factory.js:29 -#: client/src/credentials/factories/kind-change.factory.js:86 -msgid "" -"Paste the contents of the PEM file associated with the service account " -"email." -msgstr "" -"Plak hier de inhoud van het PEM-bestand dat bij de e-mail van het " -"serviceaccount hoor." - -#: client/src/credentials/factories/kind-change.factory.js:51 -msgid "Paste the contents of the SSH private key file." -msgstr "Plak hier de inhoud van het SSH-privésleutelbestand." - -#: client/src/credentials/factories/kind-change.factory.js:26 -msgid "Paste the contents of the SSH private key file.%s or click to close%s" -msgstr "" -"Plak hier de inhoud van het SSH-privésleutelbestand.%s of klik om af te " -"sluiten%s" - -#: client/src/inventories-hosts/inventories/inventory.list.js:119 -msgid "Pending Delete" -msgstr "In afwachting om verwijderd te worden" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:8 -msgid "Period" -msgstr "Periode" - -#: client/src/projects/add/projects-add.controller.js:29 -#: client/src/users/add/users-add.controller.js:43 -msgid "Permission Error" -msgstr "Machtigingsfout" - -#: client/features/credentials/credentials.strings.js:14 -#: client/features/credentials/legacy.credentials.js:66 -#: client/src/credentials/credentials.form.js:439 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:122 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:123 -#: client/src/projects/projects.form.js:233 client/src/teams/teams.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:386 -#: client/src/templates/workflows.form.js:114 -#: client/src/users/users.form.js:187 -msgid "Permissions" -msgstr "Machtigingen" - -#: client/src/job-results/job-results.partial.html:249 -#: client/src/shared/form-generator.js:1069 -#: client/src/templates/job_templates/job-template.form.js:107 -#: client/src/templates/job_templates/job-template.form.js:115 -msgid "Playbook" -msgstr "Draaiboek" - -#: client/src/projects/projects.form.js:89 -msgid "Playbook Directory" -msgstr "Draaiboekmap" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:52 -msgid "Playbook Run" -msgstr "Draaiboek uitvoering" - -#: client/src/job-results/job-results.partial.html:488 -msgid "Plays" -msgstr "Uitvoeringen van het draaiboek" - -#: client/src/users/users.form.js:126 -msgid "Please add user to an Organization." -msgstr "Voeg gebruiker toe aan een organisatie" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:100 -msgid "Please assign roles to the selected resources" -msgstr "Wijs rollen toe aan de geselecteerde bronnen" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:60 -msgid "Please assign roles to the selected users/teams" -msgstr "Wijs rollen toe aan de geselecteerde gebruikers/teams" - -#: client/src/license/license.partial.html:84 -msgid "" -"Please click the button below to visit Ansible's website to get a Tower " -"license key." -msgstr "" -"Klik op onderstaande knop om de website van Ansible te bezoeken en een " -"licentiesleutel voor Tower te bemachtigen." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:27 -msgid "Please click the icon to edit the host filter." -msgstr "Klik op het icoon om de hostfilter te wijzigen." - -#: client/src/shared/form-generator.js:861 -#: client/src/shared/form-generator.js:956 -msgid "" -"Please enter a URL that begins with ssh, http or https. The URL may not " -"contain the '@' character." -msgstr "" -"Voer een URL in die begint met ssh, http of https. De URL mag niet het teken" -" '@' bevatten." - -#: client/src/shared/form-generator.js:1158 -msgid "Please enter a number greater than %d and less than %d." -msgstr "Voer een getal in dat groter is dan %d en kleiner dan %d." - -#: client/src/shared/form-generator.js:1160 -msgid "Please enter a number greater than %d." -msgstr "Voer een getal in dat groter is dan %d." - -#: client/src/shared/form-generator.js:1152 -msgid "Please enter a number." -msgstr "Voer een getal in." - -#: client/src/job-submission/job-submission.partial.html:112 -#: client/src/job-submission/job-submission.partial.html:126 -#: client/src/job-submission/job-submission.partial.html:140 -#: client/src/job-submission/job-submission.partial.html:154 -#: client/src/login/loginModal/loginModal.partial.html:78 -msgid "Please enter a password." -msgstr "Voer een wachtwoord in." - -#: client/src/login/loginModal/loginModal.partial.html:58 -msgid "Please enter a username." -msgstr "Voer een gebruikersnaam in." - -#: client/src/shared/form-generator.js:851 -#: client/src/shared/form-generator.js:946 -msgid "Please enter a valid email address." -msgstr "Voer een geldig e-mailadres in." - -#: client/lib/components/components.strings.js:15 -#: client/src/shared/form-generator.js:1016 -#: client/src/shared/form-generator.js:846 -#: client/src/shared/form-generator.js:941 -msgid "Please enter a value." -msgstr "Voer een waarde in." - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -#: client/src/job-submission/job-submission.partial.html:311 -#: client/src/job-submission/job-submission.partial.html:317 -msgid "Please enter an answer between" -msgstr "Voer een antwoord in tussen" - -#: client/src/job-submission/job-submission.partial.html:316 -msgid "Please enter an answer that is a decimal number." -msgstr "Voer een antwoord in dat een decimaal getal is." - -#: client/src/job-submission/job-submission.partial.html:310 -msgid "Please enter an answer that is a valid integer." -msgstr "Voer een antwoord in dat een geldig geheel getal is." - -#: client/src/job-submission/job-submission.partial.html:288 -#: client/src/job-submission/job-submission.partial.html:293 -#: client/src/job-submission/job-submission.partial.html:304 -#: client/src/job-submission/job-submission.partial.html:309 -#: client/src/job-submission/job-submission.partial.html:315 -msgid "Please enter an answer." -msgstr "Voer een antwoord in." - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:11 -#: client/src/templates/completed-jobs.list.js:11 -msgid "Please save and run a job to view." -msgstr "Sla op en voer een taak uit om te bekijken." - -#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:50 -msgid "Please save before adding a survey to this job template." -msgstr "Sla op voordat u een een vragenlijst toevoegt aan deze taaksjabloon." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:46 -msgid "Please save before adding a survey to this workflow." -msgstr "Sla op voordat u een vragenlijst toevoegt aan deze workflow." - -#: client/src/notifications/notifications.list.js:15 -msgid "Please save before adding notifications." -msgstr "Sla op voordat u berichten toevoegt." - -#: client/src/organizations/organizations.form.js:68 -#: client/src/teams/teams.form.js:69 -msgid "Please save before adding users." -msgstr "Sla op voordat u gebruikers toevoegt." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:118 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:119 -#: client/src/projects/projects.form.js:225 client/src/teams/teams.form.js:113 -#: client/src/templates/job_templates/job-template.form.js:379 -#: client/src/templates/workflows.form.js:107 -msgid "Please save before assigning permissions." -msgstr "Sla op voordat u machtigingen toekent." - -#: client/src/users/users.form.js:124 client/src/users/users.form.js:183 -msgid "Please save before assigning to organizations." -msgstr "Sla op voordat u toewijst aan organisaties." - -#: client/src/users/users.form.js:152 -msgid "Please save before assigning to teams." -msgstr "Sla op voordat u toewijst aan teams." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:164 -msgid "Please save before creating groups." -msgstr "Sla op voordat u groepen aanmaakt." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:173 -msgid "Please save before creating hosts." -msgstr "Sla op voordat u hosts aanmaakt." - -#: client/src/inventories-hosts/hosts/host.form.js:112 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:86 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:111 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:112 -msgid "Please save before defining groups." -msgstr "Sla op voordat u groepen bepaalt." - -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:94 -msgid "Please save before defining hosts." -msgstr "Sla op voordat u hosts bepaalt." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:182 -msgid "Please save before defining inventory sources." -msgstr "Sla op voordat u inventarisbronnen bepaalt." - -#: client/src/templates/workflows/add-workflow/workflow-add.controller.js:45 -msgid "Please save before defining the workflow graph." -msgstr "Sla op voordat u de workflowgrafiek bepaalt." - -#: client/src/inventories-hosts/hosts/host.form.js:121 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:120 -msgid "Please save before viewing Insights." -msgstr "Sla op voordat u Insights bekijkt." - -#: client/src/inventories-hosts/hosts/host.form.js:105 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:104 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:105 -msgid "Please save before viewing facts." -msgstr "Sla op voordat u feiten bekijkt." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:164 -msgid "Please save before viewing hosts." -msgstr "Sla op voordat u hosts bekijkt." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 -msgid "Please select Users / Teams from the lists below." -msgstr "Selecteer gebruikers/teams uit de onderstaande lijsten." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 -msgid "Please select Users from the list below." -msgstr "Selecteer gebruikers uit de onderstaande lijst." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:58 -msgid "Please select a Credential." -msgstr "Selecteer toegangsgegevens." - -#: client/src/templates/job_templates/multi-credential/multi-credential.partial.html:46 -msgid "" -"Please select a machine (SSH) credential or check the \"Prompt on launch\" " -"option." -msgstr "" -"Selecteer machine (SSH)-toegangsgegevens of vink de optie \"Melding bij " -"opstarten\" aan." - -#: client/src/shared/form-generator.js:1193 -msgid "Please select a number between" -msgstr "Selecteer een getal tussen" - -#: client/src/shared/form-generator.js:1189 -msgid "Please select a number." -msgstr "Selecteer een getal." - -#: client/src/shared/form-generator.js:1081 -#: client/src/shared/form-generator.js:1149 -#: client/src/shared/form-generator.js:1270 -#: client/src/shared/form-generator.js:1378 -msgid "Please select a value." -msgstr "Selecteer een waarde." - -#: client/src/templates/job_templates/job-template.form.js:77 -msgid "Please select an Inventory or check the Prompt on launch option." -msgstr "Selecteer een inventaris of vink de optie Melding bij opstarten aan." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:79 -msgid "Please select an Inventory." -msgstr "Selecteer een inventaris." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:26 -msgid "Please select an organization before editing the host filter." -msgstr "Selecteer een organisatie voordat u het hostfilter wijzigt." - -#: client/src/shared/form-generator.js:1186 -msgid "Please select at least one value." -msgstr "Selecteer ten minste één waarde." - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:30 -msgid "Please select resources from the lists below." -msgstr "Selecteer hulpbronnen uit de onderstaande lijsten." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "Populate the hosts for this inventory by using a search filter." -msgstr "Vul de hosts voor dit inventaris in door een zoekfilter te gebruiken." - -#: client/src/notifications/shared/type-change.service.js:27 -msgid "Port" -msgstr "Poort" - -#: client/src/credentials/credentials.form.js:257 -#: client/src/credentials/factories/kind-change.factory.js:21 -#: client/src/credentials/factories/kind-change.factory.js:45 -msgid "Private Key" -msgstr "Privésleutel" - -#: client/src/credentials/credentials.form.js:264 -#: client/src/job-submission/job-submission.partial.html:118 -msgid "Private Key Passphrase" -msgstr "Privésleutel wachtwoordzin" - -#: client/src/credentials/credentials.form.js:279 -#: client/src/credentials/credentials.form.js:283 -msgid "Privilege Escalation" -msgstr "Verhoging van rechten" - -#: client/src/credentials/credentials.form.js:305 -#: client/src/job-submission/job-submission.partial.html:132 -msgid "Privilege Escalation Password" -msgstr "Wachtwoord verhoging van rechten" - -#: client/src/credentials/credentials.form.js:295 -msgid "Privilege Escalation Username" -msgstr "Gebruikersnaam verhoging van rechten" - -#: client/src/credentials/factories/become-method-change.factory.js:30 -#: client/src/credentials/factories/kind-change.factory.js:87 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:93 -#: client/src/job-results/job-results.partial.html:216 -#: client/src/templates/job_templates/job-template.form.js:100 -#: client/src/templates/job_templates/job-template.form.js:91 -msgid "Project" -msgstr "Projecten" - -#: client/src/credentials/factories/become-method-change.factory.js:53 -#: client/src/credentials/factories/kind-change.factory.js:110 -msgid "Project (Tenant Name)" -msgstr "Projecten (naam huurder)" - -#: client/src/projects/projects.form.js:75 -#: client/src/projects/projects.form.js:83 -msgid "Project Base Path" -msgstr "Basispad project" - -#: client/src/credentials/credentials.form.js:365 -msgid "Project Name" -msgstr "Projectnaam" - -#: client/src/projects/projects.form.js:100 -msgid "Project Path" -msgstr "Projectpad" - -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:66 -msgid "Project Sync Failures" -msgstr "Mislukte projectsynchronisaties" - -#: client/src/projects/list/projects-list.controller.js:170 -msgid "Project lookup failed. GET returned:" -msgstr "Ophalen project mislukt. Geretourneerde OPHALEN:" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:115 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:47 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:31 -#: client/src/home/dashboard/counts/dashboard-counts.directive.js:61 -#: client/src/organizations/linkout/organizations-linkout.route.js:206 -msgid "Projects" -msgstr "Projecten" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:18 -msgid "Promote group" -msgid_plural "Promote groups" -msgstr[0] "Groep promoveren" -msgstr[1] "Groepen promoveren" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:43 -msgid "Promote groups" -msgstr "Groepen promoveren" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:32 -msgid "Promote groups and hosts" -msgstr "Groepen en hosts promoveren" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:20 -msgid "Promote host" -msgid_plural "Promote hosts" -msgstr[0] "Host promoveren" -msgstr[1] "Hosts promoveren" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:54 -msgid "Promote hosts" -msgstr "Hosts promoveren" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:10 -msgid "Promote {{ group }} and {{ host }}" -msgstr "{{ group }} en {{ host }} promoveren" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:27 -msgid "Prompt" -msgstr "Melding" - -#: client/lib/components/components.strings.js:30 -#: client/src/templates/job_templates/job-template.form.js:139 -#: client/src/templates/job_templates/job-template.form.js:169 -#: client/src/templates/job_templates/job-template.form.js:186 -#: client/src/templates/job_templates/job-template.form.js:212 -#: client/src/templates/job_templates/job-template.form.js:229 -#: client/src/templates/job_templates/job-template.form.js:254 -#: client/src/templates/job_templates/job-template.form.js:354 -#: client/src/templates/job_templates/job-template.form.js:60 -#: client/src/templates/job_templates/job-template.form.js:86 -msgid "Prompt on launch" -msgstr "Melding bij opstarten" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:132 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:147 -msgid "Provide a comma separated list of tags." -msgstr "Geef een lijst van tags gescheiden door komma's op." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:184 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:266 -msgid "Provide a comma-separated list of filter expressions." -msgstr "Voer een lijst van filteruitdrukkingen in, gescheiden door komma's." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:200 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:284 -msgid "" -"Provide a comma-separated list of filter expressions. Hosts are imported " -"when all of the filters match. Refer to Ansible Tower documentation for more" -" detail." -msgstr "" -"Voer een lijst van filteruitdrukkingen in, gescheiden door komma's. Hosts " -"worden geïmporteerd wanneer alle filters overeenkomen. Raadpleeg de " -"documentatie van Ansible Tower voor meer informatie." - -#: client/src/inventories-hosts/hosts/host.form.js:50 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:49 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:49 -msgid "Provide a host name, ip address, or ip address:port. Examples include:" -msgstr "Geef een hostnaam, IP-adres, of IP-adres:poort op. Voorbeelden:" - -#: client/src/templates/job_templates/job-template.form.js:163 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns are allowed. Refer to" -" Ansible documentation for more information and examples on patterns." -msgstr "" -"Geef een hostpatroon op om de lijst van hosts die beheerd of beïnvloed " -"worden door het draaiboek verder te beperken. Meerdere patronen zijn " -"toegestaan. Raadpleeg de documentatie van Ansible voor meer informatie over " -"en voorbeelden van patronen." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:116 -msgid "" -"Provide a host pattern to further constrain the list of hosts that will be " -"managed or affected by the playbook. Multiple patterns can be separated by " -"%s %s or %s" -msgstr "" -"Geef een hostpatroon op om de lijst van hosts die beheerd of beïnvloed " -"worden door het draaiboek verder te beperken. Meerdere patronen kunnen " -"gescheiden worden door %s %s of %s" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:196 -msgid "Provide environment variables to pass to the custom inventory script." -msgstr "" -"Geef omgevingsvariabelen op om door te geven aan het aangepaste " -"inventarisscript." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:203 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:287 -msgid "" -"Provide the named URL encoded name or id of the remote Tower inventory to be" -" imported." -msgstr "" -"Voer de URL, versleutelde naam of ID of de externe inventaris in die " -"geïmporteerd moet worden." - -#: client/src/templates/job_templates/job-template.form.js:311 -#: client/src/templates/job_templates/job-template.form.js:319 -msgid "Provisioning Callback URL" -msgstr "Provisioning terugkoppelings-URL" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Purple" -msgstr "Paars" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:14 -msgid "Queued. Click for details" -msgstr "In de wachtrij. Klik voor meer informatie" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:112 -msgid "RADIUS" -msgstr "RADIUS" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:4 -msgid "RECENT JOB RUNS" -msgstr "RECENTE TAAKUITVOERINGEN" - -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:40 -msgid "RECENTLY RUN JOBS" -msgstr "TAKEN DIE RECENT UITGEVOERD ZIJN" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:50 -msgid "RECENTLY USED JOB TEMPLATES" -msgstr "TAAKSJABLONEN DIE RECENT GEBRUIKT ZIJN" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:4 -msgid "RECENTLY USED TEMPLATES" -msgstr "SJABLONEN DIE RECENT GEBRUIKT ZIJN" - -#: client/src/activity-stream/streams.list.js:54 -#: client/src/inventories-hosts/hosts/host.list.js:102 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:46 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:113 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:47 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:54 -#: client/src/jobs/jobs.partial.html:15 -#: client/src/portal-mode/portal-mode-jobs.partial.html:20 -#: client/src/projects/projects.list.js:71 -#: client/src/scheduler/schedules.list.js:61 -msgid "REFRESH" -msgstr "VERNIEUWEN" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:109 -msgid "REGIONS" -msgstr "REGIO'S" - -#: client/src/shared/smart-search/smart-search.partial.html:48 -msgid "RELATED FIELDS:" -msgstr "VERWANTE VELDEN:" - -#: client/src/shared/directives.js:78 -msgid "REMOVE" -msgstr "VERWIJDEREN" - -#: client/lib/components/components.strings.js:7 -msgid "REPLACE" -msgstr "VERVANGEN" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:7 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:7 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:7 -msgid "RESULTS" -msgstr "RESULTATEN" - -#: client/lib/components/components.strings.js:8 -#: client/src/job-submission/job-submission.partial.html:44 -#: client/src/job-submission/job-submission.partial.html:87 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:52 -msgid "REVERT" -msgstr "TERUGZETTEN" - -#: client/src/credentials/factories/become-method-change.factory.js:25 -#: client/src/credentials/factories/kind-change.factory.js:82 -msgid "RSA Private Key" -msgstr "RSA-privésleutel" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.route.js:28 -msgid "RUN COMMAND" -msgstr "COMMANDO UITVOEREN" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:56 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:101 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:114 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:56 -msgid "RUN COMMANDS" -msgstr "COMMANDO'S UITVOEREN" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Random" -msgstr "Willekeurig" - -#: client/src/job-results/job-results.partial.html:411 -msgid "Read only view of extra variables added to the job template." -msgstr "" -"Alleen-lezen-beeld van extra variabelen toegevoegd aan het taaksjabloon." - -#: client/src/workflow-results/workflow-results.partial.html:155 -msgid "Read only view of extra variables added to the workflow." -msgstr "Alleen-lezen-beeld van extra variabelen toegevoegd aan de workflow." - -#: client/src/notifications/notificationTemplates.list.js:26 -msgid "Recent Notifications" -msgstr "Recente berichten" - -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:98 -msgid "Recipient List" -msgstr "Lijst van ontvangers" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Red" -msgstr "Rood" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:65 -msgid "" -"Refer to the Ansible Tower documentation for further syntax and examples." -msgstr "" -"Raadpleeg de documentatie van Ansible Tower voor meer syntaxis en " -"voorbeelden." - -#: client/src/activity-stream/streams.list.js:51 -#: client/src/bread-crumb/bread-crumb.partial.html:6 -#: client/src/inventories-hosts/hosts/host.list.js:98 -#: client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js:42 -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:109 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:43 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:50 -#: client/src/projects/projects.list.js:67 -#: client/src/scheduler/schedules.list.js:57 -msgid "Refresh the page" -msgstr "Pagina vernieuwen" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:177 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:258 -msgid "Region:" -msgstr "Regio:" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:131 -msgid "Regions" -msgstr "Regio's" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:65 -msgid "Related Groups" -msgstr "Gerelateerde groepen" - -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:77 -#: client/src/job-results/job-results.partial.html:29 -#: client/src/jobs/all-jobs.list.js:99 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:11 -#: client/src/templates/completed-jobs.list.js:78 -#: client/src/workflow-results/workflow-results.partial.html:29 -msgid "Relaunch using the same parameters" -msgstr "Opnieuw opstarten met dezelfde parameters" - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:194 -msgid "Remediate Inventory" -msgstr "Inventaris herstellen" - -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:96 -#: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:97 -#: client/src/teams/teams.form.js:142 client/src/users/users.form.js:222 -msgid "Remove" -msgstr "Verwijderen" - -#: client/src/projects/projects.form.js:158 -msgid "Remove any local modifications prior to performing an update." -msgstr "" -"Verwijder alle plaatselijke aanpassingen voordat een update uitgevoerd " -"wordt." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:149 -msgid "Repeat frequency" -msgstr "Frequentie herhalen" - -#: client/src/license/license.partial.html:89 -msgid "Request License" -msgstr "Licentie opvragen" - -#: client/src/templates/survey-maker/shared/question-definition.form.js:291 -msgid "Required" -msgstr "Vereist" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:153 -msgid "Reset" -msgstr "Resetten" - -#: client/src/job-results/job-results.partial.html:123 -msgid "Results Traceback" -msgstr "Resultaten-traceback" - -#: client/src/shared/form-generator.js:690 -msgid "Revert" -msgstr "Terugzetten" - -#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:51 -#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:47 -#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:59 -#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:95 -#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:34 -#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:87 -#: client/src/configuration/auth-form/sub-forms/auth-tacacs.form.js:47 -#: client/src/configuration/jobs-form/configuration-jobs.form.js:73 -#: client/src/configuration/system-form/sub-forms/system-activity-stream.form.js:26 -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:74 -#: client/src/configuration/system-form/sub-forms/system-misc.form.js:50 -#: client/src/configuration/ui-form/configuration-ui.form.js:36 -msgid "Revert all to default" -msgstr "Alles terugzetten naar standaardinstellingen" - -#: client/src/job-results/job-results.partial.html:239 -#: client/src/projects/projects.list.js:50 -msgid "Revision" -msgstr "Herziening" - -#: client/src/projects/add/projects-add.controller.js:146 -#: client/src/projects/edit/projects-edit.controller.js:281 -msgid "Revision #" -msgstr "Herziening #" - -#: client/features/credentials/legacy.credentials.js:88 -#: client/src/credentials/credentials.form.js:461 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:148 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:149 -#: client/src/organizations/organizations.form.js:97 -#: client/src/projects/projects.form.js:255 client/src/teams/teams.form.js:135 -#: client/src/teams/teams.form.js:98 -#: client/src/templates/workflows.form.js:138 -#: client/src/users/users.form.js:205 -msgid "Role" -msgstr "Rol" - -#: client/src/instance-groups/instance-group.partial.html:14 -#: client/src/instance-groups/instance-groups.list.js:26 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:14 -#: client/src/instance-groups/instances/instances-list.partial.html:18 -#: client/src/instance-groups/instances/instances.list.js:24 -#: client/src/instance-groups/list/instance-groups-list.partial.html:29 -msgid "Running Jobs" -msgstr "Taken in uitvoering" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:18 -msgid "Running! Click for details" -msgstr "In uitvoering! Klik voor meer informatie" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:113 -msgid "SAML" -msgstr "SAML" - -#: client/lib/services/base-string.service.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal.partial.html:17 -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:17 -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:17 -#: client/src/partials/survey-maker-modal.html:87 -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:18 -msgid "SAVE" -msgstr "OPSLAAN" - -#: client/src/scheduler/main.js:331 -msgid "SCHEDULED" -msgstr "GEPLAND" - -#: client/src/scheduler/scheduled-jobs.list.js:13 -msgid "SCHEDULED JOBS" -msgstr "GEPLANDE TAKEN" - -#: client/src/activity-stream/get-target-title.factory.js:38 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:49 -#: client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js:8 -#: client/src/management-jobs/scheduler/main.js:26 -#: client/src/management-jobs/scheduler/main.js:32 -#: client/src/scheduler/main.js:145 client/src/scheduler/main.js:183 -#: client/src/scheduler/main.js:235 client/src/scheduler/main.js:273 -#: client/src/scheduler/main.js:52 client/src/scheduler/main.js:90 -msgid "SCHEDULES" -msgstr "SCHEMA'S" - -#: client/src/projects/add/projects-add.controller.js:118 -#: client/src/projects/edit/projects-edit.controller.js:254 -msgid "SCM Branch" -msgstr "SCM-vertakking" - -#: client/src/projects/add/projects-add.controller.js:137 -#: client/src/projects/edit/projects-edit.controller.js:272 -msgid "SCM Branch/Tag/Commit" -msgstr "SCM-vertakking/tag/binding" - -#: client/src/projects/add/projects-add.controller.js:158 -#: client/src/projects/edit/projects-edit.controller.js:293 -msgid "SCM Branch/Tag/Revision" -msgstr "SCM-vertakking/tag/herziening" - -#: client/src/projects/projects.form.js:159 -msgid "SCM Clean" -msgstr "SCM-zuiveren" - -#: client/src/projects/projects.form.js:170 -msgid "SCM Delete" -msgstr "SCM-verwijderen" - -#: client/src/credentials/factories/become-method-change.factory.js:20 -#: client/src/credentials/factories/kind-change.factory.js:77 -msgid "SCM Private Key" -msgstr "SCM-privésleutel" - -#: client/src/projects/projects.form.js:55 -msgid "SCM Type" -msgstr "SCM-soort" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:49 -#: client/src/projects/projects.form.js:180 -msgid "SCM Update" -msgstr "SCM-update" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "SCM Update Cancel" -msgstr "SCM-updatekanaal" - -#: client/src/projects/projects.form.js:150 -msgid "SCM Update Options" -msgstr "SCM-update-opties" - -#: client/src/projects/edit/projects-edit.controller.js:137 -#: client/src/projects/list/projects-list.controller.js:84 -msgid "SCM update currently running" -msgstr "SCM-update nu in uitvoering" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc-credential.route.js:35 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:70 -msgid "SELECT" -msgstr "SELECTEREN" - -#: client/features/credentials/credentials.strings.js:20 -msgid "SELECT A CREDENTIAL TYPE" -msgstr "SELECTEER EEN SOORT TOEGANGSGEGEVENS" - -#: client/features/credentials/credentials.strings.js:19 -msgid "SELECT AN ORGANIZATION" -msgstr "SELECTEER EEN ORGANISATIE" - -#: client/src/inventories-hosts/shared/associate-groups/associate-groups.partial.html:6 -msgid "SELECT GROUPS" -msgstr "SELECTEER GROEPEN" - -#: client/src/inventories-hosts/shared/associate-hosts/associate-hosts.partial.html:6 -msgid "SELECT HOSTS" -msgstr "SELECTEER HOSTS" - -#: client/src/job-submission/job-submission.partial.html:29 -#: client/src/job-submission/job-submission.partial.html:56 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html:20 -msgid "SELECTED:" -msgstr "GESELECTEERD:" - -#: client/src/main-menu/main-menu.partial.html:59 -#: client/src/setup-menu/setup.route.js:9 -msgid "SETTINGS" -msgstr "INSTELLINGEN" - -#: client/lib/components/components.strings.js:11 -msgid "SHOW" -msgstr "TONEN" - -#: client/src/login/loginModal/loginModal.partial.html:97 -msgid "SIGN IN" -msgstr "AANMELDEN" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.partial.html:2 -msgid "SIGN IN WITH" -msgstr "AANMELDEN MET" - -#: client/src/inventories-hosts/hosts/host.list.js:110 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:32 -msgid "SMART INVENTORY" -msgstr "SMART-INVENTARIS" - -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:102 -msgid "SOURCE" -msgstr "BRON" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.route.js:26 -msgid "SOURCES" -msgstr "BRONNEN" - -#: client/src/credentials/factories/become-method-change.factory.js:89 -#: client/src/credentials/factories/kind-change.factory.js:146 -msgid "SSH Key" -msgstr "SSH-sleutel" - -#: client/src/credentials/credentials.form.js:255 -msgid "SSH key description" -msgstr "Beschrijving SSH-sleutel" - -#: client/src/notifications/notificationTemplates.form.js:375 -msgid "SSL Connection" -msgstr "SSL-verbinding" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:128 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:135 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:96 -msgid "STANDARD OUT" -msgstr "STANDAARDOUTPUT" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:32 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:65 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:45 -msgid "STARTED" -msgstr "BEGONNEN" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:24 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:37 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:37 -msgid "STATUS" -msgstr "STATUS" - -#: client/src/credentials/credentials.form.js:119 -#: client/src/credentials/credentials.form.js:127 -msgid "STS Token" -msgstr "STS-token" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:61 -msgid "SUCCESSFUL" -msgstr "GESLAAGD" - -#: client/src/partials/survey-maker-modal.html:24 -msgid "SURVEY" -msgstr "VRAGENLIJST" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:62 -msgid "SYNC ALL" -msgstr "ALLES SYNCHRONISEREN" - -#: client/src/system-tracking/system-tracking.route.js:18 -msgid "SYSTEM TRACKING" -msgstr "SYSTEEMTRACKING" - -#: client/src/credentials/factories/become-method-change.factory.js:70 -#: client/src/credentials/factories/kind-change.factory.js:127 -msgid "Satellite 6 URL" -msgstr "Satellite 6-URL" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:110 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:193 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:157 -#: client/src/shared/form-generator.js:1691 -msgid "Save" -msgstr "Opslaan" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:86 -#: client/src/configuration/configuration.controller.js:213 -#: client/src/configuration/configuration.controller.js:272 -#: client/src/configuration/system-form/configuration-system.controller.js:68 -msgid "Save changes" -msgstr "Wijzigingen opslaan" - -#: client/src/license/license.partial.html:127 -msgid "Save successful!" -msgstr "Opslaan gelukt!" - -#: client/src/templates/templates.list.js:88 -msgid "Schedule" -msgstr "Schema" - -#: client/src/management-jobs/card/card.partial.html:28 -msgid "Schedule Management Job" -msgstr "Schema beheertaak" - -#: client/src/projects/list/projects-list.controller.js:75 -msgid "Schedule future SCM updates" -msgstr "Toekomstige SCM-updates inplannen" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:7 -msgid "Schedule future inventory syncs" -msgstr "Toekomstige inventarissynchronisaties inplannen" - -#: client/src/templates/templates.list.js:91 -msgid "Schedule future job template runs" -msgstr "Toekomstige uitvoeringen van het taaksjabloon inplannen" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:33 -#: client/src/jobs/jobs.partial.html:10 -msgid "Schedules" -msgstr "Schema's" - -#: client/src/shared/smart-search/smart-search.controller.js:49 -#: client/src/shared/smart-search/smart-search.controller.js:94 -msgid "Search" -msgstr "Zoeken" - -#: client/src/credentials/credentials.form.js:104 -msgid "Secret Key" -msgstr "Geheime sleutel" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:178 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:259 -msgid "Security Group:" -msgstr "Veiligheidsgroep:" - -#: client/src/credentials/credentials.form.js:124 -msgid "" -"Security Token Service (STS) is a web service that enables you to request " -"temporary, limited-privilege credentials for AWS Identity and Access " -"Management (IAM) users." -msgstr "" -"Security Token Service (STS) is een webdienst waarmee u tijdelijke " -"toegangsgegevens met beperkte rechten aan kunt vragen voor gebruikers van " -"AWS Identity en Access Management (IAM)" - -#: client/src/shared/form-generator.js:1695 -msgid "Select" -msgstr "Selecteren" - -#: client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.partial.html:5 -msgid "Select Instance Groups" -msgstr "Instantiegroepen selecteren" - -#: client/src/job-submission/job-submission.directive.js:64 -#: client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js:46 -msgid "Select a credential" -msgstr "Toegangsgegevens selecteren" - -#: client/src/access/add-rbac-user-team/rbac-user-team.controller.js:68 -msgid "Select a role" -msgstr "Rol selecteren" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or a selection of multiple groups." -msgstr "" -"Selecteer een inventarisbron door het selectievak ernaast aan te klikken. De" -" inventarisbron kan een enkele groep of een selectie van meerdere groepen " -"zijn." - -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:53 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:98 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:53 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single group or host, a selection of multiple " -"hosts, or a selection of multiple groups." -msgstr "" -"Selecteer een inventarisbron door het selectievak ernaast aan te klikken. De" -" inventarisbron kan een enkele groep of host, een selectie van meerdere " -"hosts of een selectie van meerdere groepen zijn." - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:111 -msgid "" -"Select an inventory source by clicking the check box beside it. The " -"inventory source can be a single host or a selection of multiple hosts." -msgstr "" -"Selecteer een inventarisbron door het selectievak ernaast aan te klikken. De" -" inventarisbron kan een enkele host of een selectie van meerdere hosts zijn." - -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:109 -#: client/src/configuration/jobs-form/configuration-jobs.controller.js:134 -#: client/src/configuration/ui-form/configuration-ui.controller.js:95 -msgid "Select commands" -msgstr "Commando's selecteren" - -#: client/src/templates/job_templates/job-template.form.js:133 -msgid "" -"Select credentials that allow Tower to access the nodes this job will be ran" -" against. You can only select one credential of each type. For machine " -"credentials (SSH), checking \"Prompt on launch\" without selecting " -"credentials will require you to select a machine credential at run time. If " -"you select credentials and check \"Prompt on launch\", the selected " -"credential(s) become the defaults that can be updated at run time." -msgstr "" -"Selecteer toegangsgegevens waarmee Tower toegang kan krijgen tot de " -"knooppunten waartegen deze taak uitgevoerd zal worden. U kunt slechts één " -"set toegangsgegevens van iedere soort kiezen. In het geval van machine-" -"toegangsgegevens (SSH) moet u, als u 'melding bij opstarten' aanvinkt zonder" -" toegangsgegevens te kiezen, bij het opstarten de machinetoegangsgegevens " -"kiezen. Als u toegangsgegevens selecteert en 'melding bij opstarten' " -"aanvinkt, worden de geselecteerde toegangsgegevens de " -"standaardtoegangsgegevens en kunnen deze bij het opstarten gewijzigd worden." - -#: client/src/projects/projects.form.js:98 -msgid "" -"Select from the list of directories found in the Project Base Path. Together" -" the base path and the playbook directory provide the full path used to " -"locate playbooks." -msgstr "" -"Kies uit de lijst mappen die in het basispad van het project gevonden zijn. " -"Het basispad en de map van het draaiboek vormen samen het volledige pad dat " -"gebruikt wordt op draaiboeken te vinden." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:263 -#: client/src/configuration/auth-form/configuration-auth.controller.js:282 -msgid "Select group types" -msgstr "Selecteer soorten groepen" - -#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:24 -msgid "Select roles" -msgstr "Selecteer rollen" - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:74 -msgid "Select the Instance Groups for this Inventory to run on." -msgstr "" -"Selecteer de instantiegroepen waar deze inventaris op uitgevoerd wordt." - -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:80 -msgid "" -"Select the Instance Groups for this Inventory to run on. Refer to the " -"Ansible Tower documentation for more detail." -msgstr "" -"Selecteer de instantiegroepen waar deze inventaris op uitgevoerd wordt. " -"Raadpleeg de documentatie van Ansible Tower voor meer informatie." - -#: client/src/templates/job_templates/job-template.form.js:193 -msgid "Select the Instance Groups for this Job Template to run on." -msgstr "" -"Selecteer de instantiegroepen waar deze taaksjabloon op uitgevoerd wordt." - -#: client/src/organizations/organizations.form.js:40 -msgid "Select the Instance Groups for this Organization to run on." -msgstr "" -"Selecteer de instantiegroepen waar de organisatie op uitgevoerd wordt." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:60 -msgid "" -"Select the credential you want the job to use when accessing the remote " -"hosts. Choose the credential containing the username and SSH key or " -"password that Ansible will need to log into the remote hosts." -msgstr "" -"Selecteer de toegangsgegevens waarvan u wilt dat de taak ze gebruikt bij het" -" aanspreken van hosts op afstand. Kies de toegangsgegevens die de " -"gebruikersnaam en de SSH-sleutel of het wachtwoord bevatten die Ansible " -"nodig heeft om aan te melden bij de hosts of afstand." - -#: client/src/templates/job_templates/job-template.form.js:79 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:81 -msgid "Select the inventory containing the hosts you want this job to manage." -msgstr "" -"Selecteer de inventaris met de hosts waarvan u wilt dat deze taak ze " -"beheert." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:122 -msgid "" -"Select the inventory file to be synced by this source. You can select from " -"the dropdown or enter a file within the input." -msgstr "" -"Selecteer het inventarisbestand dat gesynchroniseerd moet worden door deze " -"bron. U kunt kiezen uit het uitklapbare menu of een bestand invoeren in het " -"invoerveld." - -#: client/src/templates/job_templates/job-template.form.js:114 -msgid "Select the playbook to be executed by this job." -msgstr "Selecteer het draaiboek dat uitgevoerd moet worden door deze taak." - -#: client/src/templates/job_templates/job-template.form.js:99 -msgid "" -"Select the project containing the playbook you want this job to execute." -msgstr "" -"Selecteer het project dat het draaiboek bevat waarvan u wilt dat deze taak " -"hem uitvoert." - -#: client/src/configuration/system-form/configuration-system.controller.js:197 -msgid "Select types" -msgstr "Selecteer soorten" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:170 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:251 -msgid "Select which groups to create automatically." -msgstr "Selecteer welke groepen automatisch aangemaakt moeten worden." - -#: client/src/notifications/notificationTemplates.form.js:110 -msgid "Sender Email" -msgstr "Afzender e-mail" - -#: client/src/credentials/factories/become-method-change.factory.js:24 -#: client/src/credentials/factories/kind-change.factory.js:81 -msgid "Service Account Email Address" -msgstr "E-mailadres service-account" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:101 -msgid "" -"Setting the type to %s will execute the playbook and store any scanned " -"facts for use with 's System Tracking feature." -msgstr "" -"Als %s ingesteld wordt als de soort, wordt het draaiboek uitgevoerd en " -"worden gescande feiten opgeslagen voor gebruik met de systeemtrackingfunctie" -" van ." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:99 -msgid "" -"Setting the type to %s will not execute the playbook. Instead, %s will check" -" playbook syntax, test environment setup and report problems." -msgstr "" -"Als %s ingesteld wordt als de soort, wordt het draaiboek niet uitgevoerd. In" -" plaats daarvan zal %s de syntaxis van het draaiboek controleren, de " -"installatie van de omgeving testen en problemen rapporteren." - -#: client/src/main-menu/main-menu.partial.html:147 -msgid "Settings" -msgstr "Instellingen" - -#: client/src/job-submission/job-submission.partial.html:108 -#: client/src/job-submission/job-submission.partial.html:122 -#: client/src/job-submission/job-submission.partial.html:136 -#: client/src/job-submission/job-submission.partial.html:150 -#: client/src/job-submission/job-submission.partial.html:299 -#: client/src/shared/form-generator.js:876 -msgid "Show" -msgstr "Tonen" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:114 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:117 -#: client/src/templates/job_templates/job-template.form.js:245 -#: client/src/templates/job_templates/job-template.form.js:248 -msgid "Show Changes" -msgstr "Wijzigingen tonen" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:33 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:44 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:55 -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:76 -msgid "Sign in with %s" -msgstr "Aanmelden met %s" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:63 -msgid "Sign in with %s Organizations" -msgstr "Aanmelden met %s organisaties" - -#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:61 -msgid "Sign in with %s Teams" -msgstr "Aanmelden met %s teams" - -#: client/src/job-results/job-results.partial.html:395 -#: client/src/job-submission/job-submission.partial.html:245 -#: client/src/templates/job_templates/job-template.form.js:217 -#: client/src/templates/job_templates/job-template.form.js:224 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:142 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:150 -msgid "Skip Tags" -msgstr "Tags overslaan" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:148 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task." -msgstr "" -"Tags overslaan is nuttig wanneer u een groot draaiboek heeft en specifieke " -"delen van het draaiboek of een taak wilt overslaan." - -#: client/src/templates/job_templates/job-template.form.js:223 -msgid "" -"Skip tags are useful when you have a large playbook, and you want to skip " -"specific parts of a play or task. Use commas to separate multiple tags. " -"Refer to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"Tags overslaan is nuttig wanneer u een groot draaiboek heeft en specifieke " -"delen van het draaiboek of een taak wilt overslaan. Gebruik een komma om " -"meerdere tags van elkaar te scheiden. Raadpleeg de documentatie van Ansible " -"Tower voor meer informatie over het gebruik van tags." - -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:62 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:66 -msgid "Smart Host Filter" -msgstr "Smart-hostfilter" - -#: client/src/inventories-hosts/inventories/inventory.list.js:85 -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:69 -#: client/src/organizations/linkout/controllers/organizations-inventories.controller.js:70 -#: client/src/shared/form-generator.js:1456 -msgid "Smart Inventory" -msgstr "Smart-inventaris" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:44 -msgid "Solvable With Playbook" -msgstr "Op te lossen met draaiboek" - -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:57 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:64 -msgid "Source" -msgstr "Bron" - -#: client/src/credentials/credentials.form.js:75 -msgid "Source Control" -msgstr "Broncontrole" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:47 -#: client/src/projects/projects.form.js:25 -msgid "Source Details" -msgstr "Broninformatie" - -#: client/src/notifications/notificationTemplates.form.js:192 -#: client/src/notifications/notificationTemplates.form.js:193 -msgid "Source Phone Number" -msgstr "Brontelefoonnummer" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:136 -msgid "Source Regions" -msgstr "Bronregio's" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:209 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:216 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:233 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:240 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:257 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:264 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:274 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:281 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:291 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:298 -msgid "Source Variables" -msgstr "Bronvariabelen" - -#: client/src/partials/logviewer.html:9 -msgid "Source Vars" -msgstr "Bronvariabelen" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:34 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:184 -msgid "Sources" -msgstr "Bronnen" - -#: client/src/notifications/notificationTemplates.form.js:330 -msgid "" -"Specify HTTP Headers in JSON format. Refer to the Ansible Tower " -"documentation for example syntax." -msgstr "" -"Specificeer HTTP-koppen in JSON-formaat. Raadpleeg de documentatie van " -"Ansible Tower voor voorbeeldsyntaxis." - -#: client/src/credentials/credentials.form.js:285 -msgid "" -"Specify a method for %s operations. This is equivalent to specifying the %s " -"parameter, where %s could be %s" -msgstr "" -"Specificeer een methode voor %s-operaties. Dit staat gelijk aan het " -"specificeren van de %s-parameter, waar %s %s kan zijn" - -#: client/src/notifications/notificationTemplates.form.js:292 -msgid "" -"Specify a notification color. Acceptable colors are: yellow, green, red " -"purple, gray or random." -msgstr "" -"Kies een berichtkleur. Mogelijke kleuren zijn: geel, groen, rood, paars, " -"grijs of willekeurig." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:199 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:283 -msgid "" -"Specify which groups to create automatically. Group names will be created " -"similar to the options selected. If blank, all groups above are created. " -"Refer to Ansible Tower documentation for more detail." -msgstr "" -"Specificeer welke groepen automatisch aangemaakt moeten worden. De namen van" -" de groepen zullen vergelijkbaar zijn met de geselecteerde opties. Indien " -"dit leeg gelaten wordt, zullen alle bovenstaande groepen aangemaakt worden. " -"Raadpleeg de documentatie van Ansible Tower voor meer informatie." - -#: client/src/setup-menu/setup-menu.partial.html:17 -msgid "" -"Split up your organization to associate content and control permissions for " -"groups." -msgstr "" -"Verdeel uw organisatie om content te verbinden en machtigingen te beheren " -"voor groepen." - -#: client/src/partials/logviewer.html:5 -msgid "Standard Out" -msgstr "Standaardoutput" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:41 -msgid "Start Date" -msgstr "Startdatum" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:56 -msgid "Start Time" -msgstr "Starttijd" - -#: client/src/portal-mode/portal-job-templates.list.js:39 -#: client/src/templates/templates.list.js:83 -msgid "Start a job using this template" -msgstr "Start een taak met deze sjabloon" - -#: client/src/projects/edit/projects-edit.controller.js:134 -#: client/src/projects/list/projects-list.controller.js:74 -msgid "Start an SCM update" -msgstr "Start een SCM-update" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:6 -msgid "Start sync process" -msgstr "Start het synchronisatieproces" - -#: client/src/job-results/job-results.partial.html:100 -msgid "Started" -msgstr "Gestart" - -#: client/src/inventories-hosts/inventories/list/host-summary-popover/host-summary-popover.directive.js:53 -#: client/src/inventories-hosts/inventories/list/source-summary-popover/source-summary-popover.directive.js:55 -#: client/src/inventories-hosts/shared/factories/set-status.factory.js:43 -#: client/src/job-results/job-results.partial.html:67 -#: client/src/job-results/parse-stdout.service.js:68 -#: client/src/notifications/notification-templates-list/list.controller.js:71 -#: client/src/partials/logviewer.html:4 -msgid "Status" -msgstr "Status" - -#: client/src/configuration/auth-form/configuration-auth.partial.html:3 -msgid "Sub Category" -msgstr "Subcategorie" - -#: client/src/license/license.partial.html:126 -msgid "Submit" -msgstr "Indienen" - -#: client/src/jobs/factories/delete-job.factory.js:109 -msgid "Submit the request to cancel?" -msgstr "Verzoek om te annuleren indienen?" - -#: client/src/license/license.partial.html:27 -msgid "Subscription" -msgstr "Abonnement" - -#: client/src/credentials/credentials.form.js:151 -#: client/src/credentials/credentials.form.js:162 -msgid "Subscription ID" -msgstr "Abonnement-ID" - -#: client/src/credentials/credentials.form.js:161 -msgid "Subscription ID is an Azure construct, which is mapped to a username." -msgstr "" -"Abonnement-ID is een concept van Azure en is gelinkt aan een gebruikersnaam." - -#: client/src/notifications/notifications.list.js:38 -msgid "Success" -msgstr "Geslaagd" - -#: client/src/projects/factories/get-project-tool-tip.factory.js:21 -msgid "Success! Click for details" -msgstr "Geslaagd! Klik voor meer informatie" - -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:77 -msgid "Successful" -msgstr "Geslaagd" - -#: client/src/job-submission/job-submission.partial.html:20 -msgid "Survey" -msgstr "Vragenlijst" - -#: client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js:60 -#: client/src/templates/workflows/edit-workflow/workflow-edit.controller.js:64 -msgid "" -"Surveys allow users to be prompted at job launch with a series of questions " -"related to the job. This allows for variables to be defined that affect the " -"playbook run at time of launch." -msgstr "" -"Met vragenlijsten kunnen gebruikers bij het starten van een taak een melding" -" krijgen met een lijst vragen die bij de taak horen. Zo kunnen variabelen " -"die van invloed zijn op de uitvoering van het draaiboek bepaald worden bij " -"het opstarten." - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:58 -msgid "Sync all inventory sources" -msgstr "Alle inventarisbronnen synchroniseren" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:29 -msgid "Sync canceled. Click to view log." -msgstr "Synchronisatie geannuleerd. Klik om logboek te bekijken." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:35 -msgid "Sync completed. Click to view log." -msgstr "Synchronisatie voltooid. Klik om logboek te bekijken." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:32 -msgid "Sync failed. Click to view log." -msgstr "Synchronisatie mislukt. Klik om logboek te bekijken." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "Sync not performed. Click" -msgstr "Synchronisatie niet uitgevoerd. Klik" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:38 -msgid "Sync pending." -msgstr "Synchronisatie in afwachting." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:45 -msgid "Sync running" -msgstr "Synchronisatie in uitvoering" - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:46 -msgid "Sync running. Click to view log." -msgstr "Synchronisatie in uitvoering. Klik om logboek te bekijken." - -#: client/src/configuration/configuration.partial.html:17 -msgid "System" -msgstr "Systeem" - -#: client/src/users/add/users-add.controller.js:12 -#: client/src/users/edit/users-edit.controller.js:12 -#: client/src/users/list/users-list.controller.js:12 -msgid "System Administrator" -msgstr "Systeembeheerder" - -#: client/src/users/add/users-add.controller.js:11 -#: client/src/users/edit/users-edit.controller.js:11 -#: client/src/users/list/users-list.controller.js:11 -msgid "System Auditor" -msgstr "Systeemcontroleur" - -#: client/src/configuration/configuration.partial.html:3 -msgid "System auditors have read-only permissions in this section." -msgstr "Systeemcontroleurs hebben een alleen-lezen-machtiging in deze sectie." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:114 -msgid "TACACS+" -msgstr "TACACS+" - -#: client/src/activity-stream/get-target-title.factory.js:23 -#: client/src/organizations/linkout/organizations-linkout.route.js:97 -#: client/src/organizations/list/organizations-list.controller.js:60 -#: client/src/teams/main.js:46 client/src/teams/teams.list.js:14 -#: client/src/teams/teams.list.js:15 -msgid "TEAMS" -msgstr "TEAMS" - -#: client/src/activity-stream/get-target-title.factory.js:44 -#: client/src/main-menu/main-menu.partial.html:113 -#: client/src/main-menu/main-menu.partial.html:35 -#: client/src/templates/list/templates-list.route.js:13 -#: client/src/templates/templates.list.js:15 -#: client/src/templates/templates.list.js:16 -msgid "TEMPLATES" -msgstr "SJABLONEN" - -#: client/src/instance-groups/instance-groups.list.js:8 -msgid "THERE ARE CURRENTLY NO INSTANCE GROUPS DEFINED" -msgstr "ER ZIJN OP DIT MOMENT GEEN INSTANTIEGROEPEN GEDEFINIEERD" - -#: client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js:104 -msgid "TIME" -msgstr "TIJD" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:61 -msgid "TOP" -msgstr "OMHOOG" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:181 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:262 -msgid "Tag None:" -msgstr "Tag geen:" - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:133 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task." -msgstr "" -"Tags zijn nuttig als u een groot draaiboek heeft en een specifiek deel van " -"het draaiboek of van een taak uit wilt voeren." - -#: client/src/templates/job_templates/job-template.form.js:206 -msgid "" -"Tags are useful when you have a large playbook, and you want to run a " -"specific part of a play or task. Use commas to separate multiple tags. Refer" -" to Ansible Tower documentation for details on the usage of tags." -msgstr "" -"Tags zijn nuttig wanneer u een groot draaiboek heeft en specifieke delen van" -" het draaiboek of een taak wilt uitvoeren. Gebruik een komma om meerdere " -"tags van elkaar te scheiden. Raadpleeg de documentatie van Ansible Tower " -"voor meer informatie over het gebruik van tags." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:179 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:260 -msgid "Tags:" -msgstr "Tags:" - -#: client/src/notifications/notificationTemplates.form.js:309 -msgid "Target URL" -msgstr "Doel-URL" - -#: client/src/job-results/job-results.partial.html:496 -msgid "Tasks" -msgstr "Taken" - -#: client/features/credentials/legacy.credentials.js:94 -#: client/src/credentials/credentials.form.js:467 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:154 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:155 -#: client/src/projects/projects.form.js:261 -#: client/src/templates/workflows.form.js:144 -msgid "Team Roles" -msgstr "Teamrollen" - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:34 -#: client/src/organizations/linkout/organizations-linkout.route.js:108 -#: client/src/setup-menu/setup-menu.partial.html:16 -#: client/src/shared/stateDefinitions.factory.js:410 -#: client/src/users/users.form.js:159 -msgid "Teams" -msgstr "Teams" - -#: client/src/job-results/job-results.partial.html:135 -#: client/src/templates/templates.list.js:14 -msgid "Template" -msgstr "Sjabloon" - -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:35 -msgid "Templates" -msgstr "Sjablonen" - -#: client/src/credentials/credentials.form.js:337 -msgid "Tenant ID" -msgstr "Huurder-ID" - -#: client/src/configuration/system-form/sub-forms/system-logging.form.js:79 -msgid "Test" -msgstr "Test" - -#: client/src/notifications/notificationTemplates.list.js:67 -msgid "Test notification" -msgstr "Testbericht" - -#: client/src/shared/form-generator.js:1386 -#: client/src/shared/form-generator.js:1392 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" -"De waarde is niet gevonden. Voer een geldige waarde in of selecteer er een." - -#: client/lib/components/components.strings.js:43 -msgid "That value was not found. Please enter or select a valid value." -msgstr "" -"Die waarde kon niet gevonden worden. Voer een geldige waarde in of selecteer" -" er een." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:66 -msgid "The Insights Credential for {{inventory.name}} was not found." -msgstr "" -"De Insights-toegangsgegevens voor {{inventory.name}} konden niet gevonden " -"worden." - -#: client/src/credentials/factories/become-method-change.factory.js:32 -#: client/src/credentials/factories/kind-change.factory.js:89 -msgid "" -"The Project ID is the GCE assigned identification. It is constructed as two " -"words followed by a three digit number. Such as:" -msgstr "" -"Het project-ID is de toegewezen GCE-identificatie. Dit bestaat uit twee " -"woorden, gevolgd door drie getallen, zoals:" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "The SCM update process is running." -msgstr "Het SCM-updateproces is nu in uitvoering." - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:70 -msgid "The credential used to run this command." -msgstr "" -"De toegangsgegevens die gebruikt worden om dit commando uit te voeren." - -#: client/src/credentials/credentials.form.js:190 -msgid "" -"The email address assigned to the Google Compute Engine %sservice account." -msgstr "" -"Het e-mailadres dat toegewezen is aan het Google Compute Engine " -"%sserviceaccount." - -#: client/src/job-results/job-results.partial.html:513 -msgid "The host count will update when the job is complete." -msgstr "Het hostaantal wordt bijgewerkt wanneer de taak voltooid is." - -#: client/src/credentials/factories/become-method-change.factory.js:62 -#: client/src/credentials/factories/kind-change.factory.js:119 -msgid "The host to authenticate with." -msgstr "De host waarmee geauthenticeerd moet worden." - -#: client/src/credentials/factories/kind-change.factory.js:60 -msgid "The host value" -msgstr "De hostwaarde" - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:61 -msgid "The inventory this command ran on." -msgstr "De inventaris waar dit commando op wordt uitgevoerd." - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:101 -msgid "" -"The inventory will be in a pending status until the final delete is " -"processed." -msgstr "" -"De inventaris zal de status 'in afwachting' hebben totdat het laatste " -"verwijderproces verwerkt is." - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:104 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Inputting no value will use the default value from the %sansible " -"configuration file%s." -msgstr "" -"Het aantal parallelle of gelijktijdige processen dat gebruikt wordt bij het " -"uitvoeren van het draaiboeken. Als u geen waarde invoert, wordt de " -"standaardwaarde van de %sgeregistreerde Ansible-configuratie%s gebruikt." - -#: client/src/templates/job_templates/job-template.form.js:152 -msgid "" -"The number of parallel or simultaneous processes to use while executing the " -"playbook. Value defaults to 0. Refer to the Ansible documentation for " -"details about the configuration file." -msgstr "" -"Het aantal parallelle of gelijktijdige processen dat gebruikt wordt bij het " -"uitvoeren van het draaiboeken. Waarde is standaard 0. Raadpleeg de " -"documentatie van Ansible voor informatie over het configuratiebestand." - -#: client/src/job-results/job-results.controller.js:619 -msgid "The output is too large to display. Please download." -msgstr "" -"De output is te groot om weer te geven. Download het om het in te zien." - -#: client/src/credentials/factories/kind-change.factory.js:59 -msgid "The project value" -msgstr "De projectwaarde" - -#: client/src/projects/list/projects-list.controller.js:159 -msgid "" -"The selected project is not configured for SCM. To configure for SCM, edit " -"the project and provide SCM settings, and then run an update." -msgstr "" -"Het geselecteerde project is niet geconfigureerd voor SCM. Om het project te" -" configureren voor SCM, dient u het te wijzigen en SCM-instellingen op te " -"geven, om vervolgens een update uit te voeren." - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:42 -msgid "" -"The standard output is too large to display. Please specify additional " -"filters to narrow the standard out." -msgstr "" -"De standaardoutput is te groot om weer te geven. Pas extra filters toe om de" -" standaardoutput te verkleinen." - -#: client/src/templates/survey-maker/shared/question-definition.form.js:52 -msgid "" -"The suggested format for variable names is lowercase and underscore-" -"separated (for example, foo_bar, user_id, host_name, etc.). Variable names " -"with spaces are not allowed." -msgstr "" -"De voorgestelde indeling voor namen van variabelen: kleine letters en " -"gescheiden door middel van een underscore (bijvoorbeeld foo_bar, user_id, " -"host_name etc.) De naam van een variabele mag geen spaties bevatten." - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:124 -msgid "The time must be in HH24:MM:SS format." -msgstr "De tijd moet weergegeven worden in de indeling HH24:MM:SS." - -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:79 -msgid "The user who ran this command." -msgstr "De gebruiker die dit commando uitgevoerd heeft." - -#: client/src/activity-stream/streams.list.js:17 -msgid "There are no events to display at this time" -msgstr "Er zijn op dit moment geen evenementen om weer te geven" - -#: client/src/portal-mode/portal-job-templates.list.js:18 -msgid "There are no job templates to display at this time" -msgstr "Er zijn op dit moment geen taaksjablonen om weer te geven" - -#: client/src/portal-mode/portal-jobs.list.js:18 -msgid "There are no jobs to display at this time" -msgstr "Er zijn op dit moment geen taken om weer te geven" - -#: client/src/projects/list/projects-list.controller.js:150 -msgid "" -"There is no SCM update information available for this project. An update has" -" not yet been completed. If you have not already done so, start an update " -"for this project." -msgstr "" -"Er is geen SCM-update-informatie beschikbaar voor dit project. Er is nog " -"geen update voltooid. Start een update voor dit project, indien u dit nog " -"niet gedaan heeft." - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:140 -msgid "There was an error deleting inventory source groups. Returned status:" -msgstr "" -"Er is iets misgegaan bij het verwijderen van de inventarisbrongroepen. " -"Status:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:130 -msgid "There was an error deleting inventory source hosts. Returned status:" -msgstr "" -"Er is iets misgegaan bij het verwijderen van de inventarisbrongroepen. " -"Status:" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js:167 -msgid "There was an error deleting inventory source. Returned status:" -msgstr "" -"Er is iets misgegaan bij het verwijderen van de inventarisbron. Status:" - -#: client/src/configuration/configuration.controller.js:349 -msgid "There was an error resetting value. Returned status:" -msgstr "Er was een fout bij het resetten van de waarde. Teruggegeven status:" - -#: client/src/configuration/configuration.controller.js:531 -msgid "There was an error resetting values. Returned status:" -msgstr "Er was een fout bij het resetten van de waardes. Teruggegeven status:" - -#: client/src/configuration/system-form/configuration-system.controller.js:232 -msgid "There was an error testing the log aggregator. Returned status:" -msgstr "" -"Er was een fout bij het testen van de log aggregator. Teruggegeven status:" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:29 -msgid "" -"These are the modules that {{BRAND_NAME}} supports running commands against." -msgstr "" -"Dit zijn de modules waar {{BRAND_NAME}} commando's tegen kan uitvoeren." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:26 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "This group contains" -msgstr "Deze groep bevat" - -#: client/src/management-jobs/scheduler/schedulerForm.partial.html:168 -msgid "This is not a valid number." -msgstr "Dit is geen geldig nummer." - -#: client/src/credentials/factories/become-method-change.factory.js:59 -#: client/src/credentials/factories/kind-change.factory.js:116 -msgid "" -"This is the tenant name. This value is usually the same as the username." -msgstr "" -"Dit is de naam van de huurder. Deze waarde is vaak gelijk aan de " -"gebruikersnaam." - -#: client/src/notifications/notifications.list.js:21 -msgid "" -"This list is populated by notification templates added from the " -"%sNotifications%s section" -msgstr "" -"Deze lijst is gevuld met berichtsjablonen die toegevoegd zijn vanuit de " -"sectie %sBerichten%s" - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:4 -msgid "" -"This machine has not checked in with Insights in {{last_check_in}} hours" -msgstr "" -"Deze machine heeft {{last_check_in}} uur geleden voor het laatst ingecheckt " -"bij Insights" - -#: client/src/shared/form-generator.js:746 -msgid "" -"This setting has been set manually in a settings file and is now disabled." -msgstr "" -"Deze instelling is handmatig gekozen in een instellingenbestand en is nu " -"uitgeschakeld." - -#: client/src/users/users.form.js:164 -msgid "This user is not a member of any teams" -msgstr "Deze gebruiker is niet lid van een team" - -#: client/src/shared/form-generator.js:856 -#: client/src/shared/form-generator.js:951 -msgid "" -"This value does not match the password you entered previously. Please " -"confirm that password." -msgstr "" -"Deze waarde komt niet overeen met het wachtwoord dat u eerder ingevoerd " -"heeft. Bevestig dat wachtwoord." - -#: client/src/configuration/configuration.controller.js:556 -msgid "" -"This will reset all configuration values to their factory defaults. Are you " -"sure you want to proceed?" -msgstr "" -"Op deze manier worden alle configuratiewaarden gereset naar de " -"fabrieksinstellingen. Weet u zeker dat u verder wilt gaan?" - -#: client/src/activity-stream/streams.list.js:25 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:14 -#: client/src/notifications/notification-templates-list/list.controller.js:72 -msgid "Time" -msgstr "Tijd" - -#: client/src/license/license.partial.html:45 -msgid "Time Remaining" -msgstr "Tijd over" - -#: client/src/projects/projects.form.js:196 -msgid "" -"Time in seconds to consider a project to be current. During job runs and " -"callbacks the task system will evaluate the timestamp of the latest project " -"update. If it is older than Cache Timeout, it is not considered current, and" -" a new project update will be performed." -msgstr "" -"Tijd in seconden waarmee een project actueel genoemd kan worden. Tijdens " -"taken in uitvoering en terugkoppelingen wil het taaksysteem de tijdstempel " -"van de meest recente projectupdate bekijken. Indien dit ouder is dan de " -"Cache-timeout wordt het project niet gezien als actueel en moet er een " -"nieuwe projectupdate uitgevoerd worden." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:387 -msgid "" -"Time in seconds to consider an inventory sync to be current. During job runs" -" and callbacks the task system will evaluate the timestamp of the latest " -"sync. If it is older than Cache Timeout, it is not considered current, and a" -" new inventory sync will be performed." -msgstr "" -"Tijd in seconden waarmee een inventarissynchronisatie actueel genoemd kan " -"worden. Tijdens taken in uitvoering en terugkoppelingen zal het taaksysteem " -"de tijdstempel van de meest recente synchronisatie bekijken. Indien dit " -"ouder is dan de Cache-timeout wordt het project niet gezien als actueel en " -"moet er een nieuwe inventarissynchronisatie uitgevoerd worden." - -#: client/src/credentials/credentials.form.js:125 -msgid "" -"To learn more about the IAM STS Token, refer to the %sAmazon " -"documentation%s." -msgstr "" -"Raadpleeg de %sAmazondocumentatie%s voor meer informatie over de IAM STS-" -"token." - -#: client/src/shared/form-generator.js:881 -msgid "Toggle the display of plaintext." -msgstr "Tekst tonen/verbergen" - -#: client/src/notifications/shared/type-change.service.js:34 -#: client/src/notifications/shared/type-change.service.js:40 -msgid "Token" -msgstr "Token" - -#: client/src/job-results/job-results-stdout/job-results-stdout.partial.html:44 -msgid "Too much previous output to display. Showing running standard output." -msgstr "" -"Te veel eerdere output om weer te geven. Standaardoutput in uitvoering wordt" -" weergegeven." - -#: client/src/inventories-hosts/inventories/insights/insights.partial.html:10 -msgid "Total Issues" -msgstr "Totale problemen" - -#: client/src/partials/logviewer.html:6 -msgid "Traceback" -msgstr "Traceback" - -#: client/src/credentials/credentials.form.js:60 -#: client/src/credentials/credentials.form.js:84 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:52 -#: client/src/instance-groups/jobs/jobs.list.js:51 -#: client/src/inventories-hosts/inventories/inventory.list.js:55 -#: client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js:52 -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:41 -#: client/src/jobs/all-jobs.list.js:59 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:39 -#: client/src/notifications/notifications.list.js:31 -#: client/src/projects/projects.list.js:44 -#: client/src/scheduler/scheduled-jobs.list.js:42 -#: client/src/teams/teams.form.js:130 -#: client/src/templates/completed-jobs.list.js:53 -#: client/src/templates/templates.list.js:31 -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:27 -#: client/src/users/users.form.js:200 -msgid "Type" -msgstr "Soort" - -#: client/features/credentials/credentials.strings.js:18 -#: client/src/credentials/credentials.form.js:23 -#: client/src/notifications/notificationTemplates.form.js:26 -msgid "Type Details" -msgstr "Soortdetails" - -#: client/src/projects/add/projects-add.controller.js:169 -#: client/src/projects/edit/projects-edit.controller.js:304 -msgid "URL popover text" -msgstr "URL-popovertekst" - -#: client/src/login/loginModal/loginModal.partial.html:49 -msgid "USERNAME" -msgstr "GEBRUIKERSNAAM" - -#: client/src/activity-stream/get-target-title.factory.js:20 -#: client/src/organizations/linkout/organizations-linkout.route.js:42 -#: client/src/organizations/list/organizations-list.controller.js:54 -#: client/src/users/main.js:46 client/src/users/users.list.js:18 -#: client/src/users/users.list.js:19 -msgid "USERS" -msgstr "GEBRUIKERS" - -#: client/lib/components/components.strings.js:20 -msgid "Unable to Submit" -msgstr "Kon niet indienen" - -#: client/lib/components/components.strings.js:52 -msgid "Unavailable to run jobs." -msgstr "Kan geen taken uitvoeren." - -#: client/lib/components/components.strings.js:22 -msgid "Unexpected Error" -msgstr "Onverwachte fout" - -#: client/lib/components/components.strings.js:21 -msgid "Unexpected server error. View the console for more information" -msgstr "Onverwachte serverfout. Bekijk de console voor meer informatie" - -#: client/lib/components/components.strings.js:34 -msgid "Unsupported display model type" -msgstr "Soort weergavemodel niet ondersteund" - -#: client/lib/components/components.strings.js:26 -msgid "Unsupported input type" -msgstr "Soort input niet ondersteund" - -#: client/src/projects/list/projects-list.controller.js:266 -msgid "Update Not Found" -msgstr "Update niet gevonden" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:321 -msgid "Update Options" -msgstr "Update-opties" - -#: client/src/projects/edit/projects-edit.controller.js:332 -msgid "Update in Progress" -msgstr "Update in uitvoering" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:352 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:357 -#: client/src/projects/projects.form.js:177 -msgid "Update on Launch" -msgstr "Update bij opstarten" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:364 -msgid "Update on Project Change" -msgstr "Update voor projectwijziging" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:370 -msgid "Update on Project Update" -msgstr "Update voor projectupdate" - -#: client/src/license/license.partial.html:71 -msgid "Upgrade" -msgstr "Upgrade" - -#: client/src/templates/job_templates/job-template.form.js:299 -#: client/src/templates/job_templates/job-template.form.js:304 -msgid "Use Fact Cache" -msgstr "Feitcache gebruiken" - -#: client/src/notifications/notificationTemplates.form.js:395 -msgid "Use SSL" -msgstr "SSL gebruiken" - -#: client/src/notifications/notificationTemplates.form.js:390 -msgid "Use TLS" -msgstr "TLS gebruiken" - -#: client/src/instance-groups/instance-group.partial.html:10 -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.partial.html:10 -#: client/src/instance-groups/instances/instances-list.partial.html:21 -#: client/src/instance-groups/list/instance-groups-list.partial.html:32 -msgid "Used Capacity" -msgstr "Gebruikte capaciteit" - -#: client/src/credentials/credentials.form.js:76 -msgid "" -"Used to check out and synchronize playbook repositories with a remote source" -" control management system such as Git, Subversion (svn), or Mercurial (hg)." -" These credentials are used by Projects." -msgstr "" -"Wordt gebruikt om draaiboekopslagplaatsen te bekijken en te synchroniseren " -"met een broncontrole-beheersysteem op afstand, zoals Git, Subversion (svn) " -"of Mercurial (hg). Deze toegangsgegevens worden gebruikt door projecten." - -#: client/features/credentials/legacy.credentials.js:83 -#: client/src/credentials/credentials.form.js:456 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:143 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:144 -#: client/src/organizations/organizations.form.js:92 -#: client/src/projects/projects.form.js:250 client/src/teams/teams.form.js:93 -#: client/src/templates/workflows.form.js:133 -msgid "User" -msgstr "Gebruiker" - -#: client/src/configuration/configuration.partial.html:18 -msgid "User Interface" -msgstr "Gebruikersinterface" - -#: client/src/users/users.form.js:95 -msgid "User Type" -msgstr "Soort gebruiker" - -#: client/src/access/rbac-multiselect/permissionsUsers.list.js:30 -#: client/src/credentials/factories/become-method-change.factory.js:17 -#: client/src/credentials/factories/become-method-change.factory.js:38 -#: client/src/credentials/factories/kind-change.factory.js:17 -#: client/src/credentials/factories/kind-change.factory.js:41 -#: client/src/credentials/factories/kind-change.factory.js:74 -#: client/src/credentials/factories/kind-change.factory.js:95 -#: client/src/notifications/notificationTemplates.form.js:64 -#: client/src/users/users.form.js:58 client/src/users/users.list.js:29 -msgid "Username" -msgstr "Gebruikersnaam" - -#: client/src/credentials/credentials.form.js:80 -msgid "" -"Usernames, passwords, and access keys for authenticating to the specified " -"cloud or infrastructure provider. These are used for smart inventory sources" -" and for cloud provisioning and deployment in playbook runs." -msgstr "" -"Gebruikersnamen, wachtwoorden en toegangssleutels voor authenticatie bij de " -"gespecificeerde cloud- of infrastructuurprovider. Deze worden gebruikt voor " -"smart-inventarisbronnen, voor cloudvoorziening en om in te zetten bij " -"uitvoeringen van het draaiboek." - -#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 -#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:36 -#: client/src/organizations/organizations.form.js:74 -#: client/src/setup-menu/setup-menu.partial.html:10 -#: client/src/teams/teams.form.js:75 -msgid "Users" -msgstr "Gebruikers" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:7 -#: client/src/home/dashboard/lists/jobs/jobs-list.partial.html:7 -msgid "VIEW ALL" -msgstr "ALLE WEERGEVEN" - -#: client/src/main-menu/main-menu.partial.html:75 -msgid "VIEW DOCUMENTATION" -msgstr "DOCUMENTATIE WEERGEVEN" - -#: client/src/shared/paginate/paginate.partial.html:48 -msgid "VIEW PER PAGE" -msgstr "WEERGEVEN PER PAGINA" - -#: client/src/main-menu/main-menu.partial.html:51 -msgid "VIEW USER PAGE FOR {{ $root.current_user.username | uppercase }}" -msgstr "" -"GEBRUIKERSPAGINA VOOR {{ $root.current_user.username | uppercase }} " -"WEERGEVEN" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:180 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:261 -msgid "VPC ID:" -msgstr "VPC-ID:" - -#: client/src/license/license.partial.html:10 -msgid "Valid License" -msgstr "Geldige licentie" - -#: client/src/inventories-hosts/hosts/host.form.js:68 -#: client/src/inventories-hosts/inventories/related/groups/groups.form.js:46 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.form.js:47 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:67 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:67 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:81 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:88 -#: client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js:94 -msgid "Variables" -msgstr "Variabelen" - -#: client/src/job-submission/job-submission.partial.html:364 -msgid "Vault" -msgstr "Kluis" - -#: client/src/job-results/job-results.partial.html:321 -msgid "Vault Credential" -msgstr "Toegangsgegevens kluis" - -#: client/src/credentials/credentials.form.js:391 -#: client/src/job-submission/job-submission.partial.html:146 -msgid "Vault Password" -msgstr "Wachtwoord kluis" - -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:81 -#: client/src/inventories-hosts/inventories/adhoc/adhoc.form.js:90 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:307 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:314 -#: client/src/job-results/job-results.partial.html:358 -#: client/src/job-submission/job-submission.partial.html:183 -#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:99 -#: client/src/templates/job_templates/job-template.form.js:174 -#: client/src/templates/job_templates/job-template.form.js:181 -msgid "Verbosity" -msgstr "Verbositeit" - -#: client/src/license/license.partial.html:15 -msgid "Version" -msgstr "Versie" - -#: client/src/activity-stream/streams.list.js:63 -#: client/src/credential-types/credential-types.list.js:64 -#: client/src/credentials/credentials.list.js:75 -#: client/src/home/dashboard/graphs/dashboard-graphs.partial.html:58 -#: client/src/inventories-hosts/inventories/inventory.list.js:104 -#: client/src/inventory-scripts/inventory-scripts.list.js:62 -#: client/src/notifications/notificationTemplates.list.js:82 -#: client/src/scheduler/schedules.list.js:83 client/src/teams/teams.list.js:64 -#: client/src/templates/templates.list.js:112 -#: client/src/users/users.list.js:70 -msgid "View" -msgstr "weergeven" - -#: client/src/bread-crumb/bread-crumb.directive.js:41 -msgid "View Activity Stream" -msgstr "Activiteitenlogboek weergeven" - -#: client/src/main-menu/main-menu.partial.html:173 -msgid "View Documentation" -msgstr "Documentatie weergeven" - -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:79 -msgid "View Insights Data" -msgstr "Insights-gegevens weergeven" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:202 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:226 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:250 -msgid "View JSON examples at" -msgstr "Bekijk JSON-voorbeelden op" - -#: client/src/inventories-hosts/hosts/host.form.js:78 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:77 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:77 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:91 -msgid "View JSON examples at %s" -msgstr "Zie JSON-voorbeelden op %s" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:13 -msgid "View Less" -msgstr "Minder weergeven" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.partial.html:11 -msgid "View More" -msgstr "Meer weergeven" - -#: client/src/shared/form-generator.js:1719 -#: client/src/templates/job_templates/job-template.form.js:436 -#: client/src/templates/workflows.form.js:161 -msgid "View Survey" -msgstr "Vragenlijst weergeven" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:203 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:227 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:251 -msgid "View YAML examples at" -msgstr "Bekijk YAML-voorbeelden op" - -#: client/src/inventories-hosts/hosts/host.form.js:79 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.form.js:78 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.form.js:78 -#: client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js:92 -msgid "View YAML examples at %s" -msgstr "Zie YAML-voorbeelden op %s" - -#: client/src/setup-menu/setup-menu.partial.html:72 -msgid "View Your License" -msgstr "Uw licentie weergeven" - -#: client/src/setup-menu/setup-menu.partial.html:73 -msgid "View and edit your license information." -msgstr "Uw licentie-informatie weergeven en bewerken." - -#: client/src/credentials/credentials.list.js:77 -msgid "View credential" -msgstr "Toegangsgegevens weergeven" - -#: client/src/credential-types/credential-types.list.js:66 -msgid "View credential type" -msgstr "Soort toegangsgegevens weergeven" - -#: client/src/activity-stream/streams.list.js:67 -msgid "View event details" -msgstr "Evenementinformatie weergeven" - -#: client/src/inventories-hosts/inventories/related/groups/groups.list.js:93 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js:103 -#: client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js:91 -msgid "View group" -msgstr "Groep weergeven" - -#: client/src/inventories-hosts/hosts/host.list.js:89 -#: client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js:79 -#: client/src/inventories-hosts/inventories/related/hosts/related-host.list.js:93 -msgid "View host" -msgstr "Host weergeven" - -#: client/src/setup-menu/setup-menu.partial.html:67 -msgid "View information about this version of Ansible {{BRAND_NAME}}." -msgstr "Informatie over deze versie van Ansible {{BRAND_NAME}} weergeven." - -#: client/src/inventories-hosts/inventories/inventory.list.js:106 -msgid "View inventory" -msgstr "Inventaris weergeven" - -#: client/src/inventory-scripts/inventory-scripts.list.js:64 -msgid "View inventory script" -msgstr "Inventarisscript weergeven" - -#: client/src/setup-menu/setup-menu.partial.html:55 -msgid "View list and capacity of {{BRAND_NAME}} instances." -msgstr "Lijst en capaciteit van {{BRAND_NAME}}-instanties weergeven." - -#: client/src/notifications/notificationTemplates.list.js:84 -msgid "View notification" -msgstr "Bericht weergeven" - -#: client/src/job-results/job-results.partial.html:222 -msgid "View project sync results" -msgstr "Resultaten projectsynchronisatie weergeven" - -#: client/src/scheduler/schedules.list.js:85 -msgid "View schedule" -msgstr "Schema weergeven" - -#: client/src/inventories-hosts/inventories/related/sources/sources.list.js:118 -msgid "View source" -msgstr "Bron weergeven" - -#: client/src/teams/teams.list.js:67 -msgid "View team" -msgstr "Team weergeven" - -#: client/src/templates/templates.list.js:114 -msgid "View template" -msgstr "Sjabloon weergeven" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:192 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:274 -msgid "View the" -msgstr "Bekijk de" - -#: client/src/jobs/all-jobs.list.js:92 -msgid "View the job" -msgstr "De taak weergeven" - -#: client/src/projects/projects.list.js:111 -msgid "View the project" -msgstr "Het project weergeven" - -#: client/src/scheduler/scheduled-jobs.list.js:74 -msgid "View the schedule" -msgstr "Het schema weergeven" - -#: client/src/users/users.list.js:73 -msgid "View user" -msgstr "Gebruiker weergeven" - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs.list.js:42 -#: client/src/instance-groups/jobs/jobs.list.js:41 -#: client/src/job-results/job-results.partial.html:145 -#: client/src/jobs/all-jobs.list.js:49 -#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:25 -#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:25 -msgid "View workflow results" -msgstr "Workflowresultaten weergeven" - -#: client/src/templates/workflows.form.js:20 -msgid "WORKFLOW" -msgstr "WORKFLOW" - -#: client/src/configuration/auth-form/configuration-auth.controller.js:73 -#: client/src/configuration/configuration.controller.js:200 -#: client/src/configuration/configuration.controller.js:262 -#: client/src/configuration/system-form/configuration-system.controller.js:55 -msgid "Warning: Unsaved Changes" -msgstr "Waarschuwing: niet-opgeslagen wijzigingen" - -#: client/src/license/license.partial.html:78 -msgid "" -"Welcome to Ansible Tower! Please complete the steps below to acquire a " -"license." -msgstr "" -"Welkom bij Ansible Tower! Volg de onderstaande stappen op om een licentie te" -" verkrijgen." - -#: client/src/login/loginModal/loginModal.partial.html:17 -msgid "Welcome to Ansible {{BRAND_NAME}}!  Please sign in." -msgstr "Welkom bij Ansible {{BRAND_NAME}}! Meld u eerst aan." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:344 -msgid "" -"When not checked, a merge will be performed, combining local variables with " -"those found on the external source." -msgstr "" -"Als dit vakje niet aangevinkt is, worden lokale variabelen samengevoegd met " -"de variabelen die aangetroffen zijn in de externe bron." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:332 -msgid "" -"When not checked, local child hosts and groups not found on the external " -"source will remain untouched by the inventory update process." -msgstr "" -"Als dit vakje niet aangevinkt is, worden lokale onderliggende hosts en " -"groepen die niet aangetroffen zijn in de externe bron niet behandeld in het " -"synchronisatieproces van de inventaris." - -#: client/src/templates/workflows/workflow-maker/workflow-maker.form.js:97 -msgid "" -"When this template is submitted as a job, setting the type to %s will " -"execute the playbook, running tasks on the selected hosts." -msgstr "" -"Als dit sjabloon wordt ingediend als taak en de soort wordt ingesteld als " -"%s, wordt het draaiboek uitgevoerd en worden de taken uitgevoerd op de " -"gekozen hosts." - -#: client/src/shared/form-generator.js:1723 -#: client/src/templates/workflows.form.js:187 -msgid "Workflow Editor" -msgstr "Workfloweditor" - -#: client/src/templates/templates.list.js:66 -msgid "Workflow Template" -msgstr "Workflowsjabloon" - -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 -#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:41 -msgid "Workflow Templates" -msgstr "Workflowsjablonen" - -#: client/src/job-submission/job-submission.partial.html:171 -msgid "YAML" -msgstr "YAML" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:200 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:224 -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:248 -msgid "YAML:" -msgstr "YAML:" - -#: client/src/notifications/add/add.controller.js:78 -#: client/src/notifications/edit/edit.controller.js:125 -msgid "Yellow" -msgstr "Geel" - -#: client/src/home/dashboard/lists/job-templates/job-templates-list.partial.html:56 -msgid "" -"You can create a job template here." -msgstr "" -"U kunt hier een taaksjabloon " -"maken." - -#: client/src/projects/edit/projects-edit.controller.js:62 -msgid "You do not have access to view this property" -msgstr "U heeft geen toestemming om dit eigendom weer te geven" - -#: client/src/projects/add/projects-add.controller.js:29 -msgid "You do not have permission to add a project." -msgstr "U heeft geen machtiging om een project toe te voegen." - -#: client/src/users/add/users-add.controller.js:43 -msgid "You do not have permission to add a user." -msgstr "U heeft geen machtiging om een gebruiker toe te voegen." - -#: client/src/inventories-hosts/inventory-hosts.strings.js:28 -msgid "You do not have sufficient permissions to edit the host filter." -msgstr "U hebt geen toestemming om het hostfilter te bewerken." - -#: client/src/configuration/auth-form/configuration-auth.controller.js:72 -#: client/src/configuration/configuration.controller.js:199 -#: client/src/configuration/configuration.controller.js:261 -#: client/src/configuration/system-form/configuration-system.controller.js:54 -msgid "" -"You have unsaved changes. Would you like to proceed without" -" saving?" -msgstr "" -"U heeft niet-opgeslagen wijzigingen. Wilt u doorgaan zonder" -" op te slaan?" - -#: client/src/projects/list/projects-list.controller.js:222 -msgid "Your request to cancel the update was submitted to the task manager." -msgstr "" -"Uw verzoek om de update te annuleren is ingediend bij de taakbeheerder." - -#: client/src/login/loginModal/loginModal.partial.html:22 -msgid "Your session timed out due to inactivity. Please sign in." -msgstr "Uw sessie is verlopen vanwege inactiviteit. Meld u opnieuw aan." - -#: client/src/inventories-hosts/inventories/related/groups/list/groups-list.partial.html:24 -#: client/src/job-submission/job-submission.partial.html:317 -#: client/src/shared/form-generator.js:1193 -msgid "and" -msgstr "en" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "characters long." -msgstr "tekens lang." - -#: client/src/shared/smart-search/smart-search.partial.html:53 -msgid "documentation" -msgstr "documentatie" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:193 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:275 -msgid "for a complete list of supported filters." -msgstr "voor een volledige lijst van ondersteunde filters." - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -msgid "from the" -msgstr "van de" - -#: client/src/inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList.directive.js:82 -#: client/src/inventories-hosts/inventory-hosts.strings.js:8 -msgid "group" -msgid_plural "groups" -msgstr[0] "groep" -msgstr[1] "groepen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:26 -msgid "groups" -msgstr "groepen" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -msgid "groups and" -msgstr "groepen en" - -#: client/src/inventories-hosts/inventory-hosts.strings.js:9 -msgid "host" -msgid_plural "hosts" -msgstr[0] "host" -msgstr[1] "hosts" - -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:24 -#: client/src/inventories-hosts/inventories/related/sources/list/sources-list.partial.html:25 -msgid "hosts" -msgstr "hosts" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:58 -msgid "hosts with failures. Click for details." -msgstr "hosts met mislukkingen. Klik voor meer informatie." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:21 -msgid "name" -msgstr "naam" - -#: client/src/shared/paginate/paginate.partial.html:34 -msgid "of" -msgstr "van" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "of the filters match." -msgstr "van de filters komen overeen." - -#: client/src/access/rbac-multiselect/permissionsTeams.list.js:24 -msgid "organization" -msgstr "organisatie" - -#: client/src/shared/form-generator.js:1069 -msgid "playbook" -msgstr "draaiboek" - -#: client/src/credentials/credentials.form.js:138 -#: client/src/credentials/credentials.form.js:364 -msgid "set in helpers/credentials" -msgstr "ingesteld in helpers/toegangsgegevens" - -#: client/src/inventories-hosts/inventories/list/inventory-list.controller.js:43 -msgid "sources with sync failures. Click for details" -msgstr "bronnen met synchronisatiefouten. Klik voor meer informatie" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:190 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:272 -msgid "test" -msgstr "test" - -#: client/src/job-submission/job-submission.partial.html:289 -#: client/src/job-submission/job-submission.partial.html:294 -#: client/src/job-submission/job-submission.partial.html:305 -msgid "to" -msgstr "om" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:139 -msgid "" -"to include all regions. Only Hosts associated with the selected regions will" -" be updated." -msgstr "" -"om alle regio's te omvatten. Alleen hosts die bij de gekozen regio's horen " -"worden geüpdatet." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:17 -msgid "to start it now." -msgstr "om nu te beginnen." - -#: client/src/inventories-hosts/inventories/related/sources/factories/get-sync-status-msg.factory.js:25 -msgid "to update." -msgstr "om te updaten." - -#: client/src/credentials/credentials.form.js:381 -msgid "v2 URLs%s - leave blank" -msgstr "v2 URL's%s - leeg laten" - -#: client/src/credentials/credentials.form.js:382 -msgid "v3 default%s - set to 'default'" -msgstr "v3 standaard%s - instellen op 'standaard'" - -#: client/src/credentials/credentials.form.js:383 -msgid "v3 multi-domain%s - your domain name" -msgstr "v3 multi-domein%s - uw domeinnaam" - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:220 -msgid "view ec2.ini in the Ansible github repo." -msgstr "zie ec2.ini in de Ansible github repo." - -#: client/src/inventories-hosts/inventories/related/sources/sources.form.js:244 -msgid "view vmware_inventory.ini in the Ansible github repo." -msgstr "zie vmware_inventory.ini in de Ansible github repo." - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:185 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:267 -msgid "when" -msgstr "wanneer" - -#: client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js:171 -#: client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js:252 -msgid "" -"will create group names similar to the following examples based on the " -"options selected:" -msgstr "" -"zullen groepsnamen aangemaakt worden die vergelijkbaar zijn met de volgende " -"voorbeelden op basis van de geselecteerde opties:" - -#: client/src/inventories-hosts/inventories/related/groups/factories/get-hosts-status-msg.factory.js:11 -msgid "with failed jobs." -msgstr "met mislukte taken." - -#: client/src/instance-groups/instances/instance-jobs/instance-jobs-list.route.js:9 -msgid "{{ breadcrumb.instance_name }}" -msgstr "{{ breadcrumb.instance_name }}" - -#: client/lib/components/input/label.partial.html:5 -msgid "{{::state._hint}}" -msgstr "{{::state._hint}}" - -#: client/src/instance-groups/instances/instances-list.route.js:10 -msgid "{{breadcrumb.instance_group_name}}" -msgstr "{{breadcrumb.instance_group_name}}" - -#: client/src/shared/paginate/paginate.partial.html:55 -msgid "{{pageSize}}" -msgstr "{{pageSize}}" diff --git a/awx/ui/test/e2e/.babelrc b/awx/ui/test/e2e/.babelrc deleted file mode 100644 index 05758ba5a89d..000000000000 --- a/awx/ui/test/e2e/.babelrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "presets": [ - ["env", { - "targets": { - "node": 6 - } - }] - ] -} diff --git a/awx/ui/test/e2e/.eslintrc.js b/awx/ui/test/e2e/.eslintrc.js deleted file mode 100644 index 02959f42e37f..000000000000 --- a/awx/ui/test/e2e/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - rules: { - 'no-unused-expressions': 'off', - 'no-unused-vars': 'off', - } -}; diff --git a/awx/ui/test/e2e/README.md b/awx/ui/test/e2e/README.md deleted file mode 100644 index d56bdda0d1f5..000000000000 --- a/awx/ui/test/e2e/README.md +++ /dev/null @@ -1,45 +0,0 @@ -## AWX E2E -#### Introduction -This is an automated functional test suite for the front end. - -#### Technology -The tests are written in Node.js and use the [Nightwatch](https://github.com/nightwatchjs/nightwatch) test runner. - -#### Requirements -- node.js 6.x LTS -- npm 3.x LTS - -#### Installation -A successful invocation of `make ui-devel` will prepare your environment with the software -dependencies required to run these tests. - -#### Configuration -Three inputs are required: - -*AWX_E2E_URL* - -> A valid url for a running AWX instance that is reachable by your machine. This can be your local -development instance or other awx instance. Defaults to *https://localhost:8043*. - -*AWX_E2E_USERNAME* - -> A valid admin username for the target awx instance. Defaults to *awx-e2e*. - -*AWX_E2E_PASSWORD* - -> A valid password for the admin. Defaults to *password*. - -These inputs can be provided as environment variables or defined as default values in [settings](settings.js). -The settings file also contains all other configurable input values to this test suite. - -#### Usage -```shell -# run all of the tests with a live browser -npm --prefix awx/ui run e2e - -# run a subset of the tests -npm --prefix awx/ui run e2e -- --filter="test-credentials*" -``` -**Note:** -- Use `npm --prefix awx/ui run e2e -- --help` to see additional usage information for the test runner. -- All example commands in this document assume that you are working from the root directory of the awx project. diff --git a/awx/ui/test/e2e/api.js b/awx/ui/test/e2e/api.js deleted file mode 100644 index f411e8ed5674..000000000000 --- a/awx/ui/test/e2e/api.js +++ /dev/null @@ -1,61 +0,0 @@ -import https from 'https'; - -import axios from 'axios'; - -import { - AWX_E2E_URL, - AWX_E2E_USERNAME, - AWX_E2E_PASSWORD -} from './settings'; - -const session = axios.create({ - baseURL: AWX_E2E_URL, - xsrfHeaderName: 'X-CSRFToken', - xsrfCookieName: 'csrftoken', - httpsAgent: new https.Agent({ - rejectUnauthorized: false - }), - auth: { - username: AWX_E2E_USERNAME, - password: AWX_E2E_PASSWORD - } -}); - -const getEndpoint = location => { - if (location.indexOf('/api/v') === 0 || location.indexOf('://') > 0) { - return location; - } - - return `${AWX_E2E_URL}/api/v2${location}`; -}; - -const request = (method, location, data) => { - const uri = getEndpoint(location); - const action = session[method.toLowerCase()]; - - return action(uri, data) - .then(res => { - console.log([ // eslint-disable-line no-console - res.config.method.toUpperCase(), - res.config.url, - res.status, - res.statusText - ].join(' ')); - - return res; - }); -}; - -const get = (endpoint, data) => request('GET', endpoint, data); -const options = endpoint => request('OPTIONS', endpoint); -const post = (endpoint, data) => request('POST', endpoint, data); -const patch = (endpoint, data) => request('PATCH', endpoint, data); -const put = (endpoint, data) => request('PUT', endpoint, data); - -module.exports = { - get, - options, - post, - patch, - put, -}; diff --git a/awx/ui/test/e2e/cluster/Dockerfile b/awx/ui/test/e2e/cluster/Dockerfile deleted file mode 100644 index 0c92d037fe7f..000000000000 --- a/awx/ui/test/e2e/cluster/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM centos:7 - -RUN yum install -y epel-release - -RUN yum install -y \ - bzip2 \ - gcc-c++ \ - git \ - make \ - nodejs \ - npm - -WORKDIR /awx - -COPY awx/ui/package.json awx/ui/package.json - -RUN npm --prefix=awx/ui install - -COPY awx/ui/test/e2e awx/ui/test/e2e - -ENTRYPOINT ["npm", "--prefix=awx/ui", "run", "e2e", "--", "--env=cluster"] diff --git a/awx/ui/test/e2e/cluster/docker-compose.devel-override.yml b/awx/ui/test/e2e/cluster/docker-compose.devel-override.yml deleted file mode 100644 index eed4e15a9436..000000000000 --- a/awx/ui/test/e2e/cluster/docker-compose.devel-override.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -version: '2' -networks: - default: - external: - name: tools_default -services: - chrome: - external_links: - - tools_awx_1:awx - firefox: - external_links: - - tools_awx_1:awx - e2e: - external_links: - - tools_awx_1:awx - environment: - AWX_E2E_URL: https://awx:8043 diff --git a/awx/ui/test/e2e/cluster/docker-compose.yml b/awx/ui/test/e2e/cluster/docker-compose.yml deleted file mode 100644 index 4576ed804ea4..000000000000 --- a/awx/ui/test/e2e/cluster/docker-compose.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -version: '2' -services: - hub: - image: selenium/hub:3.8.1-erbium - ports: - - 4444:4444 - chrome: - image: selenium/node-chrome:3.8.1-erbium - # uncomment the two lines below to make tests watchable at vnc://localhost:secret@localhost:5900 - # image: selenium/node-chrome-debug - # ports: ['5900:5900'] - links: - - hub - volumes: - - /dev/shm:/dev/shm - environment: - HUB_PORT_4444_TCP_ADDR: hub - HUB_PORT_4444_TCP_PORT: 4444 - firefox: - image: selenium/node-firefox - links: - - hub - environment: - HUB_PORT_4444_TCP_ADDR: hub - HUB_PORT_4444_TCP_PORT: 4444 - e2e: - image: awx_e2e - build: - context: ../../../../../ - dockerfile: awx/ui/test/e2e/cluster/Dockerfile - depends_on: - - chrome - links: - - hub - volumes: - - ..:/awx/awx/ui/test/e2e - environment: - AWX_E2E_CLUSTER_HOST: hub - AWX_E2E_CLUSTER_PORT: 4444 diff --git a/awx/ui/test/e2e/commands/inject.js b/awx/ui/test/e2e/commands/inject.js deleted file mode 100644 index 3ecbbcd61c43..000000000000 --- a/awx/ui/test/e2e/commands/inject.js +++ /dev/null @@ -1,25 +0,0 @@ -exports.command = function inject (deps, script, callback) { - this.executeAsync( - `let args = Array.prototype.slice.call(arguments,0); - - return function(deps, done) { - let injector = angular.element('body').injector(); - let loaded = deps.map(d => { - if (typeof(d) === "string") { - return injector.get(d); - } else { - return d; - } - }); - (${script.toString()}).apply(this, loaded).then(done); - }.apply(this, args);`, - [deps], - function handleResult (result) { - if (typeof callback === 'function') { - callback.call(this, result.value); - } - } - ); - - return this; -}; diff --git a/awx/ui/test/e2e/commands/login.js b/awx/ui/test/e2e/commands/login.js deleted file mode 100644 index 65c9cce1eac5..000000000000 --- a/awx/ui/test/e2e/commands/login.js +++ /dev/null @@ -1,52 +0,0 @@ -import { EventEmitter } from 'events'; -import { inherits } from 'util'; - -import { - AWX_E2E_USERNAME, - AWX_E2E_PASSWORD, - AWX_E2E_TIMEOUT_LONG -} from '../settings'; - -function Login () { - EventEmitter.call(this); -} - -inherits(Login, EventEmitter); - -Login.prototype.command = function command (username, password) { - username = username || AWX_E2E_USERNAME; - password = password || AWX_E2E_PASSWORD; - - const loginPage = this.api.page.login(); - - loginPage - .navigate() - .waitForElementVisible('@submit', AWX_E2E_TIMEOUT_LONG) - .waitForElementNotVisible('div.spinny') - .setValue('@username', username) - .setValue('@password', password) - .click('@submit') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - // temporary hack while login issue is resolved - this.api.elements('css selector', '.LoginModal-alert', result => { - let alertVisible = false; - result.value.map(i => i.ELEMENT).forEach(id => { - this.api.elementIdDisplayed(id, ({ value }) => { - if (!alertVisible && value) { - alertVisible = true; - loginPage.setValue('@username', username); - loginPage.setValue('@password', password); - loginPage.click('@submit'); - loginPage.waitForElementVisible('div.spinny'); - loginPage.waitForElementNotVisible('div.spinny'); - } - }); - }); - - this.emit('complete'); - }); -}; - -module.exports = Login; diff --git a/awx/ui/test/e2e/commands/navigateTo.js b/awx/ui/test/e2e/commands/navigateTo.js deleted file mode 100644 index 4c4509cf6167..000000000000 --- a/awx/ui/test/e2e/commands/navigateTo.js +++ /dev/null @@ -1,13 +0,0 @@ -const spinny = 'div.spinny'; - -exports.command = function navigateTo (url, expectSpinny = true) { - this.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - this.url(url); - - if (expectSpinny) { - this.waitForElementVisible(spinny); - this.waitForElementNotVisible(spinny); - } - - return this; -}; diff --git a/awx/ui/test/e2e/commands/pushFileToWorker.js b/awx/ui/test/e2e/commands/pushFileToWorker.js deleted file mode 100644 index 191164f77890..000000000000 --- a/awx/ui/test/e2e/commands/pushFileToWorker.js +++ /dev/null @@ -1,57 +0,0 @@ -import { basename } from 'path'; -import { EventEmitter } from 'events'; -import { inherits } from 'util'; - -import archiver from 'archiver'; - -function pushFileToWorker (localFilePath, callback) { - const name = basename(localFilePath); - - const push = handler => { - const archive = archiver('zip'); - - const buffers = []; - - archive - .on('data', data => buffers.push(data)) - .on('error', err => { throw err; }) - .on('finish', () => { - const file = Buffer.concat(buffers).toString('base64'); - - this.api.session(session => { - const params = { - path: `/session/${session.sessionId}/file`, - method: 'POST', - data: { file }, - }; - - this.client.runProtocolAction(params, handler).send(); - }); - }); - - archive.file(localFilePath, { name }); - archive.finalize(); - }; - - push(({ status, value }) => { - if (status !== 0) { - throw new Error(value.message); - } - - if (typeof callback === 'function') { - callback.call(this, value); - } - - this.emit('complete'); - }); - - return this; -} - -function PushFileToWorker () { EventEmitter.call(this); } - -inherits(PushFileToWorker, EventEmitter); - -PushFileToWorker.prototype.command = pushFileToWorker; - -module.exports = PushFileToWorker; diff --git a/awx/ui/test/e2e/commands/waitForAngular.js b/awx/ui/test/e2e/commands/waitForAngular.js deleted file mode 100644 index bad16b09cfc5..000000000000 --- a/awx/ui/test/e2e/commands/waitForAngular.js +++ /dev/null @@ -1,19 +0,0 @@ -import { AWX_E2E_TIMEOUT_ASYNC } from '../settings'; - -exports.command = function waitForAngular (callback) { - this.timeoutsAsyncScript(AWX_E2E_TIMEOUT_ASYNC, () => { - this.executeAsync(done => { - if (angular && angular.getTestability) { - angular.getTestability(document.body).whenStable(done); - } else { - done(); - } - }, [], result => { - if (typeof callback === 'function') { - callback.call(this, result); - } - }); - }); - - return this; -}; diff --git a/awx/ui/test/e2e/fixtures.js b/awx/ui/test/e2e/fixtures.js deleted file mode 100644 index ddc705cdf76f..000000000000 --- a/awx/ui/test/e2e/fixtures.js +++ /dev/null @@ -1,385 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_PASSWORD } from './settings'; - -import { - get, - post, -} from './api'; - -const session = `e2e-${uuid().substr(0, 8)}`; -const store = {}; - -const getOrCreate = (endpoint, data, unique = ['name']) => { - const identifiers = Object.keys(data).filter(key => unique.indexOf(key) > -1); - - if (identifiers.length < 1) { - throw new Error('A unique key value must be provided.'); - } - - const lookup = `${endpoint}/${identifiers.map(key => data[key]).join('-')}`; - const params = Object.assign(...identifiers.map(key => ({ [key]: data[key] }))); - - store[lookup] = store[lookup] || get(endpoint, { params }) - .then(res => { - if (res.data.results.length > 1) { - return Promise.reject(new Error('More than one matching result.')); - } - - if (res.data.results.length === 1) { - return get(res.data.results[0].url); - } - - if (res.data.results.length === 0) { - return post(endpoint, data); - } - - return Promise.reject(new Error(`unexpected response: ${res}`)); - }); - - return store[lookup].then(created => created.data); -}; - -const getOrganization = (namespace = session) => getOrCreate('/organizations/', { - name: `${namespace}-organization`, - description: namespace -}); - -const getInventory = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/inventories/', { - name: `${namespace}-inventory`, - description: namespace, - organization: organization.id - }).then(inventory => getOrCreate('/hosts/', { - name: `${namespace}-host`, - description: namespace, - inventory: inventory.id, - variables: JSON.stringify({ ansible_connection: 'local' }), - }, ['name', 'inventory']).then(() => inventory))); - -const getHost = (namespace = session) => getInventory(namespace) - .then(inventory => getOrCreate('/hosts/', { - name: `${namespace}-host`, - description: namespace, - inventory: inventory.id, - variables: JSON.stringify({ ansible_connection: 'local' }), - }, ['name', 'inventory'])); - -const getInventoryScript = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/inventory_scripts/', { - name: `${namespace}-inventory-script`, - description: namespace, - organization: organization.id, - script: '#!/usr/bin/env python' - })); - -const getInventorySource = (namespace = session) => { - const promises = [ - getInventory(namespace), - getInventoryScript(namespace) - ]; - - return Promise.all(promises) - .then(([inventory, inventoryScript]) => getOrCreate('/inventory_sources/', { - name: `${namespace}-inventory-source-custom`, - description: namespace, - source: 'custom', - inventory: inventory.id, - source_script: inventoryScript.id - })); -}; - -const getAdminAWSCredential = (namespace = session) => { - const promises = [ - get('/me/'), - getOrCreate('/credential_types/', { - name: 'Amazon Web Services' - }) - ]; - - return Promise.all(promises) - .then(([me, credentialType]) => { - const [admin] = me.data.results; - - return getOrCreate('/credentials/', { - name: `${namespace}-credential-aws`, - description: namespace, - credential_type: credentialType.id, - user: admin.id, - inputs: { - username: 'admin', - password: 'password', - security_token: 'AAAAAAAAAAAAAAAA' - } - }); - }); -}; - -const getAdminMachineCredential = (namespace = session) => { - const promises = [ - get('/me/'), - getOrCreate('/credential_types/', { name: 'Machine' }) - ]; - - return Promise.all(promises) - .then(([me, credentialType]) => { - const [admin] = me.data.results; - return getOrCreate('/credentials/', { - name: `${namespace}-credential-machine-admin`, - description: namespace, - credential_type: credentialType.id, - user: admin.id - }); - }); -}; - -const getTeam = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/teams/', { - name: `${namespace}-team`, - description: namespace, - organization: organization.id, - })); - -const getSmartInventory = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/inventories/', { - name: `${namespace}-smart-inventory`, - description: namespace, - organization: organization.id, - host_filter: 'search=localhost', - kind: 'smart' - })); - -const getNotificationTemplate = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/notification_templates/', { - name: `${namespace}-notification-template`, - description: namespace, - organization: organization.id, - notification_type: 'slack', - notification_configuration: { - token: '54321GFEDCBAABCDEFG12345', - channels: ['awx-e2e'] - } - })); - -const getProject = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/projects/', { - name: `${namespace}-project`, - description: namespace, - organization: organization.id, - scm_url: 'https://github.com/ansible/ansible-tower-samples', - scm_type: 'git' - })); - -const waitForJob = endpoint => { - const interval = 2000; - const statuses = ['successful', 'failed', 'error', 'canceled']; - - let attempts = 20; - - return new Promise((resolve, reject) => { - (function pollStatus () { - get(endpoint).then(update => { - const completed = statuses.indexOf(update.data.status) > -1; - - if (completed) { - return resolve(update.data); - } - - if (--attempts <= 0) { - return reject(new Error('Retry limit exceeded.')); - } - - return setTimeout(pollStatus, interval); - }); - }()); - }); -}; - -const getUpdatedProject = (namespace = session) => getProject(namespace) - .then(project => { - const updateURL = project.related.current_update; - - if (updateURL) { - return waitForJob(updateURL).then(() => project); - } - - return project; - }); - -const getJob = (namespace = session) => getJobTemplate(namespace) - .then(template => { - const launchURL = template.related.launch; - return post(launchURL, {}).then(response => { - const jobURL = response.data.url; - return waitForJob(jobURL).then(() => response.data); - }); - }); - -const getJobTemplate = (namespace = session) => { - const promises = [ - getInventory(namespace), - getAdminMachineCredential(namespace), - getUpdatedProject(namespace) - ]; - - return Promise.all(promises) - .then(([inventory, credential, project]) => getOrCreate('/job_templates/', { - name: `${namespace}-job-template`, - description: namespace, - inventory: inventory.id, - credential: credential.id, - project: project.id, - playbook: 'hello_world.yml', - })); -}; - -const getWorkflowTemplate = (namespace = session) => { - const endpoint = '/workflow_job_templates/'; - - const workflowTemplatePromise = getOrganization(namespace) - .then(organization => getOrCreate(endpoint, { - name: `${namespace}-workflow-template`, - organization: organization.id, - variables: '---', - extra_vars: '', - })); - - const resources = [ - workflowTemplatePromise, - getInventorySource(namespace), - getUpdatedProject(namespace), - getJobTemplate(namespace), - ]; - - const workflowNodePromise = Promise.all(resources) - .then(([workflowTemplate, source, project, jobTemplate]) => { - const workflowNodes = workflowTemplate.related.workflow_nodes; - const unique = 'unified_job_template'; - - const nodes = [ - getOrCreate(workflowNodes, { [unique]: project.id }, [unique]), - getOrCreate(workflowNodes, { [unique]: jobTemplate.id }, [unique]), - getOrCreate(workflowNodes, { [unique]: source.id }, [unique]), - ]; - - const createSuccessNodes = ([projectNode, jobNode, sourceNode]) => Promise.all([ - getOrCreate(projectNode.related.success_nodes, { id: jobNode.id }, ['id']), - getOrCreate(jobNode.related.success_nodes, { id: sourceNode.id }, ['id']), - ]); - - return Promise.all(nodes) - .then(createSuccessNodes); - }); - - return Promise.all([workflowTemplatePromise, workflowNodePromise]) - .then(([workflowTemplate, nodes]) => workflowTemplate); -}; - -const getAuditor = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/users/', { - username: `auditor-${uuid().substr(0, 8)}`, - organization: organization.id, - first_name: 'auditor', - last_name: 'last', - email: 'null@ansible.com', - is_superuser: false, - is_system_auditor: true, - password: AWX_E2E_PASSWORD - }, ['username'])); - -const getUser = (namespace = session) => getOrganization(namespace) - .then(organization => getOrCreate('/users/', { - username: `user-${uuid().substr(0, 8)}`, - organization: organization.id, - first_name: 'firstname', - last_name: 'lastname', - email: 'null@ansible.com', - is_superuser: false, - is_system_auditor: false, - password: AWX_E2E_PASSWORD - }, ['username'])); - -const getJobTemplateAdmin = (namespace = session) => { - const rolePromise = getJobTemplate(namespace) - .then(obj => obj.summary_fields.object_roles.admin_role); - - const userPromise = getOrganization(namespace) - .then(obj => getOrCreate('/users/', { - username: `job-template-admin-${uuid().substr(0, 8)}`, - organization: obj.id, - first_name: 'firstname', - last_name: 'lastname', - email: 'null@ansible.com', - is_superuser: false, - is_system_auditor: false, - password: AWX_E2E_PASSWORD - }, ['username'])); - - const assignRolePromise = Promise.all([userPromise, rolePromise]) - .then(([user, role]) => post(`/api/v2/roles/${role.id}/users/`, { id: user.id })); - - return Promise.all([userPromise, assignRolePromise]) - .then(([user, assignment]) => user); -}; - -const getProjectAdmin = (namespace = session) => { - const rolePromise = getUpdatedProject(namespace) - .then(obj => obj.summary_fields.object_roles.admin_role); - - const userPromise = getOrganization(namespace) - .then(obj => getOrCreate('/users/', { - username: `project-admin-${uuid().substr(0, 8)}`, - organization: obj.id, - first_name: 'firstname', - last_name: 'lastname', - email: 'null@ansible.com', - is_superuser: false, - is_system_auditor: false, - password: AWX_E2E_PASSWORD - }, ['username'])); - - const assignRolePromise = Promise.all([userPromise, rolePromise]) - .then(([user, role]) => post(`/api/v2/roles/${role.id}/users/`, { id: user.id })); - - return Promise.all([userPromise, assignRolePromise]) - .then(([user, assignment]) => user); -}; - -const getInventorySourceSchedule = (namespace = session) => getInventorySource(namespace) - .then(source => getOrCreate(source.related.schedules, { - name: `${source.name}-schedule`, - description: namespace, - rrule: 'DTSTART:20171104T040000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' - })); - -const getJobTemplateSchedule = (namespace = session) => getJobTemplate(namespace) - .then(template => getOrCreate(template.related.schedules, { - name: `${template.name}-schedule`, - description: namespace, - rrule: 'DTSTART:20351104T040000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' - })); - -module.exports = { - getAdminAWSCredential, - getAdminMachineCredential, - getAuditor, - getHost, - getInventory, - getInventoryScript, - getInventorySource, - getInventorySourceSchedule, - getJob, - getJobTemplate, - getJobTemplateAdmin, - getJobTemplateSchedule, - getNotificationTemplate, - getOrganization, - getOrCreate, - getProject, - getProjectAdmin, - getSmartInventory, - getTeam, - getUpdatedProject, - getUser, - getWorkflowTemplate, -}; diff --git a/awx/ui/test/e2e/nightwatch.conf.js b/awx/ui/test/e2e/nightwatch.conf.js deleted file mode 100644 index 67566c893271..000000000000 --- a/awx/ui/test/e2e/nightwatch.conf.js +++ /dev/null @@ -1,56 +0,0 @@ -import path from 'path'; - -import chromedriver from 'chromedriver'; - -import { - AWX_E2E_CLUSTER_HOST, - AWX_E2E_CLUSTER_PORT, - AWX_E2E_CLUSTER_WORKERS, - AWX_E2E_LAUNCH_URL, - AWX_E2E_TIMEOUT_ASYNC, - AWX_E2E_TIMEOUT_MEDIUM -} from './settings'; - -const resolve = location => path.resolve(__dirname, location); - -module.exports = { - src_folders: [resolve('tests')], - output_folder: resolve('reports'), - custom_commands_path: resolve('commands'), - page_objects_path: resolve('objects'), - test_settings: { - default: { - selenium_host: 'localhost', - selenium_port: 9515, - default_path_prefix: '', - desiredCapabilities: { browserName: 'chrome' }, - test_workers: { enabled: false }, - globals: { - launch_url: AWX_E2E_LAUNCH_URL, - retryAssertionTimeout: AWX_E2E_TIMEOUT_MEDIUM, - waitForConditionTimeout: AWX_E2E_TIMEOUT_MEDIUM, - asyncHookTimeout: AWX_E2E_TIMEOUT_ASYNC, - before (done) { - chromedriver.start(['--port=9515']); - done(); - }, - after (done) { - chromedriver.stop(); - done(); - } - } - }, - // Note: These are environment-specific overrides to the default - // test settings defined above. - cluster: { - selenium_host: AWX_E2E_CLUSTER_HOST, - selenium_port: AWX_E2E_CLUSTER_PORT, - default_path_prefix: '/wd/hub', - test_workers: { - enabled: (AWX_E2E_CLUSTER_WORKERS > 0), - workers: AWX_E2E_CLUSTER_WORKERS - }, - globals: { before: {}, after: {} } - } - } -}; diff --git a/awx/ui/test/e2e/objects/activityStream.js b/awx/ui/test/e2e/objects/activityStream.js deleted file mode 100644 index 961ef6056e5a..000000000000 --- a/awx/ui/test/e2e/objects/activityStream.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/activity_stream`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - elements: { - title: '.List-titleText', - subtitle: '.List-titleLockup', - category: '#stream-dropdown-nav' - } -}; diff --git a/awx/ui/test/e2e/objects/configuration.js b/awx/ui/test/e2e/objects/configuration.js deleted file mode 100644 index fdf45677a967..000000000000 --- a/awx/ui/test/e2e/objects/configuration.js +++ /dev/null @@ -1,40 +0,0 @@ -import breadcrumb from './sections/breadcrumb'; -import header from './sections/header'; -import navigation from './sections/navigation'; - -const sections = { - header, - navigation, - breadcrumb, -}; - -const commands = [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - selectSubcategory (name) { - const spinny = 'div.spinny'; - const select = '#configure-dropdown-nav'; - const arrow = `${select} + span span[class$="arrow"]`; - const option = `//li[contains(text(), "${name}")]`; - - this.api.waitForElementVisible(arrow); - this.api.click(arrow); - - this.api.useXpath(); - this.api.waitForElementVisible(option); - this.api.click(option); - this.api.useCss(); - - return this; - }, -}]; - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/configuration`; - }, - sections, - commands, -}; diff --git a/awx/ui/test/e2e/objects/credentialTypes.js b/awx/ui/test/e2e/objects/credentialTypes.js deleted file mode 100644 index 7ea9ec298d1b..000000000000 --- a/awx/ui/test/e2e/objects/credentialTypes.js +++ /dev/null @@ -1,68 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import search from './sections/search'; -import pagination from './sections/pagination'; - -const addEditPanel = { - selector: 'div[ui-view="form"]', - elements: { - title: 'div[class="Form-title"]', - }, - sections: { - details: createFormSection({ - selector: '#credential_type_form', - labels: { - name: 'Name', - description: 'Description', - inputConfiguration: 'Input Configuration', - injectorConfiguration: 'Injector Configuration' - }, - strategy: 'legacy' - }) - } -}; - -const listPanel = { - selector: 'div[ui-view="list"]', - elements: { - add: '#button-add', - badge: 'div[class="List-titleBadge]', - titleText: 'div[class="List-titleText"]', - noitems: 'div[class="List-noItems"]' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - kind: 'td[class~="kind-column"]', - }, - sections: { - actions - } - }) - } -}; - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/credential_types`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - breadcrumb, - add: addEditPanel, - edit: addEditPanel, - list: listPanel - } -}; diff --git a/awx/ui/test/e2e/objects/credentials.js b/awx/ui/test/e2e/objects/credentials.js deleted file mode 100644 index cc2c45ff9d7f..000000000000 --- a/awx/ui/test/e2e/objects/credentials.js +++ /dev/null @@ -1,271 +0,0 @@ -import _ from 'lodash'; - -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import dynamicSection from './sections/dynamicSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const common = createFormSection({ - selector: 'form', - labels: { - name: 'Name', - description: 'Description', - organization: 'Organization', - type: 'Credential type' - } -}); - -const machine = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - username: 'Username', - password: 'Password', - sshKeyData: 'SSH Private Key', - sshKeyUnlock: 'Private Key Passphrase', - becomeMethod: 'Privilege Escalation Method', - becomeUsername: 'Privilege Escalation Username', - becomePassword: 'Privilege Escalation Password' - } -}); - -const vault = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - vaultPassword: 'Vault Password', - vaultIdentifier: 'Vault Identifier' - } -}); - -const scm = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - username: 'Username', - password: 'Password', - sshKeyData: 'SCM Private Key', - sshKeyUnlock: 'Private Key Passphrase', - } -}); - -const aws = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - accessKey: 'Access Key', - secretKey: 'Secret Key', - securityToken: 'STS Token', - } -}); - -const gce = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - email: 'Service Account Email Address', - project: 'Project', - sshKeyData: 'RSA Private Key', - serviceAccountFile: 'Service Account JSON File' - } -}); - -const vmware = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - host: 'VCenter Host', - username: 'Username', - password: 'Password', - } -}); - -const azureClassic = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - subscription: 'Subscription ID', - sshKeyData: 'Management Certificate', - } -}); - -const azure = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - subscription: 'Subscription ID', - username: 'Username', - password: 'Password', - client: 'Client ID', - secret: 'Client Secret', - tenant: 'Tenant ID', - } -}); - -const openStack = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - username: 'Username', - password: 'Password (API Key)', - host: 'Host (Authentication URL)', - project: 'Project (Tenant Name)', - domain: 'Domain Name', - } -}); - -const rackspace = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - username: 'Username', - password: 'Password', - } -}); - -const cloudForms = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - host: 'Cloudforms URL', - username: 'Username', - password: 'Password', - } -}); - -const network = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - sshKeyData: 'SSH Private Key', - sshKeyUnlock: 'Private Key Passphrase', - username: 'Username', - password: 'Password', - authorizePassword: 'Authorize Password', - } -}); - -network.elements.authorize = { - locateStrategy: 'xpath', - selector: '//input[../p/text() = "Authorize"]' -}; - -const sat6 = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - host: 'Satellite 6 URL', - username: 'Username', - password: 'Password', - } -}); - -const insights = createFormSection({ - selector: '.at-InputGroup-inset', - labels: { - username: 'Username', - password: 'Password', - }, -}); - -const details = _.merge({}, common, { - elements: { - cancel: '.btn[type="cancel"]', - save: '.btn[type="save"]', - }, - sections: { - aws, - azure, - azureClassic, - cloudForms, - dynamicSection, - gce, - insights, - machine, - network, - rackspace, - sat6, - scm, - openStack, - vault, - vmware - }, - commands: [{ - custom ({ name, inputs }) { - const labels = {}; - inputs.fields.forEach(f => { labels[f.id] = f.label; }); - - const selector = '.at-InputGroup-inset'; - const generated = createFormSection({ selector, labels }); - - const params = _.merge({ name }, generated); - return this.section.dynamicSection.create(params); - }, - clear () { - this.clearValue('@name'); - this.clearValue('@organization'); - this.clearValue('@description'); - this.clearValue('@type'); - this.waitForElementNotVisible('.at-InputGroup-inset'); - return this; - }, - clearAndSelectType (type) { - this.clear(); - this.setValue('@type', type); - this.waitForElementVisible('.at-InputGroup-inset'); - return this; - } - }] -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/credentials`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="add"]', - sections: { - details - }, - elements: { - title: 'h3[class="at-Panel-headingTitle"]' - } - }, - edit: { - selector: 'div[ui-view="edit"]', - sections: { - details, - permissions - }, - elements: { - title: 'h3[class="at-Panel-headingTitle"]' - } - }, - list: { - selector: 'div[ui-view="list"]', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - kind: 'td[class~="kind-column"]' - }, - sections: { - actions - } - }) - } - }, - } -}; diff --git a/awx/ui/test/e2e/objects/dashboard.js b/awx/ui/test/e2e/objects/dashboard.js deleted file mode 100644 index ca6695ca5c2c..000000000000 --- a/awx/ui/test/e2e/objects/dashboard.js +++ /dev/null @@ -1,24 +0,0 @@ -import breadcrumb from './sections/breadcrumb'; -import header from './sections/header'; -import navigation from './sections/navigation'; - -const sections = { - header, - navigation, - breadcrumb, -}; - -const commands = [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - } -}]; - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/home`; - }, - sections, - commands, -}; diff --git a/awx/ui/test/e2e/objects/inventories.js b/awx/ui/test/e2e/objects/inventories.js deleted file mode 100644 index dd60b80164be..000000000000 --- a/awx/ui/test/e2e/objects/inventories.js +++ /dev/null @@ -1,136 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const standardInvDetails = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#inventory_form .Form-textInput', - '#inventory_form select.Form-dropDown', - '#inventory_form .Form-textArea', - '#inventory_form input[type="checkbox"]', - '#inventory_form .ui-spinner-input', - '#inventory_form .ScheduleToggle-switch' - ] - }, - labels: { - name: 'Name', - description: 'Description', - organization: 'Organization' - } -}); - -const smartInvDetails = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#smartinventory_form input.Form-textInput', - '#smartinventory_form textarea.Form-textArea', - '#smartinventory_form .Form-lookupButton', - '#smartinventory_form #InstanceGroups' - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/inventories`; - }, - sections: { - header, - navigation, - breadcrumb, - lookupModal, - addStandardInventory: { - selector: 'div[ui-view="form"]', - sections: { - standardInvDetails - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - editStandardInventory: { - selector: 'div[ui-view="form"]', - sections: { - standardInvDetails, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - addSmartInventory: { - selector: 'div[ui-view="form"]', - sections: { - smartInvDetails - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - editSmartInventory: { - selector: 'div[ui-view="form"]', - sections: { - smartInvDetails, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: '.Panel', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: 'button[class~="List-dropdownButton"]' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - status: 'td[class~="status-column"]', - name: 'td[class~="name-column"]', - kind: 'td[class~="kind-column"]', - organization: 'td[class~="organization-column"]' - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - selectAdd (name) { - this.api.waitForElementVisible('#button-add'); - this.expect.element('#button-add').enabled; - this.api.click('#button-add'); - - this.api.useXpath(); - this.api.waitForElementVisible(`.//a[normalize-space(text())="${name}"]`); - this.api.click(`//a[normalize-space(text())="${name}"]`); - this.api.useCss(); - - return this; - } - }] -}; diff --git a/awx/ui/test/e2e/objects/inventoryScripts.js b/awx/ui/test/e2e/objects/inventoryScripts.js deleted file mode 100644 index e2f49fe1cca0..000000000000 --- a/awx/ui/test/e2e/objects/inventoryScripts.js +++ /dev/null @@ -1,83 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#inventory_script_form .Form-textInput', - '#inventory_script_form .Form-textArea', - '#inventory_script_form .Form-lookupButton' - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/inventory_scripts`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: 'div[ui-view="list"]', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - organization: 'td[class~="organization-column"]', - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/objects/jobs.js b/awx/ui/test/e2e/objects/jobs.js deleted file mode 100644 index 8e1b3fe82e3e..000000000000 --- a/awx/ui/test/e2e/objects/jobs.js +++ /dev/null @@ -1,15 +0,0 @@ -import _ from 'lodash'; - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/jobs`; - }, - sections: {}, // TODO: Fill this out - elements: {}, // TODO: Fill this out - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], -}; diff --git a/awx/ui/test/e2e/objects/login.js b/awx/ui/test/e2e/objects/login.js deleted file mode 100644 index 75623f130097..000000000000 --- a/awx/ui/test/e2e/objects/login.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/login`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - elements: { - username: '#login-username', - password: '#login-password', - submit: '#login-button', - logo: '#main_menu_logo' - } -}; diff --git a/awx/ui/test/e2e/objects/notificationTemplates.js b/awx/ui/test/e2e/objects/notificationTemplates.js deleted file mode 100644 index 9dd80df53fb8..000000000000 --- a/awx/ui/test/e2e/objects/notificationTemplates.js +++ /dev/null @@ -1,88 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#notification_template_form .Form-textInput', - '#notification_template_form select.Form-dropDown', - '#notification_template_form input[type="checkbox"]', - '#notification_template_form input[type="radio"]', - '#notification_template_form .ui-spinner-input', - '#notification_template_form .Form-textArea', - '#notification_template_form .ScheduleToggle-switch', - '#notification_template_form .Form-lookupButton' - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/notification_templates`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: 'div[ui-view="list"]', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - organization: 'td[class~="organization-column"]', - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/objects/organizations.js b/awx/ui/test/e2e/objects/organizations.js deleted file mode 100644 index 40fef9a2567b..000000000000 --- a/awx/ui/test/e2e/objects/organizations.js +++ /dev/null @@ -1,76 +0,0 @@ -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#organization_form input.Form-textInput', - '#organization_form .Form-lookupButton', - '#organization_form #InstanceGroups' - ] - }, - labels: { - name: 'Name', - description: 'Description' - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/organizations`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: '#organizations', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/objects/projects.js b/awx/ui/test/e2e/objects/projects.js deleted file mode 100644 index 85965c4019f4..000000000000 --- a/awx/ui/test/e2e/objects/projects.js +++ /dev/null @@ -1,86 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#project_form .Form-textInput', - '#project_form select.Form-dropDown', - '#project_form input[type="checkbox"]', - '#project_form .ui-spinner-input', - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/projects`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: '.Panel', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - status: 'td[class~="status-column"]', - name: 'td[class~="name-column"]', - scm_type: 'td[class~="scm_type-column"]', - last_updated: 'td[class~="last_updated-column"]' - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/objects/sections/actions.js b/awx/ui/test/e2e/objects/sections/actions.js deleted file mode 100644 index afa182e9b00a..000000000000 --- a/awx/ui/test/e2e/objects/sections/actions.js +++ /dev/null @@ -1,15 +0,0 @@ -const actions = { - selector: 'td[class="List-actionsContainer"]', - elements: { - launch: 'i[class="fa icon-launch"]', - schedule: 'i[class="fa icon-schedule"]', - copy: 'i[class="fa icon-copy"]', - edit: 'i[class="fa icon-pencil"]', - delete: 'i[class="fa icon-trash-o"]', - view: 'i[class="fa fa-search-plus"]', - sync: 'i[class="fa fa-cloud-download"]', - test: 'i[class="fa fa-bell-o' - } -}; - -module.exports = actions; diff --git a/awx/ui/test/e2e/objects/sections/breadcrumb.js b/awx/ui/test/e2e/objects/sections/breadcrumb.js deleted file mode 100644 index 62231b95c225..000000000000 --- a/awx/ui/test/e2e/objects/sections/breadcrumb.js +++ /dev/null @@ -1,8 +0,0 @@ -const breadcrumb = { - selector: 'bread-crumb > div', - elements: { - activity: 'i[class$="icon-activity-stream"]' - } -}; - -module.exports = breadcrumb; diff --git a/awx/ui/test/e2e/objects/sections/createFormSection.js b/awx/ui/test/e2e/objects/sections/createFormSection.js deleted file mode 100644 index 97e4b73394b2..000000000000 --- a/awx/ui/test/e2e/objects/sections/createFormSection.js +++ /dev/null @@ -1,129 +0,0 @@ -import { merge } from 'lodash'; - -const translated = "translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"; -const normalized = `normalize-space(${translated})`; - -const inputContainerElements = { - lookup: 'button > i[class="fa fa-search"]', - error: '.at-InputMessage--rejected', - help: 'i[class$="fa-question-circle"]', - hint: '.at-InputLabel-hint', - label: 'label', - popover: '.at-Popover-container', - yaml: 'input[type="radio", value="yaml"]', - json: 'input[type="radio", value="json"]', - reset: 'a[class~="reset"]', - down: 'span[class^="fa-angle-down"]', - up: 'span[class^="fa-angle-up"]', - prompt: { - locateStrategy: 'xpath', - selector: `.//p[${normalized}='prompt on launch']/preceding-sibling::input` - }, - show: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='show']` - }, - hide: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='hide']` - }, - on: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='on']` - }, - off: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='off']` - }, - replace: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='replace']` - }, - revert: { - locateStrategy: 'xpath', - selector: `.//button[${normalized}='revert']` - } -}; - -const legacyContainerElements = merge({}, inputContainerElements, { - prompt: { - locateStrategy: 'xpath', - selector: `.//label[${normalized}='prompt on launch']/input` - }, - error: 'div[class~="error"]', - popover: ':root div[id^="popover"]', -}); - -const generateInputSelectors = (label, containerElements) => { - // descend until span with matching text attribute is encountered - const span = `.//span[text()="${label}"]`; - // recurse upward until div with form-group in class attribute is encountered - const container = `${span}/ancestor::div[contains(@class, 'form-group')]`; - // descend until element with form-control in class attribute is encountered - const input = `${container}//*[contains(@class, 'form-control')]`; - - const inputContainer = { - locateStrategy: 'xpath', - selector: container, - elements: containerElements - }; - - const inputElement = { - locateStrategy: 'xpath', - selector: input - }; - - return { inputElement, inputContainer }; -}; - -function checkAllFieldsDisabled () { - const client = this.client.api; - - const selectors = this.props.formElementSelectors ? this.props.formElementSelectors : [ - '.at-Input' - ]; - - selectors.forEach(selector => { - client.elements('css selector', selector, inputs => { - inputs.value.map(o => o.ELEMENT).forEach(id => { - client.elementIdAttribute(id, 'disabled', ({ value }) => { - client.assert.equal(value, 'true'); - }); - }); - }); - }); -} - -const generatorOptions = { - default: inputContainerElements, - legacy: legacyContainerElements -}; - -const createFormSection = ({ selector, labels, strategy, props }) => { - const options = generatorOptions[strategy || 'default']; - - const formSection = { - props, - selector, - sections: {}, - elements: {}, - commands: [{ checkAllFieldsDisabled }] - }; - - if (!labels) { - return formSection; - } - - Object.keys(labels) - .forEach(key => { - const label = labels[key]; - const { inputElement, inputContainer } = generateInputSelectors(label, options); - - formSection.elements[key] = inputElement; - formSection.sections[key] = inputContainer; - }); - - return formSection; -}; - -module.exports = createFormSection; diff --git a/awx/ui/test/e2e/objects/sections/createTableSection.js b/awx/ui/test/e2e/objects/sections/createTableSection.js deleted file mode 100644 index 96607940e50e..000000000000 --- a/awx/ui/test/e2e/objects/sections/createTableSection.js +++ /dev/null @@ -1,76 +0,0 @@ -import dynamicSection from './dynamicSection'; - -const header = { - selector: 'thead', - sections: { - dynamicSection - }, - commands: [{ - findColumnByText (text) { - return this.section.dynamicSection.create({ - name: `column[${text}]`, - locateStrategy: 'xpath', - selector: `.//*[normalize-space(text())='${text}']/ancestor-or-self::th`, - elements: { - sortable: { - locateStrategy: 'xpath', - selector: './/*[contains(@class, "fa-sort")]' - }, - sorted: { - locateStrategy: 'xpath', - selector: './/*[contains(@class, "fa-sort-")]' - }, - } - }); - } - }] -}; - -const createTableSection = ({ elements, sections, commands }) => { - const tableSection = { - selector: 'table', - sections: { - header, - dynamicSection - }, - commands: [{ - findRowByText (text) { - return this.section.dynamicSection.create({ - elements, - sections, - commands, - name: `row[${text}]`, - locateStrategy: 'xpath', - selector: `.//tbody/tr/td//*[normalize-space(text())='${text}']/ancestor::tr` - }); - }, - findRowByIndex (index) { - return this.section.dynamicSection.create({ - elements, - sections, - commands, - name: `row[${index}]`, - locateStrategy: 'xpath', - selector: `.//tbody/tr[${index}]` - }); - }, - clickRowByIndex (index) { - this.findRowByIndex(index).click('@self'); - return this; - }, - waitForRowCount (count) { - const countReached = this.findRowByIndex(count); - countReached.waitForElementVisible('@self', 10000); - - const countExceeded = this.findRowByIndex(count + 1); - countExceeded.waitForElementNotPresent('@self', 10000); - - return this; - } - }] - }; - - return tableSection; -}; - -module.exports = createTableSection; diff --git a/awx/ui/test/e2e/objects/sections/dynamicSection.js b/awx/ui/test/e2e/objects/sections/dynamicSection.js deleted file mode 100644 index 347806631829..000000000000 --- a/awx/ui/test/e2e/objects/sections/dynamicSection.js +++ /dev/null @@ -1,26 +0,0 @@ -const dynamicSection = { - selector: '.', - commands: [{ - create ({ name, locateStrategy, selector, elements, sections, commands }) { - const Section = this.constructor; - - const options = Object.assign(Object.create(this), { - name, - locateStrategy, - elements, - selector, - sections, - commands - }); - - options.elements.self = { - locateStrategy: 'xpath', - selector: '.' - }; - - return new Section(options); - } - }] -}; - -module.exports = dynamicSection; diff --git a/awx/ui/test/e2e/objects/sections/header.js b/awx/ui/test/e2e/objects/sections/header.js deleted file mode 100644 index ceea0f004bda..000000000000 --- a/awx/ui/test/e2e/objects/sections/header.js +++ /dev/null @@ -1,11 +0,0 @@ -const header = { - selector: 'div[class="at-Layout-topNav"]', - elements: { - logo: 'div[class$="logo"] img', - user: 'i[class="fa fa-user"] + span', - documentation: 'i[class="fa fa-book"]', - logout: 'i[class="fa fa-power-off"]', - } -}; - -module.exports = header; diff --git a/awx/ui/test/e2e/objects/sections/lookupModal.js b/awx/ui/test/e2e/objects/sections/lookupModal.js deleted file mode 100644 index 4f345113236f..000000000000 --- a/awx/ui/test/e2e/objects/sections/lookupModal.js +++ /dev/null @@ -1,27 +0,0 @@ -import createTableSection from './createTableSection'; -import pagination from './pagination'; -import search from './search'; - -const lookupModal = { - selector: '#form-modal', - elements: { - close: 'i[class="fa fa-times-circle"]', - title: 'div[class^="Form-title"]', - select: 'button[class*="save"]', - cancel: 'button[class*="cancel"]', - save: 'button[class*="save"]' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - selected: 'input[type="radio", value="1"]', - } - - }) - } -}; - -module.exports = lookupModal; diff --git a/awx/ui/test/e2e/objects/sections/navigation.js b/awx/ui/test/e2e/objects/sections/navigation.js deleted file mode 100644 index 2ac257f1ddf6..000000000000 --- a/awx/ui/test/e2e/objects/sections/navigation.js +++ /dev/null @@ -1,25 +0,0 @@ -const navigation = { - selector: 'div[class^="at-Layout-side"]', - elements: { - expand: 'i[class$="fa-bars"]', - dashboard: 'i[class$="fa-tachometer"]', - jobs: 'i[class$="fa-spinner"]', - schedules: 'i[class$="fa-calendar"]', - portal: 'i[class$="fa-columns"]', - projects: 'i[class$="fa-folder-open"]', - credentials: 'i[class$="fa-key"]', - credentialTypes: 'i[class$="fa-list-alt"]', - inventories: 'i[class$="fa-sitemap"]', - templates: 'i[class$="fa-pencil-square-o"]', - organizations: 'i[class$="fa-building"]', - users: 'i[class$="fa-user"]', - teams: 'i[class$="fa-users"]', - inventoryScripts: 'i[class$="fa-code"]', - notifications: 'i[class$="fa-bell"]', - managementJobs: 'i[class$="fa-wrench"]', - instanceGroups: 'i[class$="fa-server"]', - settings: 'i[class$="fa-cog"]', - } -}; - -module.exports = navigation; diff --git a/awx/ui/test/e2e/objects/sections/pagination.js b/awx/ui/test/e2e/objects/sections/pagination.js deleted file mode 100644 index 5973ff2dd44a..000000000000 --- a/awx/ui/test/e2e/objects/sections/pagination.js +++ /dev/null @@ -1,13 +0,0 @@ -const pagination = { - selector: 'paginate div', - elements: { - first: 'i[class="fa fa-angle-double-left"]', - previous: 'i[class="fa fa-angle-left"]', - next: 'i[class="fa fa-angle-right"]', - last: 'i[class="fa fa-angle-double-right"]', - pageCount: 'span[class~="pageof"]', - itemCount: 'span[class~="itemsOf"]', - } -}; - -module.exports = pagination; diff --git a/awx/ui/test/e2e/objects/sections/permissions.js b/awx/ui/test/e2e/objects/sections/permissions.js deleted file mode 100644 index 958568157ba4..000000000000 --- a/awx/ui/test/e2e/objects/sections/permissions.js +++ /dev/null @@ -1,28 +0,0 @@ -import actions from './actions'; -import createTableSection from './createTableSection'; -import pagination from './pagination'; -import search from './search'; - -const permissions = { - selector: 'div[ui-view="related"]', - elements: { - add: '#button-add', - badge: 'div[class="List-titleBadge]', - titleText: 'div[class="List-titleText"]', - noitems: 'div[class="List-noItems"]' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - username: 'td[class~="username"]', - roles: 'td role-list:nth-of-type(1)', - teamRoles: 'td role-list:nth-of-type(2)' - }, - sections: { actions } - }) - } -}; - -module.exports = permissions; diff --git a/awx/ui/test/e2e/objects/sections/search.js b/awx/ui/test/e2e/objects/sections/search.js deleted file mode 100644 index 9feed8155429..000000000000 --- a/awx/ui/test/e2e/objects/sections/search.js +++ /dev/null @@ -1,12 +0,0 @@ -const search = { - selector: 'smart-search', - locateStrategy: 'css selector', - elements: { - clearAll: 'a[class*="clear"]', - searchButton: 'i[class$="search"]', - input: 'input', - tags: '.SmartSearch-tagContainer' - } -}; - -module.exports = search; diff --git a/awx/ui/test/e2e/objects/teams.js b/awx/ui/test/e2e/objects/teams.js deleted file mode 100644 index 485206b00cf6..000000000000 --- a/awx/ui/test/e2e/objects/teams.js +++ /dev/null @@ -1,82 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#team_form input.Form-textInput', - '#team_form .Form-lookupButton' - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/teams`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: 'div[ui-view="list"]', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - organization: 'td[class~="organization-column"]' - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/objects/templates.js b/awx/ui/test/e2e/objects/templates.js deleted file mode 100644 index 062d62c0ce64..000000000000 --- a/awx/ui/test/e2e/objects/templates.js +++ /dev/null @@ -1,267 +0,0 @@ -import _ from 'lodash'; - -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#job_template_form .Form-textInput', - '#job_template_form select.Form-dropDown', - '#job_template_form .Form-textArea', - '#job_template_form input[type="checkbox"]', - '#job_template_form .ui-spinner-input', - '#job_template_form .ScheduleToggle-switch' - ] - }, - labels: { - name: 'Name', - description: 'Description', - playbook: 'Playbook' - - } -}); - -const lookupInventory = _.merge({}, lookupModal, { - locateStrategy: 'xpath', - selector: './/div[text()="Select inventory"]/ancestor::div[contains(@class, "modal-content")]' -}); - -const lookupProject = _.merge({}, lookupModal, { - locateStrategy: 'xpath', - selector: './/div[text()="Select project"]/ancestor::div[contains(@class, "modal-content")]' -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/templates`; - }, - sections: { - header, - navigation, - breadcrumb, - lookupInventory, - lookupProject, - addJobTemplate: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - editJobTemplate: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - addWorkflowJobTemplate: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - editWorkflowJobTemplate: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: '.Panel', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - name: 'td[class~="name-column"]', - kind: 'td[class~="type-column"]' - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - clickWhenEnabled (selector) { - this.api.waitForElementVisible(selector); - this.expect.element(selector).enabled; - this.click(selector); - return this; - }, - selectAdd (name) { - this.clickWhenEnabled('#button-add'); - - this.api - .useXpath() - .waitForElementVisible(`.//a[normalize-space(text())="${name}"]`) - .click(`//a[normalize-space(text())="${name}"]`) - .useCss(); - - return this; - }, - selectPlaybook (name) { - this.clickWhenEnabled('label[for="playbook"] + div span[class$="arrow"]'); - - this.api - .useXpath() - .waitForElementVisible(`//li[contains(text(), "${name}")]`) - .click(`//li[contains(text(), "${name}")]`) - .useCss(); - - return this; - }, - selectInventory (name) { - this.clickWhenEnabled('label[for="inventory"] + div i[class$="search"]'); - - this.api - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - this.section.lookupInventory.section.search - .waitForElementVisible('@input') - .waitForElementVisible('@searchButton') - .sendKeys('@input', name) - .click('@searchButton') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - this.section.lookupInventory.section.table - .waitForRowCount(1) - .clickRowByIndex(1); - - this.section.lookupInventory.expect.element('@save').enabled; - - this.section.lookupInventory - .click('@save'); - - return this; - }, - selectProject (name) { - this.clickWhenEnabled('label[for="project"] + div i[class$="search"]'); - - this.api - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - this.section.lookupProject.section.search - .waitForElementVisible('@input') - .waitForElementVisible('@searchButton') - .sendKeys('@input', name) - .click('@searchButton') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - this.section.lookupProject.section.table - .waitForRowCount(1) - .clickRowByIndex(1); - - this.section.lookupProject.expect.element('@save').enabled; - - this.section.lookupProject - .click('@save') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - return this; - }, - selectVaultCredential (name) { - this.clickWhenEnabled('label[for="credential"] + div i[class$="search"]'); - - this.api - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementVisible('#multi-credential-kind-select + span span[class$="arrow"]') - .click('#multi-credential-kind-select + span span[class$="arrow"]') - .useXpath() - .waitForElementVisible('//li[contains(text(), "Vault")]') - .click('//li[contains(text(), "Vault")]') - .useCss() - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementVisible('multi-credential-modal smart-search input') - .waitForElementVisible('multi-credential-modal smart-search i[class$="search"]') - .sendKeys('multi-credential-modal smart-search input', name) - .click('multi-credential-modal smart-search i[class$="search"]') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .click('multi-credential-modal smart-search a[class*="clear"]') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .sendKeys('multi-credential-modal smart-search input', name) - .click('multi-credential-modal smart-search i[class$="search"]') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementNotPresent('multi-credential-modal tbody tr:nth-child(2)') - .waitForElementVisible('multi-credential-modal tbody tr:nth-child(1) input[type="checkbox"]') - .click('multi-credential-modal tbody tr:nth-child(1) input[type="checkbox"]') - .click('multi-credential-modal button[class*="save"]') - .pause(1000); - - return this; - }, - selectMachineCredential (name) { - this.clickWhenEnabled('label[for="credential"] + div i[class$="search"]'); - - this.api - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementVisible('#multi-credential-kind-select + span span[class$="arrow"]') - .click('#multi-credential-kind-select + span span[class$="arrow"]') - .useXpath() - .waitForElementVisible('//li[contains(text(), "Machine")]') - .click('//li[contains(text(), "Machine")]') - .useCss() - .waitForElementVisible('multi-credential-modal smart-search input') - .waitForElementVisible('multi-credential-modal smart-search i[class$="search"]') - .sendKeys('multi-credential-modal smart-search input', name) - .click('multi-credential-modal smart-search i[class$="search"]') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementNotPresent('multi-credential-modal tbody tr:nth-child(2)') - .waitForElementVisible('multi-credential-modal tbody tr:nth-child(1) input[type="radio"]') - .click('multi-credential-modal tbody tr:nth-child(1) input[type="radio"]') - .click('multi-credential-modal button[class*="save"]') - .pause(1000); - - return this; - } - }] -}; diff --git a/awx/ui/test/e2e/objects/users.js b/awx/ui/test/e2e/objects/users.js deleted file mode 100644 index 9b78588a211e..000000000000 --- a/awx/ui/test/e2e/objects/users.js +++ /dev/null @@ -1,83 +0,0 @@ -import actions from './sections/actions'; -import breadcrumb from './sections/breadcrumb'; -import createFormSection from './sections/createFormSection'; -import createTableSection from './sections/createTableSection'; -import header from './sections/header'; -import lookupModal from './sections/lookupModal'; -import navigation from './sections/navigation'; -import pagination from './sections/pagination'; -import permissions from './sections/permissions'; -import search from './sections/search'; - -const details = createFormSection({ - selector: 'form', - props: { - formElementSelectors: [ - '#user_form .Form-textInput', - '#user_form select.Form-dropDown' - ] - } -}); - -module.exports = { - url () { - return `${this.api.globals.launch_url}/#/users`; - }, - commands: [{ - load () { - this.api.url('data:,'); // https://github.com/nightwatchjs/nightwatch/issues/1724 - return this.navigate(); - }, - }], - sections: { - header, - navigation, - breadcrumb, - lookupModal, - add: { - selector: 'div[ui-view="form"]', - sections: { - details - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - edit: { - selector: 'div[ui-view="form"]', - sections: { - details, - permissions - }, - elements: { - title: 'div[class^="Form-title"]' - } - }, - list: { - selector: 'div[ui-view="list"]', - elements: { - badge: 'span[class~="badge"]', - title: 'div[class="List-titleText"]', - add: '#button-add' - }, - sections: { - search, - pagination, - table: createTableSection({ - elements: { - username: 'td[class~="username-column"]', - first_name: 'td[class~="first_name-column"]', - last_name: 'td[class~="last_name-column"]' - }, - sections: { - actions - } - }) - } - } - }, - elements: { - cancel: 'button[class*="Form-cancelButton"]', - save: 'button[class*="Form-saveButton"]' - } -}; diff --git a/awx/ui/test/e2e/runner.js b/awx/ui/test/e2e/runner.js deleted file mode 100755 index 494d059abf3d..000000000000 --- a/awx/ui/test/e2e/runner.js +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node -require('babel-core/register'); -require('nightwatch/bin/runner.js'); diff --git a/awx/ui/test/e2e/settings.js b/awx/ui/test/e2e/settings.js deleted file mode 100644 index acee4dca4de2..000000000000 --- a/awx/ui/test/e2e/settings.js +++ /dev/null @@ -1,25 +0,0 @@ -const AWX_E2E_CLUSTER_HOST = process.env.AWX_E2E_CLUSTER_HOST || 'localhost'; -const AWX_E2E_CLUSTER_PORT = process.env.AWX_E2E_CLUSTER_PORT || 4444; -const AWX_E2E_CLUSTER_WORKERS = process.env.AWX_E2E_CLUSTER_WORKERS || 0; -const AWX_E2E_PASSWORD = process.env.AWX_E2E_PASSWORD || 'password'; -const AWX_E2E_URL = process.env.AWX_E2E_URL || 'https://localhost:8043'; -const AWX_E2E_USERNAME = process.env.AWX_E2E_USERNAME || 'awx-e2e'; -const AWX_E2E_TIMEOUT_ASYNC = process.env.AWX_E2E_TIMEOUT_ASYNC || 90000; -const AWX_E2E_TIMEOUT_LONG = process.env.AWX_E2E_TIMEOUT_LONG || 10000; -const AWX_E2E_TIMEOUT_MEDIUM = process.env.AWX_E2E_TIMEOUT_MEDIUM || 5000; -const AWX_E2E_TIMEOUT_SHORT = process.env.AWX_E2E_TIMEOUT_SHORT || 1000; -const AWX_E2E_LAUNCH_URL = process.env.AWX_E2E_LAUNCH_URL || AWX_E2E_URL; - -module.exports = { - AWX_E2E_CLUSTER_HOST, - AWX_E2E_CLUSTER_PORT, - AWX_E2E_CLUSTER_WORKERS, - AWX_E2E_LAUNCH_URL, - AWX_E2E_PASSWORD, - AWX_E2E_URL, - AWX_E2E_USERNAME, - AWX_E2E_TIMEOUT_ASYNC, - AWX_E2E_TIMEOUT_LONG, - AWX_E2E_TIMEOUT_MEDIUM, - AWX_E2E_TIMEOUT_SHORT -}; diff --git a/awx/ui/test/e2e/tests/gce.alt.json b/awx/ui/test/e2e/tests/gce.alt.json deleted file mode 100644 index 1080223f07a3..000000000000 --- a/awx/ui/test/e2e/tests/gce.alt.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "service_account", - "project_id": "test321", - "private_key_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - "private_key": "-----BEGIN PRIVATE KEY-----\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBB\n-----END PRIVATE KEY-----\n", - "client_email": "test321.iam.gserviceaccount.com", - "client_id": "321987654321987654321", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://accounts.google.com/o/oauth2/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test321%40test.iam.gserviceaccount.com" -} diff --git a/awx/ui/test/e2e/tests/gce.invalid.json b/awx/ui/test/e2e/tests/gce.invalid.json deleted file mode 100644 index 9977a2836c1a..000000000000 --- a/awx/ui/test/e2e/tests/gce.invalid.json +++ /dev/null @@ -1 +0,0 @@ -invalid diff --git a/awx/ui/test/e2e/tests/gce.json b/awx/ui/test/e2e/tests/gce.json deleted file mode 100644 index dd3055f05982..000000000000 --- a/awx/ui/test/e2e/tests/gce.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "service_account", - "project_id": "test123", - "private_key_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "private_key": "-----BEGIN PRIVATE KEY-----\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAA\n-----END PRIVATE KEY-----\n", - "client_email": "test123.iam.gserviceaccount.com", - "client_id": "123456789123456789123", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://accounts.google.com/o/oauth2/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test123%40test.iam.gserviceaccount.com" -} diff --git a/awx/ui/test/e2e/tests/gce.missing.json b/awx/ui/test/e2e/tests/gce.missing.json deleted file mode 100644 index 5d0d1e2968be..000000000000 --- a/awx/ui/test/e2e/tests/gce.missing.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "service_account", - "project_id": "test654", - "private_key_id": "cccccccccccccccccccccccccccccccccccccccc", - "private_key": "-----BEGIN PRIVATE KEY-----\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCC\n-----END PRIVATE KEY-----\n", - "client_id": "654321987654321987654", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://accounts.google.com/o/oauth2/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test654%40test.iam.gserviceaccount.com" -} diff --git a/awx/ui/test/e2e/tests/smoke-vars.yml b/awx/ui/test/e2e/tests/smoke-vars.yml deleted file mode 100644 index 7834c3944fad..000000000000 --- a/awx/ui/test/e2e/tests/smoke-vars.yml +++ /dev/null @@ -1,7 +0,0 @@ -$ANSIBLE_VAULT;1.1;AES256 -36663862313439656164323336396466323737666532643061323738646337623166653338663939 -6365663839623936363566393461643961363963613333650a333463653831386463646564376265 -39376362376231303064326464303738343136643931336432396638333933356337383866326539 -3830316634306466310a366234333566613733633232623434363434376534663466393833666435 -36373961636564353865653162393266383135363362336139613435323464356136393034636539 -6166663537623261336262363732346238343066393861643134 diff --git a/awx/ui/test/e2e/tests/smoke.js b/awx/ui/test/e2e/tests/smoke.js deleted file mode 100644 index deb80a857f19..000000000000 --- a/awx/ui/test/e2e/tests/smoke.js +++ /dev/null @@ -1,277 +0,0 @@ -import uuid from 'uuid'; - -const id = uuid().substr(0, 8); - -const INVENTORY_NAME = `inventory-${id}`; -const MACHINE_CREDENTIAL_NAME = `credential-machine-${id}`; -const ORGANIZATION_NAME = `organization-${id}`; -const PROJECT_NAME = `project-${id}`; -const PROJECT_URL = 'https://github.com/jlaska/ansible-playbooks'; -const PROJECT_BRANCH = 'master'; -const PLAYBOOK_NAME = 'multivault.yml'; -const TEMPLATE_NAME = `template-${id}`; -const VAULT_CREDENTIAL_NAME_1 = `credential-vault-${id}-1`; -const VAULT_CREDENTIAL_NAME_2 = `credential-vault-${id}-2`; - -module.exports = { - 'login to awx': client => { - client.login(); - client.resizeWindow(1200, 800); - client.waitForAngular(); - }, - 'create organization': client => { - const organizations = client.page.organizations(); - const { details } = organizations.section.add.section; - - organizations.section.navigation.waitForElementVisible('@organizations'); - organizations.section.navigation.expect.element('@organizations').enabled; - organizations.section.navigation.click('@organizations'); - - organizations.waitForElementVisible('div.spinny'); - organizations.waitForElementNotVisible('div.spinny'); - - organizations.section.list.expect.element('@add').visible; - organizations.section.list.expect.element('@add').enabled; - organizations.section.list.click('@add'); - - details.waitForElementVisible('@name'); - details.expect.element('@name').enabled; - - details.setValue('@name', ORGANIZATION_NAME); - - organizations.waitForElementVisible('@save'); - organizations.expect.element('@save').enabled; - organizations.click('@save'); - - organizations.waitForElementVisible('div.spinny'); - organizations.waitForElementNotVisible('div.spinny'); - }, - 'create project': client => { - const projects = client.page.projects(); - - projects.section.navigation.waitForElementVisible('@projects'); - projects.section.navigation.expect.element('@projects').enabled; - projects.section.navigation.click('@projects'); - - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.section.list.waitForElementVisible('@add'); - projects.section.list.expect.element('@add').enabled; - - client.pause(1000); projects.section.list.click('@add'); - - projects.waitForElementVisible('label[for="name"] + div input'); - projects.waitForElementVisible('label[for="organization"] + div input'); - projects.waitForElementPresent('label[for="scm_type"] + div > div select option[value="git"]'); - - projects.setValue('label[for="name"] + div input', PROJECT_NAME); - projects.clearValue('label[for="organization"] + div input'); - projects.setValue('label[for="organization"] + div input', ORGANIZATION_NAME); - projects.click('label[for="scm_type"] + div > div select option[value="git"]'); - - projects.waitForElementVisible('.sourceSubForm'); - projects.waitForElementVisible('label[for="scm_url"] + div input'); - projects.waitForElementVisible('label[for="scm_branch"] + div input'); - - projects.setValue('label[for="scm_url"] + div input', PROJECT_URL); - projects.setValue('label[for="scm_branch"] + div input', PROJECT_BRANCH); - - projects.expect.element('#project_save_btn').enabled; - projects.click('#project_save_btn'); - - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.expect.element('smart-search input').enabled; - projects.sendKeys('smart-search input', `${PROJECT_NAME}${client.Keys.ENTER}`); - - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.waitForElementVisible('div.spinny', 120000); - projects.waitForElementNotVisible('div.spinny'); - projects.expect.element('i[class$="success"]').visible; - }, - 'create inventory': client => { - const inventories = client.page.inventories(); - const details = inventories.section.addStandardInventory.section.standardInvDetails; - - inventories.section.navigation.waitForElementVisible('@inventories'); - inventories.section.navigation.expect.element('@inventories').enabled; - inventories.section.navigation.click('@inventories'); - - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - - inventories.selectAdd('Inventory'); - - details.waitForElementVisible('@name'); - details.waitForElementVisible('@organization'); - - details.expect.element('@name').enabled; - details.expect.element('@organization').enabled; - - details.setValue('@name', INVENTORY_NAME); - details.setValue('@organization', ORGANIZATION_NAME); - - inventories.waitForElementVisible('@save'); - inventories.expect.element('@save').enabled; - - inventories.click('@save'); - - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - }, - 'create host': client => { - const addHost = '.hostsList #button-add'; - - client.expect.element('#hosts_tab').enabled; - client.expect.element('#hosts_tab').css('opacity').equal('1'); - client.expect.element('#hosts_tab').css('background-color').contain('255, 255, 255'); - client.click('#hosts_tab'); - - client.waitForElementVisible('div.spinny'); - client.waitForElementNotVisible('div.spinny'); - - client.expect.element('#hosts_tab').css('background-color').contain('132, 137, 146'); - - client.useCss(); - client.waitForElementVisible(addHost); - client.expect.element(addHost).enabled; - client.click(addHost); - - client.waitForElementVisible('#host_name'); - client.sendKeys('#host_name', 'localhost'); - - client.click('div[class="CodeMirror-scroll"]'); - client.sendKeys('.CodeMirror textarea', client.Keys.ENTER); - client.sendKeys('.CodeMirror textarea', 'ansible_connection: local'); - client.click('#host_host_variables_parse_type label[class$="hollow"]'); - client.click('#host_host_variables_parse_type label[class$="hollow"]'); - - client.expect.element('#host_save_btn').enabled; - client.click('#host_save_btn'); - - client.waitForElementVisible('div.spinny'); - client.waitForElementNotVisible('div.spinny'); - }, - 'create vault credentials': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.navigateTo(`${credentials.url()}/add`); - - details.waitForElementVisible('@save'); - details.clearAndSelectType('Vault'); - details.setValue('@organization', ORGANIZATION_NAME); - details.setValue('@name', VAULT_CREDENTIAL_NAME_1); - - details.section.vault.setValue('@vaultPassword', 'secret1'); - details.section.vault.setValue('@vaultIdentifier', 'first'); - - details.expect.element('@save').enabled; - details.click('@save'); - - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - client.navigateTo(`${credentials.url()}/add`); - - details.waitForElementVisible('@save'); - details.clearAndSelectType('Vault'); - details.setValue('@organization', ORGANIZATION_NAME); - details.setValue('@name', VAULT_CREDENTIAL_NAME_2); - - details.section.vault.setValue('@vaultPassword', 'secret2'); - details.section.vault.setValue('@vaultIdentifier', 'second'); - - details.expect.element('@save').enabled; - details.click('@save'); - - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - }, - 'create machine credential': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.navigateTo(`${credentials.url()}/add`); - - details.waitForElementVisible('@save'); - details.clearAndSelectType('Machine'); - details.setValue('@organization', ORGANIZATION_NAME); - details.setValue('@name', MACHINE_CREDENTIAL_NAME); - - details.expect.element('@save').enabled; - details.click('@save'); - - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - }, - 'create job template': client => { - const templates = client.page.templates(); - - client.navigateTo(templates.url()); - - templates.selectAdd('Job Template'); - templates.selectInventory(INVENTORY_NAME); - templates.selectProject(PROJECT_NAME); - templates.selectVaultCredential(VAULT_CREDENTIAL_NAME_1); - templates.selectVaultCredential(VAULT_CREDENTIAL_NAME_2); - templates.selectMachineCredential(MACHINE_CREDENTIAL_NAME); - templates.selectPlaybook(PLAYBOOK_NAME); - templates.sendKeys('label[for="name"] + div input', TEMPLATE_NAME); - - templates.expect.element('#job_template_save_btn').enabled; - templates.click('#job_template_save_btn'); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('#job_template_save_btn').enabled; - }, - 'launch job': client => { - const templates = client.page.templates(); - - templates.waitForElementVisible('smart-search input'); - templates.expect.element('smart-search input').enabled; - - client.pause(1000).waitForElementNotVisible('div.spinny'); - templates.sendKeys('smart-search input', `${TEMPLATE_NAME}${client.Keys.ENTER}`); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.sendKeys('smart-search input', `${TEMPLATE_NAME}${client.Keys.ENTER}`); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.waitForElementPresent('i[class$="launch"]'); - templates.waitForElementNotPresent('i[class$="launch"]:nth-of-type(2)'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - - templates.waitForElementVisible('i[class$="launch"]'); - templates.click('i[class$="launch"]'); - }, - 'verify expected job results': client => { - const output1 = './/span[normalize-space(text())=\'"first": "First!"\']'; - const output2 = './/span[normalize-space(text())=\'"second": "Second!"\']'; - const running = 'i[class$="icon-job-running"]'; - const success = 'i[class$="icon-job-successful"]'; - - client.waitForElementVisible('div.spinny'); - client.waitForElementNotVisible('div.spinny'); - - client.waitForElementVisible('at-job-details'); - client.waitForElementNotPresent(running, 60000); - client.waitForElementVisible(success, 60000); - - client.useXpath(); - client.waitForElementVisible(output1, 60000); - client.waitForElementVisible(output2, 60000); - client.useCss(); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/smoke.yml b/awx/ui/test/e2e/tests/smoke.yml deleted file mode 100644 index 10edd0ab0f85..000000000000 --- a/awx/ui/test/e2e/tests/smoke.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# ansible-playbook multivault.yml --vault-id var1@prompt --vault-id var2@prompt -# Vault password (var1): secret1 -# Vault password (var2): secret2 - -- hosts: all - gather_facts: false - vars: - first: !vault | - $ANSIBLE_VAULT;1.2;AES256;first - 30326539376633656433636231653132623266336338316462356132366361653566303364353335 - 6665626463633737666336643334353262373836613332650a353531666262636531383430363935 - 33633465306165393538323336323135393730383563653738666163633835383262396135353765 - 6238333837306332630a336538623333313636353363326666613564353666623635373432386162 - 3562 - second: !vault | - $ANSIBLE_VAULT;1.2;AES256;second - 34653738643565633930336534363230343562343362643432616165373034376565353833366361 - 6264346330376564643262643166623164323433336631360a396336353866323663613935383534 - 33643034373439326435373539323433313832366437303764353562653834623966663533613464 - 3961663934613264360a613763346638636566386461333235366335336564353935356232316265 - 3164 - tasks: - - debug: var=first - - debug: var=second diff --git a/awx/ui/test/e2e/tests/test-auditor-read-only-forms.js b/awx/ui/test/e2e/tests/test-auditor-read-only-forms.js deleted file mode 100644 index ede45a1a8e37..000000000000 --- a/awx/ui/test/e2e/tests/test-auditor-read-only-forms.js +++ /dev/null @@ -1,196 +0,0 @@ -import { - getAdminAWSCredential, - getAdminMachineCredential, - getAuditor, - getInventory, - getInventoryScript, - getNotificationTemplate, - getOrganization, - getSmartInventory, - getTeam, - getUpdatedProject, - getUser -} from '../fixtures'; - -const data = {}; - -let credentials; -let inventoryScripts; -let notificationTemplates; -let organizations; -let projects; -// let templates; -let users; -let inventories; -let teams; - -module.exports = { - before: (client, done) => { - const promises = [ - getAuditor().then(obj => { data.auditor = obj; }), - getOrganization().then(obj => { data.organization = obj; }), - getInventory().then(obj => { data.inventory = obj; }), - getInventoryScript().then(obj => { data.inventoryScript = obj; }), - getAdminAWSCredential().then(obj => { data.adminAWSCredential = obj; }), - getAdminMachineCredential().then(obj => { data.adminMachineCredential = obj; }), - getSmartInventory().then(obj => { data.smartInventory = obj; }), - getTeam().then(obj => { data.team = obj; }), - getUser().then(obj => { data.user = obj; }), - getNotificationTemplate().then(obj => { data.notificationTemplate = obj; }), - getUpdatedProject().then(obj => { data.project = obj; }) - ]; - - Promise.all(promises) - .then(() => { - client.useCss(); - - credentials = client.page.credentials(); - inventoryScripts = client.page.inventoryScripts(); - // templates = client.page.templates(); - notificationTemplates = client.page.notificationTemplates(); - organizations = client.page.organizations(); - projects = client.page.projects(); - users = client.page.users(); - inventories = client.page.inventories(); - teams = client.page.teams(); - - client.login(data.auditor.username); - client.waitForAngular(); - - done(); - }); - }, - 'verify an auditor\'s credentials inputs are read-only': client => { - const url = `${credentials.url()}/${data.adminAWSCredential.id}/`; - - client.navigateTo(url); - - credentials.section.edit - .expect.element('@title').text.contain(data.adminAWSCredential.name); - - credentials.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify an auditor\'s inventory scripts inputs are read-only': client => { - const url = `${inventoryScripts.url()}/${data.inventoryScript.id}/`; - - client.navigateTo(url); - - inventoryScripts.section.edit - .expect.element('@title').text.contain(data.inventoryScript.name); - - inventoryScripts.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on inventory scripts form': () => { - inventoryScripts.expect.element('@save').to.not.be.visible; - }, - // TODO: re-enable these tests when JT edit has been re-factored to reliably show/remove the - // loading spinner only one time. Without this, we can't tell when all the requisite data is - // available. - // - // 'verify an auditor\'s job template inputs are read-only': function (client) { - // const url = `${templates.url()}/job_template/${data.jobTemplate.id}/`; - // client.navigateTo(url)'' - // - // templates.section.editJobTemplate - // .expect.element('@title').text.contain(data.jobTemplate.name); - // - // templates.section.edit.section.details.checkAllFieldsDisabled(); - // }, - // 'verify save button hidden from auditor on job templates form': function () { - // templates.expect.element('@save').to.not.be.visible; - // }, - 'verify an auditor\'s notification templates inputs are read-only': client => { - const url = `${notificationTemplates.url()}/${data.notificationTemplate.id}/`; - - client.navigateTo(url); - - notificationTemplates.section.edit - .expect.element('@title').text.contain(data.notificationTemplate.name); - - notificationTemplates.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on notification templates page': () => { - notificationTemplates.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s organizations inputs are read-only': client => { - const url = `${organizations.url()}/${data.organization.id}/`; - - client.navigateTo(url); - - organizations.section.edit - .expect.element('@title').text.contain(data.organization.name); - - organizations.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on organizations form': () => { - organizations.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s smart inventory inputs are read-only': client => { - const url = `${inventories.url()}/smart/${data.smartInventory.id}/`; - - client.navigateTo(url); - - inventories.section.editSmartInventory - .expect.element('@title').text.contain(data.smartInventory.name); - - inventories.section.editSmartInventory.section.smartInvDetails.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on smart inventories form': () => { - inventories.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s project inputs are read-only': client => { - const url = `${projects.url()}/${data.project.id}/`; - - client.navigateTo(url); - - projects.section.edit - .expect.element('@title').text.contain(data.project.name); - - projects.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on projects form': () => { - projects.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s standard inventory inputs are read-only': client => { - const url = `${inventories.url()}/inventory/${data.inventory.id}/`; - - client.navigateTo(url); - - inventories.section.editStandardInventory - .expect.element('@title').text.contain(data.inventory.name); - - inventories.section.editStandardInventory.section.standardInvDetails - .checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on standard inventory form': () => { - inventories.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s teams inputs are read-only': client => { - const url = `${teams.url()}/${data.team.id}/`; - - client.navigateTo(url); - - teams.section.edit - .expect.element('@title').text.contain(data.team.name); - - teams.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on teams form': () => { - teams.expect.element('@save').to.not.be.visible; - }, - 'verify an auditor\'s user inputs are read-only': client => { - const url = `${users.url()}/${data.user.id}/`; - - client.navigateTo(url); - - users.section.edit - .expect.element('@title').text.contain(data.user.username); - - users.section.edit.section.details.checkAllFieldsDisabled(); - }, - 'verify save button hidden from auditor on users form': client => { - users.expect.element('@save').to.not.be.visible; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-configuration-ldap-fields.js b/awx/ui/test/e2e/tests/test-configuration-ldap-fields.js deleted file mode 100644 index ab0db09d16a0..000000000000 --- a/awx/ui/test/e2e/tests/test-configuration-ldap-fields.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = { - 'expected LDAP codemirror fields are rendered when returning from another tab': client => { - const authTab = '#auth_tab'; - const authView = 'div[ui-view="auth"]'; - const ldapForm = '#configuration_ldap_template_form'; - const systemTab = '#system_tab'; - const systemView = 'div[ui-view="system"]'; - - const { navigation } = client.page.dashboard().section; - const configuration = client.page.configuration(); - - client.login(); - client.waitForAngular(); - - navigation - .waitForElementVisible('@settings') - .click('@settings'); - - configuration.waitForElementVisible(authView); - - configuration.waitForElementVisible(systemTab); - configuration.click(systemTab); - configuration.waitForElementNotVisible(authView); - configuration.waitForElementVisible(systemView); - - configuration.waitForElementVisible(authTab); - configuration.click(authTab); - configuration.waitForElementNotVisible(systemView); - configuration.waitForElementVisible(authView); - - configuration.selectSubcategory('LDAP'); - configuration.waitForElementVisible(ldapForm); - - const expectedCodemirrorFields = [ - 'AUTH_LDAP_USER_SEARCH', - 'AUTH_LDAP_GROUP_SEARCH', - 'AUTH_LDAP_USER_ATTR_MAP', - 'AUTH_LDAP_GROUP_TYPE_PARAMS', - 'AUTH_LDAP_USER_FLAGS_BY_GROUP', - 'AUTH_LDAP_ORGANIZATION_MAP', - 'AUTH_LDAP_TEAM_MAP', - ]; - - const ldapCodeMirrors = `${ldapForm} div[class^="CodeMirror"] textarea`; - - client.elements('css selector', ldapCodeMirrors, ({ value }) => { - client.assert.equal(value.length, expectedCodemirrorFields.length); - }); - - expectedCodemirrorFields.forEach(fieldName => { - const codemirror = `#cm-${fieldName}-container div[class^="CodeMirror"]`; - - configuration.expect.element(codemirror).visible; - configuration.expect.element(codemirror).enabled; - }); - - client.end(); - }, -}; diff --git a/awx/ui/test/e2e/tests/test-credential-types-add-edit.js b/awx/ui/test/e2e/tests/test-credential-types-add-edit.js deleted file mode 100644 index 6108db871c1c..000000000000 --- a/awx/ui/test/e2e/tests/test-credential-types-add-edit.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - before: (client, done) => { - const credentialTypes = client.page.credentialTypes(); - - client.login(); - client.waitForAngular(); - - credentialTypes.navigateTo(`${credentialTypes.url()}/add/`); - - credentialTypes.section.add - .waitForElementVisible('@title', done); - }, - 'expected fields are present and enabled': client => { - const credentialTypes = client.page.credentialTypes(); - const { details } = credentialTypes.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.section.inputConfiguration.expect.element('.CodeMirror').visible; - details.section.injectorConfiguration.expect.element('.CodeMirror').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@inputConfiguration').enabled; - details.expect.element('@injectorConfiguration').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-aws.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-aws.js deleted file mode 100644 index 5da3e727ae91..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-aws.js +++ /dev/null @@ -1,136 +0,0 @@ -import uuid from 'uuid'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - credentials.section.add.section.details - .waitForElementVisible('@save') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Amazon Web Services', done); - }, - 'expected fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - details.section.aws.expect.element('@accessKey').visible; - details.section.aws.expect.element('@secretKey').visible; - details.section.aws.expect.element('@securityToken').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - details.section.aws.expect.element('@accessKey').enabled; - details.section.aws.expect.element('@secretKey').enabled; - details.section.aws.expect.element('@securityToken').enabled; - }, - 'required fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const required = [ - details.section.name, - details.section.type, - details.section.aws.section.accessKey, - details.section.aws.section.secretKey - ]; - - required.forEach(s => { - s.expect.element('@label').text.to.contain('*'); - }); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details - .clearAndSelectType('Amazon Web Services') - .setValue('@name', store.credential.name); - - details.expect.element('@save').not.enabled; - details.section.aws.setValue('@accessKey', 'AAAAAAAAAAAAA'); - details.section.aws.setValue('@secretKey', 'AAAAAAAAAAAAA'); - details.expect.element('@save').enabled; - }, - 'create aws credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Amazon Web Services') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.aws - .setValue('@accessKey', 'ABCD123456789') - .setValue('@secretKey', '987654321DCBA'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - - const { search } = credentials.section.list.section; - const { table } = credentials.section.list.section; - - search - .waitForElementVisible('@input') - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - table.waitForRowCount(1); - table.findRowByText(store.credential.name) - .waitForElementVisible('@self'); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js deleted file mode 100644 index 9e4238cd6a1e..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js +++ /dev/null @@ -1,175 +0,0 @@ -import uuid from 'uuid'; - -const store = { - credentialType: { - name: `credentialType-${uuid().substr(0, 8)}`, - description: 'custom cloud credential', - kind: 'cloud', - inputs: { - fields: [ - { - id: 'project', - label: 'Project', - type: 'string', - help_text: 'Name of your project' - }, - { - id: 'token', - label: 'Token', - secret: true, - type: 'string', - help_text: 'help' - }, - { - id: 'secret_key_data', - label: 'Secret Key', - type: 'string', - secret: true, - multiline: true, - help_text: 'help', - }, - { - id: 'public_key_data', - label: 'Public Key', - type: 'string', - secret: true, - multiline: true, - help_text: 'help', - }, - { - id: 'secret_key_unlock', - label: 'Private Key Passphrase', - type: 'string', - secret: true, - // help_text: 'help' - }, - { - id: 'color', - label: 'Favorite Color', - choices: [ - '', - 'red', - 'orange', - 'yellow', - 'green', - 'blue', - 'indigo', - 'violet' - ], - help_text: 'help', - }, - ], - required: ['project', 'token'] - }, - injectors: { - env: { - CUSTOM_CREDENTIAL_TOKEN: '{{ token }}' - } - } - } -}; - -const { inputs } = store.credentialType; -const { fields } = inputs; -const help = fields.filter(f => f.help_text); -const required = fields.filter(f => inputs.required.indexOf(f.id) > -1); -const strings = fields.filter(f => f.type === undefined || f.type === 'string'); - -const getObjects = client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const type = details.custom(store.credentialType); - - return { credentials, details, type }; -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - - client.login(); - client.waitForAngular(); - - client.inject( - [store.credentialType, 'CredentialTypeModel'], - (data, Model) => new Model().http.post({ data }), - ({ data }) => { store.credentialType.response = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - credentials.section.add.section.details - .waitForElementVisible('@save') - .setValue('@name', `cred-${uuid()}`) - .setValue('@type', store.credentialType.name, done); - }, - 'all fields are visible': client => { - const { type } = getObjects(client); - fields.forEach(f => { - type.expect.element(`@${f.id}`).visible; - }); - }, - 'helplinks open popovers showing expected content': client => { - const { type } = getObjects(client); - - help.forEach(f => { - const group = type.section[f.id]; - - group.expect.element('@popover').not.visible; - group.click('@help'); - group.expect.element('@popover').visible; - group.expect.element('@popover').text.to.contain(f.help_text); - group.click('@help'); - }); - - help.forEach(f => { - const group = type.section[f.id]; - group.expect.element('@popover').not.visible; - }); - }, - 'secret field buttons hide and unhide input': client => { - const { type } = getObjects(client); - const secrets = strings.filter(f => f.secret && !f.multiline); - - secrets.forEach(f => { - const group = type.section[f.id]; - const input = `@${f.id}`; - - group.expect.element('@show').visible; - group.expect.element('@hide').not.present; - - type.setValue(input, 'SECRET'); - type.expect.element(input).text.equal(''); - - group.click('@show'); - group.expect.element('@show').not.present; - group.expect.element('@hide').visible; - type.expect.element(input).value.contain('SECRET'); - - group.click('@hide'); - group.expect.element('@show').visible; - group.expect.element('@hide').not.present; - type.expect.element(input).text.equal(''); - }); - }, - 'required fields show * symbol': client => { - const { type } = getObjects(client); - - required.forEach(f => { - const group = type.section[f.id]; - group.expect.element('@label').text.to.contain('*'); - }); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js deleted file mode 100644 index cdf871c36a78..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js +++ /dev/null @@ -1,279 +0,0 @@ -import path from 'path'; -import uuid from 'uuid'; - -const GCE_SERVICE_ACCOUNT_FILE = path.resolve(__dirname, 'gce.json'); -const GCE_SERVICE_ACCOUNT_FILE_ALT = path.resolve(__dirname, 'gce.alt.json'); -const GCE_SERVICE_ACCOUNT_FILE_INVALID = path.resolve(__dirname, 'gce.invalid.json'); -const GCE_SERVICE_ACCOUNT_FILE_MISSING = path.resolve(__dirname, 'gce.missing.json'); - -let credentials; - -module.exports = { - before: (client, done) => { - credentials = client.page.credentials(); - - client.login(); - client.waitForAngular(); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - credentials.section.add.section.details - .waitForElementVisible('@save') - .setValue('@name', `credential-${uuid().substr(0, 8)}`) - .setValue('@type', 'Google Compute Engine', done); - }, - 'expected fields are initially visible and enabled': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - - gce.expect.element('@email').visible; - gce.expect.element('@sshKeyData').visible; - gce.expect.element('@project').visible; - gce.expect.element('@serviceAccountFile').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - - gce.expect.element('@email').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present; - }, - 'select valid credential file': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - client.pushFileToWorker(GCE_SERVICE_ACCOUNT_FILE, file => { - gce.section.serviceAccountFile.setValue('form input[type="file"]', file); - }); - - gce.expect.element('@email').not.enabled; - gce.expect.element('@sshKeyData').not.enabled; - gce.expect.element('@project').not.enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present; - }, - 'deselect valid credential file': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - gce.section.serviceAccountFile.click('form i[class*="trash"]'); - - gce.expect.element('@email').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present; - - gce.section.email.expect.element('@error').visible; - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - }, - 'select credential file with missing field': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - client.pushFileToWorker(GCE_SERVICE_ACCOUNT_FILE_MISSING, file => { - gce.section.serviceAccountFile.setValue('form input[type="file"]', file); - }); - - gce.expect.element('@email').not.enabled; - gce.expect.element('@sshKeyData').not.enabled; - gce.expect.element('@project').not.enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present; - - gce.section.email.expect.element('@error').visible; - - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - gce.section.sshKeyData.expect.element('@error').not.present; - }, - 'deselect credential file with missing field': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - gce.section.serviceAccountFile.click('form i[class*="trash"]'); - - gce.expect.element('@email').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present; - - gce.section.email.expect.element('@error').visible; - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - }, - 'select invalid credential file': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - client.pushFileToWorker(GCE_SERVICE_ACCOUNT_FILE_INVALID, file => { - gce.section.serviceAccountFile.setValue('form input[type="file"]', file); - }); - - gce.expect.element('@email').not.enabled; - gce.expect.element('@sshKeyData').not.enabled; - gce.expect.element('@project').not.enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present; - - gce.section.email.expect.element('@error').visible; - gce.section.serviceAccountFile.expect.element('@error').visible; - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.project.expect.element('@error').not.present; - }, - 'deselect invalid credential file': client => { - const { details } = credentials.section.add.section; - const { gce } = details.section; - - gce.section.serviceAccountFile.click('form i[class*="trash"]'); - - gce.expect.element('@email').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible; - gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled; - gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present; - - gce.section.email.expect.element('@error').visible; - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - }, - 'save valid credential file': client => { - const add = credentials.section.add.section.details; - const edit = credentials.section.edit.section.details; - - client.pushFileToWorker(GCE_SERVICE_ACCOUNT_FILE, file => { - add.section.gce.section.serviceAccountFile.setValue('form input[type="file"]', file); - }); - - add.section.gce.expect.element('@email').not.enabled; - add.section.gce.expect.element('@sshKeyData').not.enabled; - add.section.gce.expect.element('@project').not.enabled; - add.section.gce.expect.element('@serviceAccountFile').enabled; - - add.section.gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible; - add.section.gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled; - add.section.gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present; - - add.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.section.gce.expect.element('@email').enabled; - edit.section.gce.expect.element('@project').enabled; - - edit.section.gce.expect.element('@serviceAccountFile').not.enabled; - edit.section.gce.expect.element('@sshKeyData').not.enabled; - }, - 'select and deselect credential file when replacing private key': client => { - const { gce } = credentials.section.edit.section.details.section; - - gce.section.sshKeyData.waitForElementVisible('@replace'); - gce.section.sshKeyData.click('@replace'); - - gce.expect.element('@email').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.email.expect.element('@error').not.present; - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - - client.pushFileToWorker(GCE_SERVICE_ACCOUNT_FILE_ALT, file => { - gce.section.serviceAccountFile.setValue('form input[type="file"]', file); - }); - - gce.expect.element('@serviceAccountFile').enabled; - - gce.expect.element('@email').not.enabled; - gce.expect.element('@sshKeyData').not.enabled; - gce.expect.element('@project').not.enabled; - - gce.section.email.expect.element('@error').not.present; - gce.section.project.expect.element('@error').not.present; - gce.section.sshKeyData.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - - gce.section.sshKeyData.expect.element('@replace').not.present; - gce.section.sshKeyData.expect.element('@revert').present; - gce.section.sshKeyData.expect.element('@revert').not.enabled; - - gce.section.serviceAccountFile.click('form i[class*="trash"]'); - - gce.expect.element('@email').enabled; - gce.expect.element('@sshKeyData').enabled; - gce.expect.element('@project').enabled; - gce.expect.element('@serviceAccountFile').enabled; - - gce.section.sshKeyData.expect.element('@error').visible; - - gce.section.email.expect.element('@error').not.present; - gce.section.project.expect.element('@error').not.present; - gce.section.serviceAccountFile.expect.element('@error').not.present; - - gce.section.sshKeyData.expect.element('@revert').enabled; - - gce.section.sshKeyData.click('@revert'); - - gce.expect.element('@email').enabled; - gce.expect.element('@project').enabled; - - gce.expect.element('@serviceAccountFile').not.enabled; - gce.expect.element('@sshKeyData').not.enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-gce.js deleted file mode 100644 index b7457d81b609..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce.js +++ /dev/null @@ -1,175 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details - .waitForElementVisible('@save') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Google Compute Engine', done); - }, - 'expected fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - details.section.gce.expect.element('@email').visible; - details.section.gce.expect.element('@sshKeyData').visible; - details.section.gce.expect.element('@project').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - details.section.gce.expect.element('@email').enabled; - details.section.gce.expect.element('@sshKeyData').enabled; - details.section.gce.expect.element('@project').enabled; - - details.section.organization.expect.element('@lookup').visible; - }, - 'required fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const required = [ - details.section.name, - details.section.type, - details.section.gce.section.email, - details.section.gce.section.sshKeyData - ]; - - required.forEach(s => { - s.expect.element('@label').text.to.contain('*'); - }); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details - .clearAndSelectType('Google Compute Engine') - .setValue('@name', store.credential.name); - - details.expect.element('@save').not.enabled; - - details.section.gce - .setValue('@email', 'abc@123.com') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - details.expect.element('@save').enabled; - }, - 'error displayed for invalid ssh key data': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyData } = details.section.gce.section; - - details - .clearAndSelectType('Google Compute Engine') - .setValue('@name', store.credential.name); - - details.section.gce - .setValue('@email', 'abc@123.com') - .setValue('@sshKeyData', 'invalid'); - - details.click('@save'); - - sshKeyData.expect.element('@error').visible; - sshKeyData.expect.element('@error').text.to.contain('Invalid certificate or key'); - - details.section.gce.clearValue('@sshKeyData'); - - sshKeyData.expect.element('@error').visible; - sshKeyData.expect.element('@error').text.to.contain('Please enter a value'); - - details.section.gce.setValue('@sshKeyData', 'AAAA'); - sshKeyData.expect.element('@error').not.present; - }, - 'create gce credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Google Compute Engine') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.gce - .setValue('@email', 'abc@123.com') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.contain(store.credential.name); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-insights.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-insights.js deleted file mode 100644 index b4798df5004b..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-insights.js +++ /dev/null @@ -1,137 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details - .waitForElementVisible('@save') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Insights', done); - }, - 'expected fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - details.section.insights.expect.element('@username').visible; - details.section.insights.expect.element('@password').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - details.section.insights.expect.element('@username').enabled; - details.section.insights.expect.element('@password').enabled; - }, - 'required fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const required = [ - details.section.name, - details.section.type, - details.section.insights.section.username, - details.section.insights.section.password - ]; - - required.forEach(s => { - s.expect.element('@label').text.to.contain('*'); - }); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details - .clearAndSelectType('Insights') - .setValue('@name', store.credential.name); - - details.expect.element('@save').not.enabled; - - details.section.insights - .setValue('@username', 'wrosellini') - .setValue('@password', 'quintus'); - - details.expect.element('@save').enabled; - }, - 'create insights credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Insights') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.insights - .setValue('@username', 'wrosellini') - .setValue('@password', 'quintus'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.contain(store.credential.name); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js deleted file mode 100644 index 68507171b0b0..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js +++ /dev/null @@ -1,208 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details.waitForElementVisible('@save', done); - }, - 'common fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - }, - 'required common fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.section.name.expect.element('@label').text.to.contain('*'); - details.section.type.expect.element('@label').text.to.contain('*'); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@save').not.enabled; - - details - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Machine'); - - details.expect.element('@save').enabled; - }, - 'machine credential fields are visible after choosing type': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { machine } = details.section; - - machine.expect.element('@username').visible; - machine.expect.element('@password').visible; - machine.expect.element('@becomeUsername').visible; - machine.expect.element('@becomePassword').visible; - machine.expect.element('@sshKeyData').visible; - machine.expect.element('@sshKeyUnlock').visible; - }, - 'error displayed for invalid ssh key data': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyData } = details.section.machine.section; - - details - .clearAndSelectType('Machine') - .setValue('@name', store.credential.name); - - details.section.machine.setValue('@sshKeyData', 'invalid'); - - details.click('@save'); - - sshKeyData.expect.element('@error').visible; - sshKeyData.expect.element('@error').text.to.contain('Invalid certificate or key'); - - details.section.machine.clearValue('@sshKeyData'); - sshKeyData.expect.element('@error').not.present; - }, - 'error displayed for unencrypted ssh key with passphrase': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyUnlock } = details.section.machine.section; - - details - .clearAndSelectType('Machine') - .setValue('@name', store.credential.name); - - details.section.machine - .setValue('@sshKeyUnlock', 'password') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - details.click('@save'); - - sshKeyUnlock.expect.element('@error').visible; - sshKeyUnlock.expect.element('@error').text.to.contain('not encrypted'); - - details.section.machine.clearValue('@sshKeyUnlock'); - sshKeyUnlock.expect.element('@error').not.present; - }, - 'create machine credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Machine') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.machine - .setValue('@username', 'dsarif') - .setValue('@password', 'freneticpny') - .setValue('@becomeMethod', 'sudo') - .setValue('@becomeUsername', 'dsarif') - .setValue('@becomePassword', 'freneticpny') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'change the password after saving': client => { - const credentials = client.page.credentials(); - const { edit } = credentials.section; - const { machine } = edit.section.details.section; - - machine.section.password.expect.element('@replace').visible; - machine.section.password.expect.element('@replace').enabled; - machine.section.password.expect.element('@revert').not.present; - - machine.expect.element('@password').not.enabled; - - machine.section.password.click('@replace'); - - machine.section.password.expect.element('@replace').not.present; - machine.section.password.expect.element('@revert').visible; - - machine.expect.element('@password').enabled; - machine.setValue('@password', 'newpassword'); - - edit.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.contain(store.credential.name); - - client.end(); - }, -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-network.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-network.js deleted file mode 100644 index 63669b543b33..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-network.js +++ /dev/null @@ -1,208 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details.waitForElementVisible('@save', done); - }, - 'common fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - }, - 'required common fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.section.name.expect.element('@label').text.to.contain('*'); - details.section.type.expect.element('@label').text.to.contain('*'); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@save').not.enabled; - - details - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Network'); - - details.section.network - .waitForElementVisible('@username') - .setValue('@username', 'sgrimes'); - - details.expect.element('@save').enabled; - }, - 'network credential fields are visible after choosing type': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { network } = details.section; - - network.expect.element('@username').visible; - network.expect.element('@password').visible; - network.expect.element('@authorizePassword').visible; - network.expect.element('@sshKeyData').visible; - network.expect.element('@sshKeyUnlock').visible; - }, - 'error displayed for invalid ssh key data': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyData } = details.section.network.section; - - details - .clearAndSelectType('Network') - .setValue('@name', store.credential.name); - - details.section.network - .setValue('@username', 'sgrimes') - .setValue('@sshKeyData', 'invalid'); - - details.click('@save'); - - sshKeyData.expect.element('@error').visible; - sshKeyData.expect.element('@error').text.to.contain('Invalid certificate or key'); - - details.section.network.clearValue('@sshKeyData'); - sshKeyData.expect.element('@error').not.present; - }, - 'error displayed for unencrypted ssh key with passphrase': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyUnlock } = details.section.network.section; - - details - .clearAndSelectType('Network') - .setValue('@name', store.credential.name); - - details.section.network - .setValue('@username', 'sgrimes') - .setValue('@sshKeyUnlock', 'password') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - details.click('@save'); - - sshKeyUnlock.expect.element('@error').visible; - sshKeyUnlock.expect.element('@error').text.to.contain('not encrypted'); - - details.section.network.clearValue('@sshKeyUnlock'); - sshKeyUnlock.expect.element('@error').not.present; - }, - 'error displayed for authorize password without authorize enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { authorizePassword } = details.section.network.section; - - details - .clearAndSelectType('Network') - .setValue('@name', store.credential.name); - - details.section.network - .setValue('@username', 'sgrimes') - .setValue('@authorizePassword', 'ovid'); - - details.click('@save'); - - const expected = 'cannot be set unless "Authorize" is set'; - authorizePassword.expect.element('@error').visible; - authorizePassword.expect.element('@error').text.to.equal(expected); - - details.section.network.clearValue('@authorizePassword'); - authorizePassword.expect.element('@error').not.present; - }, - 'create network credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Network') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.network - .setValue('@username', 'sgrimes') - .setValue('@password', 'ovid') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.contain(store.credential.name); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-scm.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-scm.js deleted file mode 100644 index 744a98b14fa8..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-scm.js +++ /dev/null @@ -1,177 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - }, -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details.waitForElementVisible('@save', done); - }, - 'common fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - }, - 'required common fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.section.name.expect.element('@label').text.to.contain('*'); - details.section.type.expect.element('@label').text.to.contain('*'); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@save').not.enabled; - - details - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Source Control'); - - details.expect.element('@save').enabled; - }, - 'scm credential fields are visible after choosing type': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.section.scm.expect.element('@username').visible; - details.section.scm.expect.element('@password').visible; - details.section.scm.expect.element('@sshKeyData').visible; - details.section.scm.expect.element('@sshKeyUnlock').visible; - }, - 'error displayed for invalid ssh key data': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyData } = details.section.scm.section; - - details - .clearAndSelectType('Source Control') - .setValue('@name', store.credential.name); - - details.section.scm.setValue('@sshKeyData', 'invalid'); - - details.click('@save'); - - sshKeyData.expect.element('@error').visible; - sshKeyData.expect.element('@error').text.to.contain('Invalid certificate or key'); - - details.section.scm.clearValue('@sshKeyData'); - sshKeyData.expect.element('@error').not.present; - }, - 'error displayed for unencrypted ssh key with passphrase': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { sshKeyUnlock } = details.section.scm.section; - - details - .clearAndSelectType('Source Control') - .setValue('@name', store.credential.name); - - details.section.scm - .setValue('@sshKeyUnlock', 'password') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - details.click('@save'); - - sshKeyUnlock.expect.element('@error').visible; - sshKeyUnlock.expect.element('@error').text.to.contain('not encrypted'); - - details.section.scm.clearValue('@sshKeyUnlock'); - sshKeyUnlock.expect.element('@error').not.present; - }, - 'create SCM credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Source Control') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.scm - .setValue('@username', 'gthorpe') - .setValue('@password', 'hydro') - .sendKeys('@sshKeyData', '-----BEGIN RSA PRIVATE KEY-----') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', 'AAAA') - .sendKeys('@sshKeyData', client.Keys.ENTER) - .sendKeys('@sshKeyData', '-----END RSA PRIVATE KEY-----'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.to.contain(store.credential.name); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-vault.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-vault.js deleted file mode 100644 index b017651de36a..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-vault.js +++ /dev/null @@ -1,138 +0,0 @@ -import uuid from 'uuid'; - -import { AWX_E2E_TIMEOUT_LONG } from '../settings'; - -const testID = uuid().substr(0, 8); - -const store = { - organization: { - name: `org-${testID}` - }, - credential: { - name: `cred-${testID}` - } -}; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - client.inject( - [store, 'OrganizationModel'], - (_store_, Model) => new Model().http.post({ data: _store_.organization }), - ({ data }) => { store.organization = data; } - ); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details - .waitForElementVisible('@save') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name) - .setValue('@type', 'Vault', done); - }, - 'expected fields are visible and enabled': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details.expect.element('@name').visible; - details.expect.element('@description').visible; - details.expect.element('@organization').visible; - details.expect.element('@type').visible; - details.section.vault.expect.element('@vaultPassword').visible; - - details.expect.element('@name').enabled; - details.expect.element('@description').enabled; - details.expect.element('@organization').enabled; - details.expect.element('@type').enabled; - details.section.vault.expect.element('@vaultPassword').enabled; - }, - 'required fields display \'*\'': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const required = [ - details.section.name, - details.section.type, - details.section.vault.section.vaultPassword, - ]; - - required.map(s => s.expect.element('@label').text.to.contain('*')); - }, - 'save button becomes enabled after providing required fields': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details - .clearAndSelectType('Vault') - .setValue('@name', store.credential.name); - - details.expect.element('@save').not.enabled; - details.section.vault.setValue('@vaultPassword', 'ch@ng3m3'); - details.expect.element('@save').enabled; - }, - 'vault password field is disabled when prompt on launch is selected': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - details - .clearAndSelectType('Vault') - .setValue('@name', store.credential.name); - - details.section.vault.expect.element('@vaultPassword').enabled; - details.section.vault.section.vaultPassword.click('@prompt'); - details.section.vault.expect.element('@vaultPassword').not.enabled; - }, - 'create vault credential': client => { - const credentials = client.page.credentials(); - const { add } = credentials.section; - const { edit } = credentials.section; - - add.section.details - .clearAndSelectType('Vault') - .setValue('@name', store.credential.name) - .setValue('@organization', store.organization.name); - - add.section.details.section.vault.setValue('@vaultPassword', 'ch@ng3m3'); - - add.section.details.click('@save'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - edit.expect.element('@title').text.equal(store.credential.name); - }, - 'edit details panel remains open after saving': client => { - const credentials = client.page.credentials(); - - credentials.section.edit.expect.section('@details').visible; - }, - 'credential is searchable after saving': client => { - const credentials = client.page.credentials(); - const row = '#credentials_table tbody tr'; - - credentials.section.list.section.search - .waitForElementVisible('@input', AWX_E2E_TIMEOUT_LONG) - .setValue('@input', `name:${store.credential.name}`) - .click('@searchButton'); - - credentials.waitForElementNotPresent(`${row}:nth-of-type(2)`); - credentials.expect.element(row).text.contain(store.credential.name); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-list-actions.js b/awx/ui/test/e2e/tests/test-credentials-list-actions.js deleted file mode 100644 index dd5c27449639..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-list-actions.js +++ /dev/null @@ -1,50 +0,0 @@ -import { getAdminMachineCredential } from '../fixtures'; - -const data = {}; - -module.exports = { - before: (client, done) => { - getAdminMachineCredential('test-actions') - .then(obj => { data.credential = obj; }) - .then(done); - }, - 'copy credential': client => { - const credentials = client.page.credentials(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - credentials.load(); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - credentials.section.list.expect.element('smart-search').visible; - credentials.section.list.expect.element('smart-search input').enabled; - - credentials.section.list - .sendKeys('smart-search input', `id:>${data.credential.id - 1} id:<${data.credential.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - credentials.expect.element(`#credentials_table tr[id="${data.credential.id}"]`).visible; - credentials.expect.element('i[class*="copy"]').visible; - credentials.expect.element('i[class*="copy"]').enabled; - - credentials.click('i[class*="copy"]'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - credentials.expect.element('div[ui-view="edit"] form').visible; - credentials.section.edit.expect.element('@title').visible; - credentials.section.edit.expect.element('@title').text.contain(data.credential.name); - credentials.section.edit.expect.element('@title').text.not.equal(data.credential.name); - credentials.section.edit.section.details.expect.element('@save').visible; - credentials.section.edit.section.details.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-lookup-credential-type.js b/awx/ui/test/e2e/tests/test-credentials-lookup-credential-type.js deleted file mode 100644 index 72b1c891a14d..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-lookup-credential-type.js +++ /dev/null @@ -1,47 +0,0 @@ -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - credentials.section.navigation - .waitForElementVisible('@credentials') - .click('@credentials'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.section.list - .waitForElementVisible('@add') - .click('@add'); - - details - .waitForElementVisible('@save', done); - }, - 'open the lookup modal': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - const modal = 'div[class="modal-body"]'; - const title = 'div[class^="Form-title"]'; - - details.expect.element('@type').visible; - details.expect.element('@type').enabled; - - details.section.type.expect.element('@lookup').visible; - details.section.type.expect.element('@lookup').enabled; - - details.section.type.click('@lookup'); - - client.expect.element(modal).present; - - const expected = 'SELECT CREDENTIAL TYPE'; - client.expect.element(title).visible; - client.expect.element(title).text.equal(expected); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-lookup-organization.js b/awx/ui/test/e2e/tests/test-credentials-lookup-organization.js deleted file mode 100644 index 948c6693deca..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-lookup-organization.js +++ /dev/null @@ -1,161 +0,0 @@ -import { range } from 'lodash'; - -import { getOrganization } from '../fixtures'; - -module.exports = { - before: (client, done) => { - const resources = range(100).map(n => getOrganization(`test-lookup-${n}`)); - - Promise.all(resources) - .then(() => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - - client.login(); - client.waitForAngular(); - - credentials.section.navigation.waitForElementVisible('@credentials'); - credentials.section.navigation.click('@credentials'); - - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - credentials.section.list.waitForElementVisible('@add'); - credentials.section.list.click('@add'); - - details.waitForElementVisible('@save'); - - done(); - }); - }, - 'open the lookup modal': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { lookupModal } = credentials.section; - - details.expect.element('@organization').visible; - details.expect.element('@organization').enabled; - - details.section.organization.expect.element('@lookup').visible; - details.section.organization.expect.element('@lookup').enabled; - - details.section.organization.click('@lookup'); - - credentials.expect.section('@lookupModal').present; - - const expected = 'SELECT ORGANIZATION'; - lookupModal.expect.element('@title').visible; - lookupModal.expect.element('@title').text.equal(expected); - }, - 'select button is disabled until item is selected': client => { - const credentials = client.page.credentials(); - const { details } = credentials.section.add.section; - const { lookupModal } = credentials.section; - const { table } = lookupModal.section; - - details.section.organization.expect.element('@lookup').visible; - details.section.organization.expect.element('@lookup').enabled; - - details.section.organization.click('@lookup'); - - credentials.expect.section('@lookupModal').present; - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(6) input[type="radio"]').not.present; - - lookupModal.expect.element('@select').visible; - lookupModal.expect.element('@select').not.enabled; - - table.click('tbody tr:nth-child(2)'); - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').selected; - - lookupModal.expect.element('@select').visible; - lookupModal.expect.element('@select').enabled; - }, - 'sort and unsort the table by name with an item selected': client => { - const credentials = client.page.credentials(); - const { lookupModal } = credentials.section; - const { table } = lookupModal.section; - - const column = table.section.header.findColumnByText('Name'); - - column.expect.element('@self').visible; - column.expect.element('@sortable').visible; - - column.click('@self'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - - column.click('@self'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - }, - 'use the pagination controls with an item selected': client => { - const credentials = client.page.credentials(); - const { lookupModal } = credentials.section; - const { table } = lookupModal.section; - const { pagination } = lookupModal.section; - - pagination.click('@next'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - - pagination.click('@previous'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - - pagination.click('@last'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - pagination.click('@previous'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - - pagination.click('@first'); - credentials.waitForElementVisible('div.spinny'); - credentials.waitForElementNotVisible('div.spinny'); - - table.expect.element('tbody tr:nth-child(1) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(2) input[type="radio"]').selected; - table.expect.element('tbody tr:nth-child(3) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; - table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-navigation-click-through.js b/awx/ui/test/e2e/tests/test-credentials-navigation-click-through.js deleted file mode 100644 index 9fe4a7c79b89..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-navigation-click-through.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - beforeEach: (client, done) => { - const credentials = client.useCss().page.credentials(); - - client.login(); - client.waitForAngular(); - - credentials - .load() - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny', done); - }, - 'activity link is visible and takes user to activity stream': client => { - const credentials = client.page.credentials(); - const activityStream = client.page.activityStream(); - - credentials.expect.section('@breadcrumb').visible; - credentials.section.breadcrumb.expect.element('@activity').visible; - credentials.section.breadcrumb.click('@activity'); - - activityStream - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForElementVisible('@title') - .waitForElementVisible('@category'); - - activityStream.expect.element('@title').text.contain('CREDENTIALS'); - activityStream.expect.element('@category').value.contain('credential'); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-credentials-search-sort.js b/awx/ui/test/e2e/tests/test-credentials-search-sort.js deleted file mode 100644 index cd46775aae9e..000000000000 --- a/awx/ui/test/e2e/tests/test-credentials-search-sort.js +++ /dev/null @@ -1,55 +0,0 @@ -const columns = ['Name', 'Kind', 'Owners', 'Actions']; -const sortable = ['Name']; - -module.exports = { - before: (client, done) => { - const credentials = client.page.credentials(); - - client.login(); - client.resizeWindow(1200, 800); - client.waitForAngular(); - - credentials - .load() - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - credentials.waitForElementVisible('#credentials_table', done); - }, - 'expected table columns are visible': client => { - const credentials = client.page.credentials(); - const { table } = credentials.section.list.section; - - columns.forEach(label => { - table.section.header.findColumnByText(label) - .expect.element('@self').visible; - }); - }, - 'only fields expected to be sortable show sort icon': client => { - const credentials = client.page.credentials(); - const { table } = credentials.section.list.section; - - sortable.forEach(label => { - table.section.header.findColumnByText(label) - .expect.element('@sortable').visible; - }); - }, - 'sort all columns expected to be sortable': client => { - const credentials = client.page.credentials(); - const { table } = credentials.section.list.section; - - sortable.forEach(label => { - const column = table.section.header.findColumnByText(label); - - column.click('@self'); - - credentials - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny'); - - column.expect.element('@sorted').visible; - }); - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-inventories-list-actions.js b/awx/ui/test/e2e/tests/test-inventories-list-actions.js deleted file mode 100644 index e705daeacf25..000000000000 --- a/awx/ui/test/e2e/tests/test-inventories-list-actions.js +++ /dev/null @@ -1,50 +0,0 @@ -import { getInventory } from '../fixtures'; - -const data = {}; - -module.exports = { - before: (client, done) => { - getInventory('test-actions') - .then(obj => { data.inventory = obj; }) - .then(done); - }, - 'copy inventory': client => { - const inventories = client.page.inventories(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - inventories.load(); - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - - inventories.section.list.expect.element('smart-search').visible; - inventories.section.list.section.search.expect.element('@input').enabled; - - inventories.section.list.section.search - .sendKeys('@input', `id:>${data.inventory.id - 1} id:<${data.inventory.id + 1}`) - .sendKeys('@input', client.Keys.ENTER); - - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - - inventories.expect.element(`#inventories_table tr[id="${data.inventory.id}"]`).visible; - inventories.expect.element('i[class*="copy"]').visible; - inventories.expect.element('i[class*="copy"]').enabled; - - inventories.click('i[class*="copy"]'); - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - - inventories.expect.element('#inventory_form').visible; - inventories.section.editStandardInventory.expect.element('@title').visible; - inventories.section.editStandardInventory.expect.element('@title').text.contain(data.inventory.name); - inventories.section.editStandardInventory.expect.element('@title').text.not.equal(data.inventory.name); - inventories.expect.element('@save').visible; - inventories.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js b/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js deleted file mode 100644 index b75bb73516ae..000000000000 --- a/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js +++ /dev/null @@ -1,50 +0,0 @@ -import { getInventoryScript } from '../fixtures'; - -const data = {}; - -module.exports = { - before: (client, done) => { - getInventoryScript('test-actions') - .then(obj => { data.inventoryScript = obj; }) - .then(done); - }, - 'copy inventory script': client => { - const inventoryScripts = client.page.inventoryScripts(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - inventoryScripts.load(); - inventoryScripts.waitForElementVisible('div.spinny'); - inventoryScripts.waitForElementNotVisible('div.spinny'); - - inventoryScripts.section.list.expect.element('smart-search').visible; - inventoryScripts.section.list.expect.element('smart-search input').enabled; - - inventoryScripts.section.list - .sendKeys('smart-search input', `id:>${data.inventoryScript.id - 1} id:<${data.inventoryScript.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - inventoryScripts.waitForElementVisible('div.spinny'); - inventoryScripts.waitForElementNotVisible('div.spinny'); - - inventoryScripts.expect.element(`#inventory_scripts_table tr[id="${data.inventoryScript.id}"]`).visible; - inventoryScripts.expect.element('i[class*="copy"]').visible; - inventoryScripts.expect.element('i[class*="copy"]').enabled; - - inventoryScripts.click('i[class*="copy"]'); - inventoryScripts.waitForElementVisible('div.spinny'); - inventoryScripts.waitForElementNotVisible('div.spinny'); - - inventoryScripts.expect.element('#inventory_script_form').visible; - inventoryScripts.section.edit.expect.element('@title').visible; - inventoryScripts.section.edit.expect.element('@title').text.contain(data.inventoryScript.name); - inventoryScripts.section.edit.expect.element('@title').text.not.equal(data.inventoryScript.name); - inventoryScripts.expect.element('@save').visible; - inventoryScripts.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-notifications-list-actions.js b/awx/ui/test/e2e/tests/test-notifications-list-actions.js deleted file mode 100644 index 8e126e075d11..000000000000 --- a/awx/ui/test/e2e/tests/test-notifications-list-actions.js +++ /dev/null @@ -1,50 +0,0 @@ -import { getNotificationTemplate } from '../fixtures'; - -const data = {}; - -module.exports = { - before: (client, done) => { - getNotificationTemplate('test-actions') - .then(obj => { data.notification = obj; }) - .then(done); - }, - 'copy notification template': client => { - const notifications = client.page.notificationTemplates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - notifications.load(); - notifications.waitForElementVisible('div.spinny'); - notifications.waitForElementNotVisible('div.spinny'); - - notifications.section.list.expect.element('smart-search').visible; - notifications.section.list.expect.element('smart-search input').enabled; - - notifications.section.list - .sendKeys('smart-search input', `id:>${data.notification.id - 1} id:<${data.notification.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - notifications.waitForElementVisible('div.spinny'); - notifications.waitForElementNotVisible('div.spinny'); - - notifications.expect.element(`#notification_templates_table tr[id="${data.notification.id}"]`).visible; - notifications.expect.element('i[class*="copy"]').visible; - notifications.expect.element('i[class*="copy"]').enabled; - - notifications.click('i[class*="copy"]'); - notifications.waitForElementVisible('div.spinny'); - notifications.waitForElementNotVisible('div.spinny'); - - notifications.expect.element('#notification_template_form').visible; - notifications.section.edit.expect.element('@title').visible; - notifications.section.edit.expect.element('@title').text.contain(data.notification.name); - notifications.section.edit.expect.element('@title').text.not.equal(data.notification.name); - notifications.expect.element('@save').visible; - notifications.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-projects-list-actions.js b/awx/ui/test/e2e/tests/test-projects-list-actions.js deleted file mode 100644 index 17881ed90654..000000000000 --- a/awx/ui/test/e2e/tests/test-projects-list-actions.js +++ /dev/null @@ -1,51 +0,0 @@ -import { getUpdatedProject } from '../fixtures'; - -const data = {}; - -module.exports = { - before: (client, done) => { - getUpdatedProject('test-actions') - .then(obj => { data.project = obj; }) - .then(done); - }, - 'copy project': client => { - const projects = client.page.projects(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - projects.load(); - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.section.list.expect.element('smart-search').visible; - projects.section.list.section.search.expect.element('@input').enabled; - - projects.section.list.section.search - .sendKeys('@input', `id:>${data.project.id - 1} id:<${data.project.id + 1}`) - .sendKeys('@input', client.Keys.ENTER); - - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.section.list.expect.element('@badge').text.equal('1'); - projects.expect.element(`#projects_table tr[id="${data.project.id}"]`).visible; - projects.expect.element('i[class*="copy"]').visible; - projects.expect.element('i[class*="copy"]').enabled; - - projects.click('i[class*="copy"]'); - projects.waitForElementVisible('div.spinny'); - projects.waitForElementNotVisible('div.spinny'); - - projects.expect.element('#project_form').visible; - projects.section.edit.expect.element('@title').visible; - projects.section.edit.expect.element('@title').text.contain(data.project.name); - projects.section.edit.expect.element('@title').text.not.equal(data.project.name); - projects.expect.element('@save').visible; - projects.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-search-tag-add-remove.js b/awx/ui/test/e2e/tests/test-search-tag-add-remove.js deleted file mode 100644 index 294f7aa58255..000000000000 --- a/awx/ui/test/e2e/tests/test-search-tag-add-remove.js +++ /dev/null @@ -1,124 +0,0 @@ -import { range } from 'lodash'; - -import { getAdminMachineCredential } from '../fixtures'; - -const spinny = 'div.spinny'; -const searchInput = 'smart-search input'; -const searchSubmit = 'smart-search i[class*="search"]'; -const searchTags = 'smart-search .SmartSearch-tagContainer'; -const searchClearAll = 'smart-search .SmartSearch-clearAll'; -const searchTagDelete = 'i[class*="fa-times"]'; - -const createTagSelector = n => `${searchTags}:nth-of-type(${n})`; -const createTagDeleteSelector = n => `${searchTags}:nth-of-type(${n}) ${searchTagDelete}`; - -const checkTags = (client, tags) => { - const strategy = 'css selector'; - - const countReached = createTagSelector(tags.length); - const countExceeded = createTagSelector(tags.length + 1); - - if (tags.length > 0) { - client.waitForElementVisible(countReached); - client.waitForElementNotPresent(countExceeded); - } - - client.elements(strategy, searchTags, tagElements => { - client.assert.equal(tagElements.value.length, tags.length); - - let n = -1; - tagElements.value.map(o => o.ELEMENT).forEach(id => { - client.elementIdText(id, ({ value }) => { - client.assert.equal(value, tags[++n]); - }); - }); - }); -}; - -module.exports = { - before: (client, done) => { - const resources = range(25).map(n => getAdminMachineCredential(`test-search-${n}`)); - - Promise.all(resources).then(done); - }, - 'add and remove search tags': client => { - const credentials = client.page.credentials(); - - client.login(); - client.waitForAngular(); - - credentials.section.navigation.waitForElementVisible('@credentials'); - credentials.section.navigation.click('@credentials'); - - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - client.waitForElementVisible(searchInput); - client.waitForElementVisible(searchSubmit); - - client.expect.element(searchInput).enabled; - client.expect.element(searchSubmit).enabled; - - checkTags(client, []); - - client.setValue(searchInput, 'foo'); - client.click(searchSubmit); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['foo']); - - client.setValue(searchInput, 'bar e2e'); - client.click(searchSubmit); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['foo', 'bar', 'e2e']); - - client.click(searchClearAll); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, []); - - client.setValue(searchInput, 'fiz name:foo'); - client.click(searchSubmit); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['fiz', 'name:foo']); - - client.click(searchClearAll); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, []); - - client.setValue(searchInput, 'hello name:world fiz'); - client.click(searchSubmit); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['hello', 'fiz', 'name:world']); - - client.click(createTagDeleteSelector(2)); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['hello', 'name:world']); - - client.click(createTagDeleteSelector(1)); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, ['name:world']); - - client.click(createTagDeleteSelector(1)); - client.waitForElementVisible(spinny); - client.waitForElementNotVisible(spinny); - - checkTags(client, []); - - client.end(); - }, -}; diff --git a/awx/ui/test/e2e/tests/test-templates-copy-delete-warnings.js b/awx/ui/test/e2e/tests/test-templates-copy-delete-warnings.js deleted file mode 100644 index b6544ff2dae9..000000000000 --- a/awx/ui/test/e2e/tests/test-templates-copy-delete-warnings.js +++ /dev/null @@ -1,214 +0,0 @@ -import { post } from '../api'; -import { - getInventoryScript, - getInventorySource, - getJobTemplate, - getOrCreate, - getOrganization, - getProject, - getUser, - getWorkflowTemplate, -} from '../fixtures'; - -let data; - -const promptHeader = '#prompt-header'; -const promptWarning = '#prompt-body'; -const promptResource = 'span[class="Prompt-warningResourceTitle"]'; -const promptResourceCount = 'span[class="badge List-titleBadge"]'; -const promptCancelButton = '#prompt_cancel_btn'; -const promptActionButton = '#prompt_action_btn'; -const promptCloseButton = '#prompt-header + div i[class*="times-circle"]'; - -module.exports = { - before: (client, done) => { - const resources = [ - getUser('test-warnings'), - getOrganization('test-warnings'), - getWorkflowTemplate('test-warnings'), - getProject('test-warnings'), - getJobTemplate('test-warnings'), - getInventoryScript('external-org'), - getInventorySource('external-org'), - ]; - - Promise.all(resources) - .then(([user, org, workflow, project, template, script, source]) => { - const unique = 'unified_job_template'; - const nodes = workflow.related.workflow_nodes; - const nodePromise = getOrCreate(nodes, { [unique]: source.id }, [unique]); - - const permissions = [ - [org, 'admin_role'], - [workflow, 'admin_role'], - [project, 'admin_role'], - [template, 'admin_role'], - [script, 'read_role'], - ]; - - const assignments = permissions - .map(([resource, name]) => resource.summary_fields.object_roles[name]) - .map(role => `/api/v2/roles/${role.id}/users/`) - .map(url => post(url, { id: user.id })) - .concat([nodePromise]); - - Promise.all(assignments) - .then(() => { data = { user, project, source, template, workflow }; }) - .then(done); - }); - }, - 'verify job template delete warning': client => { - const templates = client.page.templates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - templates.load(); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('smart-search').visible; - templates.expect.element('smart-search input').enabled; - - templates - .sendKeys('smart-search input', `id:>${data.template.id - 1} id:<${data.template.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - templates.expect.element(`#row-${data.template.id}`).visible; - templates.expect.element('i[class*="trash"]').visible; - templates.expect.element('i[class*="trash"]').enabled; - - templates.click('i[class*="trash"]'); - - templates.expect.element(promptHeader).visible; - templates.expect.element(promptWarning).visible; - templates.expect.element(promptResource).visible; - templates.expect.element(promptResourceCount).visible; - templates.expect.element(promptCancelButton).visible; - templates.expect.element(promptActionButton).visible; - templates.expect.element(promptCloseButton).visible; - - templates.expect.element(promptCancelButton).enabled; - templates.expect.element(promptActionButton).enabled; - templates.expect.element(promptCloseButton).enabled; - - templates.expect.element(promptHeader).text.contain('DELETE'); - templates.expect.element(promptHeader).text.contain(`${data.template.name.toUpperCase()}`); - - templates.expect.element(promptWarning).text.contain('job template'); - - templates.expect.element(promptResource).text.contain('Workflow Job Template Nodes'); - templates.expect.element(promptResourceCount).text.contain('1'); - - templates.click(promptCancelButton); - - templates.expect.element(promptHeader).not.visible; - - client.end(); - }, - 'verify workflow template delete warning': client => { - const templates = client.page.templates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - templates.load(); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('smart-search').visible; - templates.expect.element('smart-search input').enabled; - - templates - .sendKeys('smart-search input', `id:>${data.workflow.id - 1} id:<${data.workflow.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - templates.expect.element(`#row-${data.workflow.id}`).visible; - templates.expect.element('i[class*="trash"]').visible; - templates.expect.element('i[class*="trash"]').enabled; - - templates.click('i[class*="trash"]'); - - templates.expect.element(promptHeader).visible; - templates.expect.element(promptWarning).visible; - templates.expect.element(promptCancelButton).visible; - templates.expect.element(promptActionButton).visible; - templates.expect.element(promptCloseButton).visible; - - templates.expect.element(promptCancelButton).enabled; - templates.expect.element(promptActionButton).enabled; - templates.expect.element(promptCloseButton).enabled; - - templates.expect.element(promptHeader).text.contain('DELETE'); - templates.expect.element(promptHeader).text.contain(`${data.workflow.name.toUpperCase()}`); - - templates.expect.element(promptWarning).text.contain('workflow template'); - - templates.click(promptCancelButton); - - templates.expect.element(promptHeader).not.visible; - - client.end(); - }, - 'verify workflow restricted copy warning': client => { - const templates = client.page.templates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(data.user.username); - client.waitForAngular(); - - templates.load(); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('smart-search').visible; - templates.expect.element('smart-search input').enabled; - - templates - .sendKeys('smart-search input', `id:>${data.workflow.id - 1} id:<${data.workflow.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - templates.expect.element(`#row-${data.workflow.id}`).visible; - templates.expect.element('i[class*="copy"]').visible; - templates.expect.element('i[class*="copy"]').enabled; - - templates.click('i[class*="copy"]'); - - templates.expect.element(promptHeader).visible; - templates.expect.element(promptWarning).visible; - templates.expect.element(promptCancelButton).visible; - templates.expect.element(promptActionButton).visible; - templates.expect.element(promptCloseButton).visible; - - templates.expect.element(promptCancelButton).enabled; - templates.expect.element(promptActionButton).enabled; - templates.expect.element(promptCloseButton).enabled; - - templates.expect.element(promptHeader).text.contain('COPY WORKFLOW'); - templates.expect.element(promptWarning).text.contain('Unified Job Templates'); - templates.expect.element(promptWarning).text.contain(`${data.source.name}`); - - templates.click(promptCancelButton); - - templates.expect.element(promptHeader).not.visible; - - client.end(); - }, -}; diff --git a/awx/ui/test/e2e/tests/test-templates-list-actions.js b/awx/ui/test/e2e/tests/test-templates-list-actions.js deleted file mode 100644 index ae551e776842..000000000000 --- a/awx/ui/test/e2e/tests/test-templates-list-actions.js +++ /dev/null @@ -1,161 +0,0 @@ -import { - getInventorySource, - getJobTemplate, - getProject, - getWorkflowTemplate -} from '../fixtures'; - -let data; - -module.exports = { - before: (client, done) => { - const resources = [ - getInventorySource('test-actions'), - getJobTemplate('test-actions'), - getProject('test-actions'), - getWorkflowTemplate('test-actions'), - ]; - - Promise.all(resources) - .then(([source, template, project, workflow]) => { - data = { source, template, project, workflow }; - done(); - }); - }, - 'copy job template': client => { - const templates = client.page.templates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - templates.load(); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('smart-search').visible; - templates.expect.element('smart-search input').enabled; - - templates - .sendKeys('smart-search input', `id:>${data.template.id - 1} id:<${data.template.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - templates.expect.element(`#row-${data.template.id}`).visible; - templates.expect.element('i[class*="copy"]').visible; - templates.expect.element('i[class*="copy"]').enabled; - - templates.click('i[class*="copy"]'); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('#job_template_form').visible; - templates.section.addJobTemplate.expect.element('@title').visible; - templates.section.addJobTemplate.expect.element('@title').text.contain(data.template.name); - templates.section.addJobTemplate.expect.element('@title').text.not.equal(data.template.name); - templates.expect.element('@save').visible; - templates.expect.element('@save').enabled; - - client.end(); - }, - 'copy workflow template': client => { - const templates = client.page.templates(); - - client.useCss(); - client.resizeWindow(1200, 800); - client.login(); - client.waitForAngular(); - - templates.load(); - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('smart-search').visible; - templates.expect.element('smart-search input').enabled; - - templates - .sendKeys('smart-search input', `id:>${data.workflow.id - 1} id:<${data.workflow.id + 1}`) - .sendKeys('smart-search input', client.Keys.ENTER); - - templates.waitForElementVisible('div.spinny'); - templates.waitForElementNotVisible('div.spinny'); - - templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - templates.expect.element(`#row-${data.workflow.id}`).visible; - templates.expect.element('i[class*="copy"]').visible; - templates.expect.element('i[class*="copy"]').enabled; - - templates - .click('i[class*="copy"]') - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForAngular(); - - templates.expect.element('#workflow_job_template_form').visible; - templates.section.editWorkflowJobTemplate.expect.element('@title').visible; - templates.section.editWorkflowJobTemplate.expect.element('@title').text.contain(data.workflow.name); - templates.section.editWorkflowJobTemplate.expect.element('@title').text.not.equal(data.workflow.name); - - templates.expect.element('@save').visible; - templates.expect.element('@save').enabled; - - client - .useXpath() - .pause(1000) - .waitForElementVisible('//*[text()=" Workflow Editor"]') - .click('//*[text()=" Workflow Editor"]') - .useCss() - .waitForElementVisible('div.spinny') - .waitForElementNotVisible('div.spinny') - .waitForAngular(); - - client.expect.element('#workflow-modal-dialog').visible; - client.expect.element('#workflow-modal-dialog span[class^="badge"]').visible; - client.expect.element('#workflow-modal-dialog span[class^="badge"]').text.equal('3'); - client.expect.element('div[class="WorkflowMaker-title"]').visible; - client.expect.element('div[class="WorkflowMaker-title"]').text.contain(data.workflow.name); - client.expect.element('div[class="WorkflowMaker-title"]').text.not.equal(data.workflow.name); - - client.expect.element('#workflow-modal-dialog i[class*="fa-cog"]').visible; - client.expect.element('#workflow-modal-dialog i[class*="fa-cog"]').enabled; - - client.click('#workflow-modal-dialog i[class*="fa-cog"]'); - - client.waitForElementVisible('workflow-controls'); - client.waitForElementVisible('div[class*="-zoomPercentage"]'); - - client.click('i[class*="fa-home"]').expect.element('div[class*="-zoomPercentage"]').text.equal('100%'); - client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('90%'); - client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('80%'); - client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('70%'); - client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('60%'); - - client.expect.element('#node-1').visible; - client.expect.element('#node-2').visible; - client.expect.element('#node-3').visible; - client.expect.element('#node-4').visible; - - client.expect.element('#node-1 text').text.not.equal('').after(5000); - client.expect.element('#node-2 text').text.not.equal('').after(5000); - client.expect.element('#node-3 text').text.not.equal('').after(5000); - client.expect.element('#node-4 text').text.not.equal('').after(5000); - - const checkNodeText = (selector, text) => client.getText(selector, ({ value }) => { - client.assert.equal(text.indexOf(value.replace('...', '')) >= 0, true); - }); - - checkNodeText('#node-1 text', 'START'); - checkNodeText('#node-2 text', data.project.name); - checkNodeText('#node-3 text', data.template.name); - checkNodeText('#node-4 text', data.source.name); - - templates.expect.element('@save').visible; - templates.expect.element('@save').enabled; - - client.end(); - } -}; diff --git a/awx/ui/test/e2e/tests/test-xss.js b/awx/ui/test/e2e/tests/test-xss.js deleted file mode 100644 index 6383926709de..000000000000 --- a/awx/ui/test/e2e/tests/test-xss.js +++ /dev/null @@ -1,710 +0,0 @@ -import { - getAdminMachineCredential, - getHost, - getInventory, - getInventoryScript, - getInventorySource, - getInventorySourceSchedule, - getJobTemplate, - getJobTemplateSchedule, - getNotificationTemplate, - getOrganization, - getProjectAdmin, - getSmartInventory, - getTeam, - getUpdatedProject, - getJob, -} from '../fixtures'; - -const data = {}; -const urls = {}; -const pages = {}; - -module.exports = { - before: (client, done) => { - const namespace = '
test
'; - const namespaceShort = '
t
'; - - const resources = [ - getOrganization(namespace).then(obj => { data.organization = obj; }), - getHost(namespaceShort).then(obj => { data.host = obj; }), - getInventory(namespace).then(obj => { data.inventory = obj; }), - getInventoryScript(namespace).then(obj => { data.inventoryScript = obj; }), - getSmartInventory(namespace).then(obj => { data.smartInventory = obj; }), - getInventorySource(namespace).then(obj => { data.inventorySource = obj; }), - getInventorySourceSchedule(namespace).then(obj => { data.sourceSchedule = obj; }), - getUpdatedProject(namespace).then(obj => { data.project = obj; }), - getAdminMachineCredential(namespace).then(obj => { data.credential = obj; }), - getJobTemplate(namespace).then(obj => { data.jobTemplate = obj; }), - getJobTemplateSchedule(namespace).then(obj => { data.jobTemplateSchedule = obj; }), - getTeam(namespace).then(obj => { data.team = obj; }), - getProjectAdmin(namespace).then(obj => { data.user = obj; }), - getNotificationTemplate(namespace).then(obj => { data.notification = obj; }), - getJob(namespace).then(obj => { data.job = obj; }), - ]; - - Promise.all(resources) - .then(() => { - pages.organizations = client.page.organizations(); - pages.inventories = client.page.inventories(); - pages.inventoryScripts = client.page.inventoryScripts(); - pages.projects = client.page.projects(); - pages.credentials = client.page.credentials(); - pages.templates = client.page.templates(); - pages.teams = client.page.teams(); - pages.users = client.page.users(); - pages.notificationTemplates = client.page.notificationTemplates(); - pages.jobs = client.page.jobs(); - - urls.organization = `${pages.organizations.url()}/${data.organization.id}`; - urls.inventory = `${pages.inventories.url()}/inventory/${data.inventory.id}`; - urls.inventoryScript = `${pages.inventoryScripts.url()}/${data.inventoryScript.id}`; - urls.inventorySource = `${urls.inventory}/inventory_sources/edit/${data.inventorySource.id}`; - urls.sourceSchedule = `${urls.inventorySource}/schedules/${data.sourceSchedule.id}`; - urls.smartInventory = `${pages.inventories.url()}/smart/${data.smartInventory.id}`; - urls.project = `${pages.projects.url()}/${data.project.id}`; - urls.credential = `${pages.credentials.url()}/${data.credential.id}`; - urls.jobTemplate = `${pages.templates.url()}/job_template/${data.jobTemplate.id}`; - urls.jobTemplateSchedule = `${urls.jobTemplate}/schedules/${data.jobTemplateSchedule.id}`; - urls.team = `${pages.teams.url()}/${data.team.id}`; - urls.user = `${pages.users.url()}/${data.user.id}`; - urls.notification = `${pages.notificationTemplates.url()}/${data.notification.id}`; - urls.jobs = `${pages.jobs.url()}`; - urls.jobsSchedules = `${pages.jobs.url()}/schedules`; - urls.inventoryHosts = `${pages.inventories.url()}/inventory/${data.host.summary_fields.inventory.id}/hosts`; - - client.useCss(); - client.login(); - client.resizeWindow(1200, 800); - client.waitForAngular(); - - done(); - }); - }, - 'check template form for unsanitized content': client => { - const multiCredentialOpen = 'multi-credential button i[class*="search"]'; - const multiCredentialExit = 'multi-credential-modal button[class*="exit"]'; - - client.navigateTo(urls.jobTemplate, false); - - client.expect.element('#job_template_form').visible; - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.expect.element(multiCredentialOpen).visible; - client.expect.element(multiCredentialOpen).enabled; - - client.pause(2000).click(multiCredentialOpen); - - client.expect.element('#multi-credential-modal').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click(multiCredentialExit); - - client.pause(500).expect.element('div.spinny').not.visible; - client.expect.element('#multi-credential-modal').not.present; - }, - 'check template list for unsanitized content': client => { - const itemRow = `#row-${data.jobTemplate.id}`; - const itemName = `${itemRow} .at-RowItem-header`; - - client.expect.element('.at-Panel smart-search').visible; - client.expect.element('.at-Panel smart-search input').enabled; - - client.sendKeys('.at-Panel smart-search input', `id:>${data.jobTemplate.id - 1} id:<${data.jobTemplate.id + 1}`); - client.sendKeys('.at-Panel smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').not.visible; - - client.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - // TODO: uncomment when tooltips are added - // client.moveToElement(itemName, 0, 0, () => { - // client.expect.element(itemName).attribute('aria-describedby'); - // - // client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - // const tooltip = `#${value}`; - // - // client.expect.element(tooltip).present; - // client.expect.element(tooltip).visible; - // - // client.expect.element('#xss').not.present; - // client.expect.element('[class=xss]').not.present; - // client.expect.element(tooltip).attribute('innerHTML') - // .contains('<div id="xss" class="xss">test</div>'); - // }); - // }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check user form for unsanitized content': client => { - client.navigateTo(urls.user); - - client.expect.element('#user_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check user roles list for unsanitized content': client => { - const adminRole = data.project.summary_fields.object_roles.admin_role; - const itemDelete = `#permissions_table tr[id="${adminRole.id}"] #delete-action`; - - client.expect.element('#permissions_tab').visible; - client.expect.element('#permissions_tab').enabled; - - client.click('#permissions_tab'); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.expect.element('div[ui-view="related"]').visible; - client.expect.element('div[ui-view="related"] smart-search input').enabled; - - client.sendKeys('div[ui-view="related"] smart-search input', `id:>${adminRole.id - 1} id:<${adminRole.id + 1}`); - client.sendKeys('div[ui-view="related"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').not.visible; - - client.expect.element(itemDelete).visible; - client.expect.element(itemDelete).enabled; - - client.click(itemDelete); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt-header').text.equal('REMOVE ROLE'); - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check user permissions view for unsanitized content': client => { - client.expect.element('button[aw-tool-tip="Grant Permission"]').enabled; - - client.click('button[aw-tool-tip="Grant Permission"]'); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - client.expect.element('div[class="AddPermissions-header"]').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.expect.element('div[class="AddPermissions-dialog"] button[class*="exit"]').enabled; - - client.click('div[class="AddPermissions-dialog"] button[class*="exit"]'); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - }, - 'check notification form for unsanitized content': client => { - client.navigateTo(urls.notification); - - client.expect.element('#notification_template_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check notification list for unsanitized content': client => { - const itemRow = `#notification_templates_table tr[id="${data.notification.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.notification.id - 1} id:<${data.notification.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check organization form for unsanitized content': client => { - client.navigateTo(urls.organization); - - client.expect.element('#organization_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check organization list for unsanitized content': client => { - const itemName = '#OrgCards h3[class*="-label"]'; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.organization.id - 1} id:<${data.organization.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click('#OrgCards i[class*="trash"]'); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check inventory form for unsanitized content': client => { - client.navigateTo(urls.inventory); - - client.expect.element('#inventory_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check inventory list for unsanitized content': client => { - const itemRow = `#inventories_table tr[id="${data.inventory.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.inventory.id - 1} id:<${data.inventory.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - // client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check smart inventory form for unsanitized content': client => { - client.navigateTo(urls.smartInventory, false); - - client.expect.element('#smartinventory_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check inventory script form for unsanitized content': client => { - client.navigateTo(urls.inventoryScript); - - client.expect.element('#inventory_script_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check inventory script list for unsanitized content': client => { - const itemRow = `#inventory_scripts_table tr[id="${data.inventoryScript.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.inventoryScript.id - 1} id:<${data.inventoryScript.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check project form for unsanitized content': client => { - client.navigateTo(urls.project); - - client.expect.element('#project_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check project roles list for unsanitized content': client => { - const itemDelete = `#permissions_table tr[id="${data.user.id}"] div[class*="RoleList-deleteContainer"]`; - - client.expect.element('#permissions_tab').visible; - client.expect.element('#permissions_tab').enabled; - - client.click('#permissions_tab'); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.expect.element('div[ui-view="related"]').visible; - client.expect.element('div[ui-view="related"] smart-search input').enabled; - - client.sendKeys('div[ui-view="related"] smart-search input', `id:>${data.user.id - 1} id:<${data.user.id + 1}`); - client.sendKeys('div[ui-view="related"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').not.visible; - - client.expect.element(itemDelete).visible; - client.expect.element(itemDelete).enabled; - - client.click(itemDelete); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt-header').text.equal('USER ACCESS REMOVAL'); - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check project permissions view for unsanitized content': client => { - client.expect.element('button[aw-tool-tip="Add a permission"]').visible; - client.expect.element('button[aw-tool-tip="Add a permission"]').enabled; - - client.click('button[aw-tool-tip="Add a permission"]'); - client.expect.element('div.spinny').not.visible; - - client.expect.element('div[class="AddPermissions-header"]').visible; - client.expect.element('div[class="AddPermissions-header"]').attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.expect.element('div[class="AddPermissions-dialog"] button[class*="exit"]').enabled; - - client.click('div[class="AddPermissions-dialog"] button[class*="exit"]'); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - // client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - client.waitForAngular(); - - client.expect.element('#project_tab').enabled; - - client.click('#project_tab'); - - client.expect.element('#project_form').visible; - }, - 'check project list for unsanitized content': client => { - const itemRow = `#projects_table tr[id="${data.project.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.project.id - 1} id:<${data.project.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check credential form for unsanitized content': client => { - client.navigateTo(urls.credential); - - client.expect.element('div[ui-view="edit"] form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check credential list for unsanitized content': client => { - const itemRow = `#credentials_table tr[id="${data.credential.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[ui-view="list"] smart-search').visible; - client.expect.element('div[ui-view="list"] smart-search input').enabled; - - client.sendKeys('div[ui-view="list"] smart-search input', `id:>${data.credential.id - 1} id:<${data.credential.id + 1}`); - client.sendKeys('div[ui-view="list"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check team form for unsanitized content': client => { - client.navigateTo(urls.team); - - client.expect.element('#team_form').visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check team list for unsanitized content': client => { - const itemRow = `#teams_table tr[id="${data.team.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.team.id - 1} id:<${data.team.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.expect.element('.List-titleBadge').text.equal('1'); - client.expect.element(itemName).visible; - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - - client.click(`${itemRow} i[class*="trash"]`); - - client.expect.element('#prompt-header').visible; - client.expect.element('#prompt_cancel_btn').enabled; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - - client.click('#prompt_cancel_btn'); - - client.expect.element('#prompt-header').not.visible; - }, - 'check inventory source schedule view for unsanitized content': client => { - client.navigateTo(urls.sourceSchedule); - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check job template schedule view for unsanitized content': client => { - client.navigateTo(urls.jobTemplateSchedule); - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - }, - 'check job schedules view for unsanitized content': client => { - const itemRow = `#schedules_table tr[id="${data.jobTemplateSchedule.id}"]`; - const itemName = `${itemRow} td[class*="name-"] a`; - - client.navigateTo(urls.jobsSchedules); - - client.moveToElement(itemName, 0, 0, () => { - client.expect.element(itemName).attribute('aria-describedby'); - client.getAttribute(itemName, 'aria-describedby', ({ value }) => { - const tooltip = `#${value}`; - client.expect.element(tooltip).present; - client.expect.element(tooltip).visible; - - client.expect.element('#xss').not.present; - client.expect.element('[class=xss]').not.present; - client.expect.element(tooltip).attribute('innerHTML') - .contains('<div id="xss" class="xss">test</div>'); - }); - }); - }, - 'check host recent jobs popup for unsanitized content': client => { - const itemRow = `#hosts_table tr[id="${data.host.id}"]`; - const itemName = `${itemRow} td[class*="active_failures-"] a`; - const popOver = `${itemRow} td[class*="active_failures-"] div[class*="popover"]`; - - client.navigateTo(urls.inventoryHosts); - client.expect.element('div[class^="Panel"] smart-search').visible; - client.expect.element('div[class^="Panel"] smart-search input').enabled; - - client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.host.id - 1} id:<${data.host.id + 1}`); - client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER); - - client.expect.element('div.spinny').visible; - client.expect.element('div.spinny').not.visible; - - client.click(itemName); - client.expect.element(popOver).present; - - client.expect.element('[class=xss]').not.present; - - client.end(); - }, -}; diff --git a/awx/ui/test/spec/column-sort/column-sort.directive-test.js b/awx/ui/test/spec/column-sort/column-sort.directive-test.js deleted file mode 100644 index 64b0eb497103..000000000000 --- a/awx/ui/test/spec/column-sort/column-sort.directive-test.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict'; - -xdescribe('Directive: column-sort', () =>{ - - let $scope, template, $compile, QuerySet, GetBasePath; - - beforeEach(angular.mock.module('templateUrl')); - beforeEach(function(){ - - this.mock = { - dataset: [ - {name: 'zero', idx: 0}, - {name: 'one', idx: 1}, - {name: 'two', idx: 2} - ] - }; - - this.name_field = angular.element(` - `); - - this.idx_field = angular.element(` - `); - - this.$state = { - params: {}, - go: jasmine.createSpy('go') - }; - - this.$stateParams = {}; - - var mockFilter = function (value) { - return value; - }; - - angular.mock.module('ColumnSortModule', ($provide) =>{ - - QuerySet = jasmine.createSpyObj('qs', ['search']); - QuerySet.search.and.callFake(() => { return { then: function(){} }; }); - GetBasePath = jasmine.createSpy('GetBasePath'); - $provide.value('QuerySet', QuerySet); - $provide.value('GetBasePath', GetBasePath); - $provide.value('$state', this.$state); - $provide.value('$stateParams', this.$stateParams); - $provide.value("translateFilter", mockFilter); - - }); - }); - - beforeEach(angular.mock.inject(($templateCache, _$rootScope_, _$compile_) => { - template = window.__html__['client/src/shared/column-sort/column-sort.partial.html']; - $templateCache.put('/static/partials/shared/column-sort/column-sort.partial.html', template); - - $compile = _$compile_; - $scope = _$rootScope_.$new(); - })); - - it('should be ordered by name', function(){ - - this.$state.params = { - mock_search: {order_by: 'name'} - }; - - $compile(this.name_field)($scope); - $compile(this.idx_field)($scope); - - $scope.$digest(); - expect( $(this.name_field).find('.columnSortIcon').hasClass('fa-sort-up') ).toEqual(true); - expect( $(this.idx_field).find('.columnSortIcon').hasClass('fa-sort') ).toEqual(true); - }); - - it('should toggle to ascending name order, then ascending idx, then descending idx', function(){ - - this.$state.params = { - mock_search: {order_by: 'idx'} - }; - - $compile(this.name_field)($scope); - $compile(this.idx_field)($scope); - - $scope.$digest(); - - $(this.name_field).click(); - expect( $(this.name_field).find('.columnSortIcon').hasClass('fa-sort-up') ).toEqual(true); - expect( $(this.idx_field).find('.columnSortIcon').hasClass('fa-sort') ).toEqual(true); - - $(this.idx_field).click(); - expect( $(this.name_field).find('.columnSortIcon').hasClass('fa-sort') ).toEqual(true); - expect( $(this.idx_field).find('.columnSortIcon').hasClass('fa-sort-up') ).toEqual(true); - - $(this.idx_field).click(); - expect( $(this.name_field).find('.columnSortIcon').hasClass('fa-sort') ).toEqual(true); - expect( $(this.idx_field).find('.columnSortIcon').hasClass('fa-sort-down') ).toEqual(true); - }); - -}); diff --git a/awx/ui/test/spec/features/features.directive-test.js b/awx/ui/test/spec/features/features.directive-test.js deleted file mode 100644 index b931c8a92137..000000000000 --- a/awx/ui/test/spec/features/features.directive-test.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -describe('Directive: Features enabled/disabled', () => { - let $compile, - $scope, - q; - - beforeEach(angular.mock.module('features')); - - beforeEach(angular.mock.inject((_$compile_, _$rootScope_, $q) => { - $compile = _$compile_; - $scope = _$rootScope_; - q = $q; - - $scope.featuresConfigured = q.defer(); - })); - - it('Removes the element if feature is disabled', () => { - let element = $compile("
A critical security flaw in the glibc library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.

\n", - "generic_html": "

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2015_7547_glibc|GLIBC_CVE_2015_7547", - "error_key": "GLIBC_CVE_2015_7547", - "plugin": "CVE_2015_7547_glibc", - "description": "Remote code execution vulnerability in libresolv via crafted DNS response (CVE-2015-7547)", - "summary": "A critical security flaw in the `glibc` library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.", - "generic": "The `glibc` library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the `libresolv` part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when `libresolv` is called from the nss_dns NSS service module. This flaw is known as [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).", - "reason": "

This host is vulnerable because it has vulnerable package glibc-2.17-55.el7 installed and DNS is enabled in /etc/nsswitch.conf:

\n
hosts:      files dns\n

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2168451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:35.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating glibc and restarting the affected system:

\n
# yum update glibc\n# reboot\n

Alternatively, you can restart all affected services, but because this vulnerability affects a large amount of applications on the system, the best solution is to restart the system.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "mitigation_conf": "no", - "sysctl_live_ack_limit": "100", - "package_name": "kernel", - "sysctl_live_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit = 100", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "vulnerable_kernel": "3.10.0-123.el7", - "sysctl_conf_ack_limit": "100", - "sysctl_conf_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit=100", - "mitigation_live": "no" - }, - "id": 766342155, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the RFC 5961 challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n", - "generic_html": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "plugin": "CVE_2016_5696_kernel", - "description": "Kernel vulnerable to man-in-the-middle via payload injection", - "summary": "A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the [RFC 5961](https://tools.ietf.org/html/rfc5961) challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.", - "generic": "A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack ([RFC 5961](https://tools.ietf.org/html/rfc5961)) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

Your currently loaded kernel configuration contains this setting:

\n
net.ipv4.tcp_challenge_ack_limit = 100\n

Your currently stored kernel configuration is:

\n
net.ipv4.tcp_challenge_ack_limit=100\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5696](https://access.redhat.com/security/cve/CVE-2016-5696)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2438571", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying the following mitigations until the machine is restarted with the updated kernel package.

\n

Edit /etc/sysctl.conf file as root, add the mitigation configuration, and reload the kernel configuration:

\n
# echo "net.ipv4.tcp_challenge_ack_limit = 2147483647" >> /etc/sysctl.conf \n# sysctl -p\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 56045, - "maintenance_plan": { - "maintenance_id": 15875, - "name": "Payload Injection Fix", - "description": "", - "start": "2017-06-01T02:00:00.000Z", - "end": "2017-06-01T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61575, - "maintenance_plan": { - "maintenance_id": 16825, - "name": "Summit 2017 Plan 1", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66175, - "maintenance_plan": { - "maintenance_id": 19435, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71015, - "maintenance_plan": { - "maintenance_id": 19835, - "name": "Optum Payload", - "description": "", - "start": "2017-05-27T02:00:00.000Z", - "end": "2017-05-27T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - } -] diff --git a/awx/ui/test/spec/inventories/insights/data/insights-data.js b/awx/ui/test/spec/inventories/insights/data/insights-data.js deleted file mode 100644 index 0d36f8af6a7e..000000000000 --- a/awx/ui/test/spec/inventories/insights/data/insights-data.js +++ /dev/null @@ -1,662 +0,0 @@ -export default { - "toString": "ansible1.tronik-insights440.atl.redhat.com", - "isCheckingIn": true, - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "display_name": null, - "remote_branch": null, - "remote_leaf": null, - "account_number": "540155", - "hostname": "ansible1.tronik-insights440.atl.redhat.com", - "parent_id": null, - "system_type_id": 105, - "last_check_in": "2017-05-25T14:01:19.000Z", - "stale_ack": false, - "type": "machine", - "product": "rhel", - "created_at": "2016-07-26T23:31:13.000Z", - "updated_at": "2017-05-25T14:01:19.000Z", - "unregistered_at": null, - "reports": [{ - "details": { - "vulnerable_setting": "hosts: files dns", - "affected_package": "glibc-2.17-55.el7", - "error_key": "GLIBC_CVE_2015_7547" - }, - "id": 709784455, - "rule_id": "CVE_2015_7547_glibc|GLIBC_CVE_2015_7547", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A critical security flaw in the glibc library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.

\n", - "generic_html": "

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2015_7547_glibc|GLIBC_CVE_2015_7547", - "error_key": "GLIBC_CVE_2015_7547", - "plugin": "CVE_2015_7547_glibc", - "description": "Remote code execution vulnerability in libresolv via crafted DNS response (CVE-2015-7547)", - "summary": "A critical security flaw in the `glibc` library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.", - "generic": "The `glibc` library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the `libresolv` part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when `libresolv` is called from the nss_dns NSS service module. This flaw is known as [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).", - "reason": "

This host is vulnerable because it has vulnerable package glibc-2.17-55.el7 installed and DNS is enabled in /etc/nsswitch.conf:

\n
hosts:      files dns\n

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2168451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:35.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating glibc and restarting the affected system:

\n
# yum update glibc\n# reboot\n

Alternatively, you can restart all affected services, but because this vulnerability affects a large amount of applications on the system, the best solution is to restart the system.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "affected_kernel": "3.10.0-123.el7", - "error_key": "KERNEL_CVE-2016-0728" - }, - "id": 709784465, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as CVE-2016-0728.

\n", - "generic_html": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

Red Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "error_key": "KERNEL_CVE-2016-0728", - "plugin": "CVE_2016_0728_kernel", - "description": "Kernel key management subsystem vulnerable to local privilege escalation (CVE-2016-0728)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).", - "generic": "A vulnerability in the Linux kernel rated **Important** was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n\nRed Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the [systemtap patch](https://bugzilla.redhat.com/attachment.cgi?id=1116284&action=edit) to update your running kernel.", - "reason": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

The host is vulnerable as it is running kernel-3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaws and versions of the package that are vulnerable see [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2130791", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:37.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update kernel and reboot. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n
# yum update kernel\n# reboot\n-or-\n# debuginfo-install kernel     (or equivalent)\n# stap -vgt -Gfix_p=1 -Gtrace_p=0 cve20160728e.stp\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "processes_listening_int": [], - "processes_listening_ext": [], - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "processes_listening": [], - "processes_names": [], - "vulnerable_package": "openssl-libs-1.0.1e-34.el7" - }, - "id": 709784475, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned CVE-2016-0800 and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.

\n", - "generic_html": "

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "plugin": "CVE_2016_0800_openssl_drown", - "description": "OpenSSL vulnerable to very efficient session decryption (CVE-2016-0800/Special DROWN)", - "summary": "A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800) and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.", - "generic": "A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.\n\nA more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see [CVE-2015-0293](https://access.redhat.com/security/cve/CVE-2015-0293)).", - "reason": "

This host is vulnerable because it has vulnerable package openssl-libs-1.0.1e-34.el7 installed.

\n

This package does not have a patch for CVE-2015-0293 applied, which makes the system especially vulnerable. This is known as Special DROWN. An attacker can use this flaw to perform active man-in-the-middle (MITM) attacks and impersonate a TLS server to connecting TLS client in a matter of minutes.

\n

Fortunately, it does not seem to run any processes that use OpenSSL libraries.

\n

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2174451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 3, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update openssl and restart the affected system:

\n
# yum update openssl\n# reboot\n

Alternatively, you can restart all affected services (that is, the ones linked to the openssl library), especially those listening on public IP addresses.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "vulnerable_kernel": "3.10.0-123.el7", - "package_name": "kernel", - "error_key": "KERNEL_CVE_2016_5195" - }, - "id": 709784485, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.

\n", - "generic_html": "

A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.

\n

A process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "error_key": "KERNEL_CVE_2016_5195", - "plugin": "CVE_2016_5195_kernel", - "description": "Kernel vulnerable to privilege escalation via permission bypass (CVE-2016-5195)", - "summary": "A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.", - "generic": "A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.\n\nA process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally have read-only access to and thus increase their privileges on the system.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5195](https://access.redhat.com/security/cve/CVE-2016-5195)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2706661", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying mitigations until the machine is restarted with the updated kernel package.

\n

Please refer to the Resolve Tab in the vulnerability article for information about the mitigation and the latest information.

\n" - }, - "maintenance_actions": [{ - "done": false, - "id": 29885, - "maintenance_plan": { - "maintenance_id": 12195, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-jnewton", - "silenced": false, - "hidden": true, - "suggestion": "proposed", - "remote_branch": null - } - }] - }, { - "details": { - "package": "bash-4.2.45-5.el7", - "error_key": "VULNERABLE_BASH_DETECTED" - }, - "id": 709784505, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.

\n", - "generic_html": "

Hosts running earlier versions of bash are affected by the code injection vulnerability known as Shellshock.

\n", - "more_info_html": "

For further information about this critical vulnerability, see:

\n\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": true, - "ansible_mitigation": false, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "error_key": "VULNERABLE_BASH_DETECTED", - "plugin": "bash_injection", - "description": "Bash locally vulnerable via environment variables (CVE-2014-6271, CVE-2014-7169/Shellshock)", - "summary": "In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.", - "generic": "Hosts running earlier versions of `bash` are affected by the code injection vulnerability known as **Shellshock**.", - "reason": "

This host is running a version of bash that is affected by the code injection vulnerability known as Shellshock.

\n

The package affected is bash-4.2.45-5.el7.

\n", - "type": null, - "more_info": "For further information about this **critical** vulnerability, see:\n* [Bash Code Injection Vulnerability via Specially Crafted Environment Variables (CVE-2014-6271, CVE-2014-7169)](https://access.redhat.com/articles/1200223)\n* [CVE-2014-6271](https://access.redhat.com/security/cve/CVE-2014-6271)\n* [CVE-2014-7169](https://access.redhat.com/security/cve/CVE-2014-7169)", - "active": true, - "node_id": "1200223", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you upgrade bash immediately:

\n
# yum update bash\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "detected_problem_log_perms": [{ - "log_perms_dirfilename": "/var/log/cron", - "log_perms_sensitive": true, - "log_perms_ls_line": "-rw-r--r--. 1 root root 15438 May 25 10:01 cron" - }], - "error_key": "HARDENING_LOGGING_3_LOG_PERMS" - }, - "id": 709784525, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.

\n", - "generic_html": "

Issues related to system logging and auditing were detected on your system.

\n

Red Hat recommends that the logging service rsyslog and the auditing service auditd are enabled and that log files in /var/log have secure permissions.

\n", - "more_info_html": "\n", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "error_key": "HARDENING_LOGGING_3_LOG_PERMS", - "plugin": "hardening_logging_log_perms", - "description": "Decreased security in system logging permissions", - "summary": "Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.\n", - "generic": "Issues related to system logging and auditing were detected on your system.\n\nRed Hat recommends that the logging service `rsyslog` and the auditing service `auditd` are enabled and that log files in `/var/log` have secure permissions.\n", - "reason": "

Log files have permission issues.

\n

The following files or directories in /var/log have file permissions that differ from the default RHEL configuration and are possibly non-secure. Red Hat recommends that the file permissions be adjusted to more secure settings.

\n
{{ $index + ((" + list.iterator + "_page - 1) * " + list.iterator + "_page_size) + 1 }}.
"; - - for (field_action in list.fieldActions) { - if (field_action !== 'columnClass') { - if (list.fieldActions[field_action].type && list.fieldActions[field_action].type === 'DropDown') { - innerTable += DropDown({ - list: list, - fld: field_action, - options: options, - base: base, - type: 'fieldActions', - td: false - }); - } - if (field_action === 'pending_deletion') { - innerTable += `Pending Delete`; - } else if (field_action === 'submit') { - innerTable += ``; - } else { - // Plug in Dropdown Component - if (field_action === 'submit' && list.fieldActions[field_action].relaunch === true) { - innerTable += ``; - } else if (field_action === 'submit' && list.fieldActions[field_action].launch === true) { - innerTable += ``; - } else { - fAction = list.fieldActions[field_action]; - innerTable += ""; - } - } - } - } - innerTable += "
') - .addClass('col-xs-1 select-column List-tableHeader List-staticColumn--smallStatus') - .append( - $('') - .attr('selections-empty', 'selectedItems.length === 0') - .attr('items-length', list.name + '.length') - .attr('label', '')); - } - - if (options === undefined) { - options = this.options; - } - - html = "
# - - - Select"; - html += (list.fieldActions.label === undefined || list.fieldActions.label) ? i18n._("Actions") : ""; - html += "
\n \n \n \n \n \n\n\n\n\n\n\n\n
File or directory nameDetected problemOutput from ls -l
/var/log/cronUsers other than root can read or write.-rw-r--r--. 1 root root 15438 May 25 10:01 cron
\n\n\n\n", - "type": null, - "more_info": "* [Why is `/var/log/cron` world readable in RHEL7?](https://access.redhat.com/solutions/1491573)\n* [Using the chkconfig Utility](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-services-chkconfig.html) to configure services on RHEL 6\n* [Managing System Services](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Services.html) to configure services on RHEL 7\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2017-05-16T04:08:34.000Z", - "rec_impact": 1, - "rec_likelihood": 1, - "resolution": "

Red Hat recommends that you perform the following adjustments:

\n

Fixing permission issues depends on whether there is a designated safe group on your system that has Read access to the log files. This situation might exist if you want to allow certain administrators to see the log files without becoming root. To prevent log tampering, no other user than root should have permissions to Write to the log files. (The btmp and wtmp files are owned by the utmp group but other users should still be unable to write to them.)

\n

Fix for a default RHEL configuration

\n

(No designated group for reading log files)

\n
chown root:root /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n

Fix for a configuration with a designated safe group for reading log files

\n

In the following lines, substitute the name of your designated safe group for the string safegroup:

\n
chown root:safegroup /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "filesystems": [{ - "usage": "99", - "mountpoint": "/" - }, { - "usage": "99", - "mountpoint": "/" - }], - "error_key": "FILESYSTEM_CAPACITY" - }, - "id": 709784535, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "generic_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "more_info_html": "

How to increase the filesystem size?\nHow do I find out what is using disk space?

\n", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "error_key": "FILESYSTEM_CAPACITY", - "plugin": "filesystem_capacity", - "description": "Decreased stability and/or performance due to filesystem over 95% capacity", - "summary": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "generic": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "reason": "

This host has the following file systems nearing or at capacity:

\n
    \n\n
  • Filesystem: / Usage: 99%
  • \n\n
  • Filesystem: / Usage: 99%
  • \n\n
", - "type": null, - "more_info": "[How to increase the filesystem size?](https://access.redhat.com/solutions/21820)\n[How do I find out what is using disk space?](https://access.redhat.com/solutions/1154683)\n", - "active": true, - "node_id": "1154683", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 3, - "resolution": "

To solve the issue, Red Hat recommends that you either add more storage capacity to the identified file systems, or remove unnecessary files to reduce the current usage.\nPlease refer to more_information part for more detailed steps.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "msg": "[ 0.000000] crashkernel=auto resulted in zero bytes of reserved memory.", - "auto_with_low_ram": true, - "rhel_ver": 7, - "error_key": "CRASHKERNEL_RESERVATION_FAILED" - }, - "id": 709784555, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.

\n", - "generic_html": "

Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "more_info_html": "", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "error_key": "CRASHKERNEL_RESERVATION_FAILED", - "plugin": "crashkernel_reservation_failed", - "description": "Kdump crashkernel reservation failed due to improper configuration of crashkernel parameter", - "summary": "The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.\n", - "generic": "Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.", - "reason": "

This host is unable to reserve memory for the kdump kernel:

\n
[    0.000000] crashkernel=auto resulted in zero bytes of reserved memory.\n

This means the kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "59432", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 1, - "rec_likelihood": 3, - "resolution": "

To fix this issue, Red Hat recommends that you change the crashkernel setting in the grub.conf file.

\n

This host failed to reserved memory with auto crashkernel parameter due to low physical memory. The memory must be reserved by explicitly requesting the reservation size, for example: crashkernel=128M.

\n

For details of crashkernel setting, please refer to the Knowledge article How should the crashkernel parameter be configured for using kdump on RHEL7? to pickup the setting specifically for your host.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION" - }, - "id": 709784565, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "generic_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "more_info_html": "", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "plugin": "tzdata_need_upgrade", - "description": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale", - "summary": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "generic": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "reason": "

This system running as a non-NTP system is following the UTC timescale. In this situation, manual correction is required to avoid system clock inaccuracy when a leap second event happens.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "1465713", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 1, - "resolution": "

The system clock of this system needs manual correction when a leap second event happens. For example:

\n
\n\n# date -s \"20170101 HH:MM:SS\"\n\n
\n\n

You need to replace "HH:MM:SS" with the accurate time after the leap second occurs.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "selinux_info": true, - "package_name": "kernel", - "selinux_enforcing": true, - "selinux_can_help": true, - "minimal_selinux_policy": "selinux-policy-3.13.1-81.el7", - "selinux_enabled": true, - "vulnerable_kernel": "3.10.0-123.el7", - "active_policy": "selinux-policy-3.12.1-153.el7", - "dccp_loading_disabled": null, - "error_key": "KERNEL_CVE_2017_6074", - "enough_policy": false, - "dccp_loaded": null, - "mitigation_info": false - }, - "id": 709784575, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.

\n

An attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.

\n

Red Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "error_key": "KERNEL_CVE_2017_6074", - "plugin": "CVE_2017_6074_kernel", - "description": "Kernel vulnerable to local privilege escalation via DCCP module (CVE-2017-6074)", - "summary": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074). An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.\n", - "generic": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. \n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.\n\nAn attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.\n\nRed Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.\n", - "reason": "

A use-after-free flaw was found within the Linux kernel IPv6 DCCP network protocol code.

\n

This host is affected because:

\n
  • It is running kernel 3.10.0-123.el7.
  • SELinux policy is outdated.
\n\n\n\n\n\n\n

Your installed SELinux policy is selinux-policy-3.12.1-153.el7; however, to mitigate the issue, the earliest required version is selinux-policy-3.13.1-81.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074).\n* To learn how to upgrade packages, see [What is yum and how do I use it?](https://access.redhat.com/solutions/9934).\n* For more information about SELinux, see [Benefits of running SELinux](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/chap-Security-Enhanced_Linux-Introduction.html#sect-Security-Enhanced_Linux-Introduction-Benefits_of_running_SELinux).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n

Alternatively, apply one of the following mitigations:

\n
Update SELinux policy
\n

Update your SELinux policy:

\n
# yum update selinux-policy\n

The system does not provide enough information for Insights about loaded kernel modules. It is not possible to recommend a mitigation based on kernel modules.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "mitigation_conf": "no", - "sysctl_live_ack_limit": "100", - "package_name": "kernel", - "sysctl_live_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit = 100", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "vulnerable_kernel": "3.10.0-123.el7", - "sysctl_conf_ack_limit": "100", - "sysctl_conf_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit=100", - "mitigation_live": "no" - }, - "id": 766342155, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the RFC 5961 challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n", - "generic_html": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "plugin": "CVE_2016_5696_kernel", - "description": "Kernel vulnerable to man-in-the-middle via payload injection", - "summary": "A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the [RFC 5961](https://tools.ietf.org/html/rfc5961) challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.", - "generic": "A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack ([RFC 5961](https://tools.ietf.org/html/rfc5961)) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

Your currently loaded kernel configuration contains this setting:

\n
net.ipv4.tcp_challenge_ack_limit = 100\n

Your currently stored kernel configuration is:

\n
net.ipv4.tcp_challenge_ack_limit=100\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5696](https://access.redhat.com/security/cve/CVE-2016-5696)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2438571", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying the following mitigations until the machine is restarted with the updated kernel package.

\n

Edit /etc/sysctl.conf file as root, add the mitigation configuration, and reload the kernel configuration:

\n
# echo "net.ipv4.tcp_challenge_ack_limit = 2147483647" >> /etc/sysctl.conf \n# sysctl -p\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 56045, - "maintenance_plan": { - "maintenance_id": 15875, - "name": "Payload Injection Fix", - "description": "", - "start": "2017-06-01T02:00:00.000Z", - "end": "2017-06-01T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61575, - "maintenance_plan": { - "maintenance_id": 16825, - "name": "Summit 2017 Plan 1", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66175, - "maintenance_plan": { - "maintenance_id": 19435, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71015, - "maintenance_plan": { - "maintenance_id": 19835, - "name": "Optum Payload", - "description": "", - "start": "2017-05-27T02:00:00.000Z", - "end": "2017-05-27T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - }, { - "details": { - "mod_loading_disabled": null, - "package_name": "kernel", - "error_key": "KERNEL_CVE_2017_2636", - "vulnerable_kernel": "3.10.0-123.el7", - "mod_loaded": null, - "mitigation_info": false - }, - "id": 766342165, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as CVE-2017-2636.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.

\n

An attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.

\n

Red Hat recommends that you use the proposed mitigation to disable the N_HDLC module.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "error_key": "KERNEL_CVE_2017_2636", - "plugin": "CVE_2017_2636_kernel", - "description": "Kernel vulnerable to local privilege escalation via n_hdlc module (CVE-2017-2636)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636).\n", - "generic": "A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.\n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.\n\nAn attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.\n\nRed Hat recommends that you use the proposed mitigation to disable the N_HDLC module.\n", - "reason": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636) and [CVE-2017-2636 article](https://access.redhat.com/security/vulnerabilities/CVE-2017-2636).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 58335, - "maintenance_plan": { - "maintenance_id": 16545, - "name": "Insights Summit 2017 - n_HDLC", - "description": "", - "start": "2017-05-06T02:00:00.000Z", - "end": "2017-05-06T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61895, - "maintenance_plan": { - "maintenance_id": 16835, - "name": "Summit 2017 N_HDLC", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66225, - "maintenance_plan": { - "maintenance_id": 19445, - "name": "Seattle's Best Plan", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71075, - "maintenance_plan": { - "maintenance_id": 19845, - "name": "Optum N_HDLC FIX", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - }] -} diff --git a/awx/ui/test/spec/inventories/insights/data/low.insights-data.js b/awx/ui/test/spec/inventories/insights/data/low.insights-data.js deleted file mode 100644 index 568e1d76e488..000000000000 --- a/awx/ui/test/spec/inventories/insights/data/low.insights-data.js +++ /dev/null @@ -1,84 +0,0 @@ -export default [ - { - "details": { - "detected_problem_log_perms": [{ - "log_perms_dirfilename": "/var/log/cron", - "log_perms_sensitive": true, - "log_perms_ls_line": "-rw-r--r--. 1 root root 15438 May 25 10:01 cron" - }], - "error_key": "HARDENING_LOGGING_3_LOG_PERMS" - }, - "id": 709784525, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.

\n", - "generic_html": "

Issues related to system logging and auditing were detected on your system.

\n

Red Hat recommends that the logging service rsyslog and the auditing service auditd are enabled and that log files in /var/log have secure permissions.

\n", - "more_info_html": "\n", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "error_key": "HARDENING_LOGGING_3_LOG_PERMS", - "plugin": "hardening_logging_log_perms", - "description": "Decreased security in system logging permissions", - "summary": "Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.\n", - "generic": "Issues related to system logging and auditing were detected on your system.\n\nRed Hat recommends that the logging service `rsyslog` and the auditing service `auditd` are enabled and that log files in `/var/log` have secure permissions.\n", - "reason": "

Log files have permission issues.

\n

The following files or directories in /var/log have file permissions that differ from the default RHEL configuration and are possibly non-secure. Red Hat recommends that the file permissions be adjusted to more secure settings.

\n\n \n \n \n \n \n\n\n\n\n\n\n\n
File or directory nameDetected problemOutput from ls -l
/var/log/cronUsers other than root can read or write.-rw-r--r--. 1 root root 15438 May 25 10:01 cron
\n\n\n\n", - "type": null, - "more_info": "* [Why is `/var/log/cron` world readable in RHEL7?](https://access.redhat.com/solutions/1491573)\n* [Using the chkconfig Utility](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-services-chkconfig.html) to configure services on RHEL 6\n* [Managing System Services](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Services.html) to configure services on RHEL 7\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2017-05-16T04:08:34.000Z", - "rec_impact": 1, - "rec_likelihood": 1, - "resolution": "

Red Hat recommends that you perform the following adjustments:

\n

Fixing permission issues depends on whether there is a designated safe group on your system that has Read access to the log files. This situation might exist if you want to allow certain administrators to see the log files without becoming root. To prevent log tampering, no other user than root should have permissions to Write to the log files. (The btmp and wtmp files are owned by the utmp group but other users should still be unable to write to them.)

\n

Fix for a default RHEL configuration

\n

(No designated group for reading log files)

\n
chown root:root /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n

Fix for a configuration with a designated safe group for reading log files

\n

In the following lines, substitute the name of your designated safe group for the string safegroup:

\n
chown root:safegroup /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION" - }, - "id": 709784565, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "generic_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "more_info_html": "", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "plugin": "tzdata_need_upgrade", - "description": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale", - "summary": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "generic": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "reason": "

This system running as a non-NTP system is following the UTC timescale. In this situation, manual correction is required to avoid system clock inaccuracy when a leap second event happens.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "1465713", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 1, - "resolution": "

The system clock of this system needs manual correction when a leap second event happens. For example:

\n
\n\n# date -s \"20170101 HH:MM:SS\"\n\n
\n\n

You need to replace "HH:MM:SS" with the accurate time after the leap second occurs.

\n" - }, - "maintenance_actions": [] - } -] diff --git a/awx/ui/test/spec/inventories/insights/data/medium.insights-data.js b/awx/ui/test/spec/inventories/insights/data/medium.insights-data.js deleted file mode 100644 index 0e251f8d745a..000000000000 --- a/awx/ui/test/spec/inventories/insights/data/medium.insights-data.js +++ /dev/null @@ -1,418 +0,0 @@ -export default [ - { - "details": { - "affected_kernel": "3.10.0-123.el7", - "error_key": "KERNEL_CVE-2016-0728" - }, - "id": 709784465, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as CVE-2016-0728.

\n", - "generic_html": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

Red Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "error_key": "KERNEL_CVE-2016-0728", - "plugin": "CVE_2016_0728_kernel", - "description": "Kernel key management subsystem vulnerable to local privilege escalation (CVE-2016-0728)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).", - "generic": "A vulnerability in the Linux kernel rated **Important** was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n\nRed Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the [systemtap patch](https://bugzilla.redhat.com/attachment.cgi?id=1116284&action=edit) to update your running kernel.", - "reason": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

The host is vulnerable as it is running kernel-3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaws and versions of the package that are vulnerable see [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2130791", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:37.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update kernel and reboot. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n
# yum update kernel\n# reboot\n-or-\n# debuginfo-install kernel     (or equivalent)\n# stap -vgt -Gfix_p=1 -Gtrace_p=0 cve20160728e.stp\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "processes_listening_int": [], - "processes_listening_ext": [], - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "processes_listening": [], - "processes_names": [], - "vulnerable_package": "openssl-libs-1.0.1e-34.el7" - }, - "id": 709784475, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned CVE-2016-0800 and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.

\n", - "generic_html": "

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "plugin": "CVE_2016_0800_openssl_drown", - "description": "OpenSSL vulnerable to very efficient session decryption (CVE-2016-0800/Special DROWN)", - "summary": "A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800) and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.", - "generic": "A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.\n\nA more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see [CVE-2015-0293](https://access.redhat.com/security/cve/CVE-2015-0293)).", - "reason": "

This host is vulnerable because it has vulnerable package openssl-libs-1.0.1e-34.el7 installed.

\n

This package does not have a patch for CVE-2015-0293 applied, which makes the system especially vulnerable. This is known as Special DROWN. An attacker can use this flaw to perform active man-in-the-middle (MITM) attacks and impersonate a TLS server to connecting TLS client in a matter of minutes.

\n

Fortunately, it does not seem to run any processes that use OpenSSL libraries.

\n

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2174451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 3, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update openssl and restart the affected system:

\n
# yum update openssl\n# reboot\n

Alternatively, you can restart all affected services (that is, the ones linked to the openssl library), especially those listening on public IP addresses.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "vulnerable_kernel": "3.10.0-123.el7", - "package_name": "kernel", - "error_key": "KERNEL_CVE_2016_5195" - }, - "id": 709784485, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.

\n", - "generic_html": "

A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.

\n

A process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "error_key": "KERNEL_CVE_2016_5195", - "plugin": "CVE_2016_5195_kernel", - "description": "Kernel vulnerable to privilege escalation via permission bypass (CVE-2016-5195)", - "summary": "A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.", - "generic": "A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.\n\nA process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally have read-only access to and thus increase their privileges on the system.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5195](https://access.redhat.com/security/cve/CVE-2016-5195)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2706661", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying mitigations until the machine is restarted with the updated kernel package.

\n

Please refer to the Resolve Tab in the vulnerability article for information about the mitigation and the latest information.

\n" - }, - "maintenance_actions": [{ - "done": false, - "id": 29885, - "maintenance_plan": { - "maintenance_id": 12195, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-jnewton", - "silenced": false, - "hidden": true, - "suggestion": "proposed", - "remote_branch": null - } - }] - }, { - "details": { - "package": "bash-4.2.45-5.el7", - "error_key": "VULNERABLE_BASH_DETECTED" - }, - "id": 709784505, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.

\n", - "generic_html": "

Hosts running earlier versions of bash are affected by the code injection vulnerability known as Shellshock.

\n", - "more_info_html": "

For further information about this critical vulnerability, see:

\n\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": true, - "ansible_mitigation": false, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "error_key": "VULNERABLE_BASH_DETECTED", - "plugin": "bash_injection", - "description": "Bash locally vulnerable via environment variables (CVE-2014-6271, CVE-2014-7169/Shellshock)", - "summary": "In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.", - "generic": "Hosts running earlier versions of `bash` are affected by the code injection vulnerability known as **Shellshock**.", - "reason": "

This host is running a version of bash that is affected by the code injection vulnerability known as Shellshock.

\n

The package affected is bash-4.2.45-5.el7.

\n", - "type": null, - "more_info": "For further information about this **critical** vulnerability, see:\n* [Bash Code Injection Vulnerability via Specially Crafted Environment Variables (CVE-2014-6271, CVE-2014-7169)](https://access.redhat.com/articles/1200223)\n* [CVE-2014-6271](https://access.redhat.com/security/cve/CVE-2014-6271)\n* [CVE-2014-7169](https://access.redhat.com/security/cve/CVE-2014-7169)", - "active": true, - "node_id": "1200223", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you upgrade bash immediately:

\n
# yum update bash\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "filesystems": [{ - "usage": "99", - "mountpoint": "/" - }, { - "usage": "99", - "mountpoint": "/" - }], - "error_key": "FILESYSTEM_CAPACITY" - }, - "id": 709784535, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "generic_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "more_info_html": "

How to increase the filesystem size?\nHow do I find out what is using disk space?

\n", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "error_key": "FILESYSTEM_CAPACITY", - "plugin": "filesystem_capacity", - "description": "Decreased stability and/or performance due to filesystem over 95% capacity", - "summary": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "generic": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "reason": "

This host has the following file systems nearing or at capacity:

\n
    \n\n
  • Filesystem: / Usage: 99%
  • \n\n
  • Filesystem: / Usage: 99%
  • \n\n
", - "type": null, - "more_info": "[How to increase the filesystem size?](https://access.redhat.com/solutions/21820)\n[How do I find out what is using disk space?](https://access.redhat.com/solutions/1154683)\n", - "active": true, - "node_id": "1154683", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 3, - "resolution": "

To solve the issue, Red Hat recommends that you either add more storage capacity to the identified file systems, or remove unnecessary files to reduce the current usage.\nPlease refer to more_information part for more detailed steps.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "msg": "[ 0.000000] crashkernel=auto resulted in zero bytes of reserved memory.", - "auto_with_low_ram": true, - "rhel_ver": 7, - "error_key": "CRASHKERNEL_RESERVATION_FAILED" - }, - "id": 709784555, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.

\n", - "generic_html": "

Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "more_info_html": "", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "error_key": "CRASHKERNEL_RESERVATION_FAILED", - "plugin": "crashkernel_reservation_failed", - "description": "Kdump crashkernel reservation failed due to improper configuration of crashkernel parameter", - "summary": "The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.\n", - "generic": "Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.", - "reason": "

This host is unable to reserve memory for the kdump kernel:

\n
[    0.000000] crashkernel=auto resulted in zero bytes of reserved memory.\n

This means the kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "59432", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 1, - "rec_likelihood": 3, - "resolution": "

To fix this issue, Red Hat recommends that you change the crashkernel setting in the grub.conf file.

\n

This host failed to reserved memory with auto crashkernel parameter due to low physical memory. The memory must be reserved by explicitly requesting the reservation size, for example: crashkernel=128M.

\n

For details of crashkernel setting, please refer to the Knowledge article How should the crashkernel parameter be configured for using kdump on RHEL7? to pickup the setting specifically for your host.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "selinux_info": true, - "package_name": "kernel", - "selinux_enforcing": true, - "selinux_can_help": true, - "minimal_selinux_policy": "selinux-policy-3.13.1-81.el7", - "selinux_enabled": true, - "vulnerable_kernel": "3.10.0-123.el7", - "active_policy": "selinux-policy-3.12.1-153.el7", - "dccp_loading_disabled": null, - "error_key": "KERNEL_CVE_2017_6074", - "enough_policy": false, - "dccp_loaded": null, - "mitigation_info": false - }, - "id": 709784575, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.

\n

An attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.

\n

Red Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "error_key": "KERNEL_CVE_2017_6074", - "plugin": "CVE_2017_6074_kernel", - "description": "Kernel vulnerable to local privilege escalation via DCCP module (CVE-2017-6074)", - "summary": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074). An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.\n", - "generic": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. \n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.\n\nAn attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.\n\nRed Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.\n", - "reason": "

A use-after-free flaw was found within the Linux kernel IPv6 DCCP network protocol code.

\n

This host is affected because:

\n
  • It is running kernel 3.10.0-123.el7.
  • SELinux policy is outdated.
\n\n\n\n\n\n\n

Your installed SELinux policy is selinux-policy-3.12.1-153.el7; however, to mitigate the issue, the earliest required version is selinux-policy-3.13.1-81.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074).\n* To learn how to upgrade packages, see [What is yum and how do I use it?](https://access.redhat.com/solutions/9934).\n* For more information about SELinux, see [Benefits of running SELinux](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/chap-Security-Enhanced_Linux-Introduction.html#sect-Security-Enhanced_Linux-Introduction-Benefits_of_running_SELinux).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n

Alternatively, apply one of the following mitigations:

\n
Update SELinux policy
\n

Update your SELinux policy:

\n
# yum update selinux-policy\n

The system does not provide enough information for Insights about loaded kernel modules. It is not possible to recommend a mitigation based on kernel modules.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "mod_loading_disabled": null, - "package_name": "kernel", - "error_key": "KERNEL_CVE_2017_2636", - "vulnerable_kernel": "3.10.0-123.el7", - "mod_loaded": null, - "mitigation_info": false - }, - "id": 766342165, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as CVE-2017-2636.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.

\n

An attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.

\n

Red Hat recommends that you use the proposed mitigation to disable the N_HDLC module.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "error_key": "KERNEL_CVE_2017_2636", - "plugin": "CVE_2017_2636_kernel", - "description": "Kernel vulnerable to local privilege escalation via n_hdlc module (CVE-2017-2636)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636).\n", - "generic": "A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.\n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.\n\nAn attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.\n\nRed Hat recommends that you use the proposed mitigation to disable the N_HDLC module.\n", - "reason": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636) and [CVE-2017-2636 article](https://access.redhat.com/security/vulnerabilities/CVE-2017-2636).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 58335, - "maintenance_plan": { - "maintenance_id": 16545, - "name": "Insights Summit 2017 - n_HDLC", - "description": "", - "start": "2017-05-06T02:00:00.000Z", - "end": "2017-05-06T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61895, - "maintenance_plan": { - "maintenance_id": 16835, - "name": "Summit 2017 N_HDLC", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66225, - "maintenance_plan": { - "maintenance_id": 19445, - "name": "Seattle's Best Plan", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71075, - "maintenance_plan": { - "maintenance_id": 19845, - "name": "Optum N_HDLC FIX", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - } -] diff --git a/awx/ui/test/spec/inventories/insights/data/not_solvable.insights-data.js b/awx/ui/test/spec/inventories/insights/data/not_solvable.insights-data.js deleted file mode 100644 index 66469645856c..000000000000 --- a/awx/ui/test/spec/inventories/insights/data/not_solvable.insights-data.js +++ /dev/null @@ -1,381 +0,0 @@ -export default [ - { - "details": { - "vulnerable_setting": "hosts: files dns", - "affected_package": "glibc-2.17-55.el7", - "error_key": "GLIBC_CVE_2015_7547" - }, - "id": 709784455, - "rule_id": "CVE_2015_7547_glibc|GLIBC_CVE_2015_7547", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A critical security flaw in the glibc library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.

\n", - "generic_html": "

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2015_7547_glibc|GLIBC_CVE_2015_7547", - "error_key": "GLIBC_CVE_2015_7547", - "plugin": "CVE_2015_7547_glibc", - "description": "Remote code execution vulnerability in libresolv via crafted DNS response (CVE-2015-7547)", - "summary": "A critical security flaw in the `glibc` library was found. It allows an attacker to crash an application built against that library or, potentially, execute arbitrary code with privileges of the user running the application.", - "generic": "The `glibc` library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the `libresolv` part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when `libresolv` is called from the nss_dns NSS service module. This flaw is known as [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).", - "reason": "

This host is vulnerable because it has vulnerable package glibc-2.17-55.el7 installed and DNS is enabled in /etc/nsswitch.conf:

\n
hosts:      files dns\n

The glibc library is vulnerable to a stack-based buffer overflow security flaw. A remote attacker could create specially crafted DNS responses that could cause the libresolv part of the library, which performs dual A/AAAA DNS queries, to crash or potentially execute code with the permissions of the user running the library. The issue is only exposed when libresolv is called from the nss_dns NSS service module. This flaw is known as CVE-2015-7547.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2015-7547](https://access.redhat.com/security/cve/CVE-2015-7547).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2168451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:35.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating glibc and restarting the affected system:

\n
# yum update glibc\n# reboot\n

Alternatively, you can restart all affected services, but because this vulnerability affects a large amount of applications on the system, the best solution is to restart the system.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "affected_kernel": "3.10.0-123.el7", - "error_key": "KERNEL_CVE-2016-0728" - }, - "id": 709784465, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as CVE-2016-0728.

\n", - "generic_html": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

Red Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0728_kernel|KERNEL_CVE-2016-0728", - "error_key": "KERNEL_CVE-2016-0728", - "plugin": "CVE_2016_0728_kernel", - "description": "Kernel key management subsystem vulnerable to local privilege escalation (CVE-2016-0728)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).", - "generic": "A vulnerability in the Linux kernel rated **Important** was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n\nRed Hat recommends that you update the kernel and reboot the system. If you cannot reboot now, consider applying the [systemtap patch](https://bugzilla.redhat.com/attachment.cgi?id=1116284&action=edit) to update your running kernel.", - "reason": "

A vulnerability in the Linux kernel rated Important was discovered. The use-after-free flaw relates to the way the Linux kernel's key management subsystem handles keyring object reference counting in certain error paths of the join_session_keyring() function. A local, unprivileged user could use this flaw to escalate their privileges on the system. The issue was reported as CVE-2016-0728.

\n

The host is vulnerable as it is running kernel-3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaws and versions of the package that are vulnerable see [CVE-2016-0728](https://access.redhat.com/security/cve/cve-2016-0728).\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2130791", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:37.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update kernel and reboot. If you cannot reboot now, consider applying the systemtap patch to update your running kernel.

\n
# yum update kernel\n# reboot\n-or-\n# debuginfo-install kernel     (or equivalent)\n# stap -vgt -Gfix_p=1 -Gtrace_p=0 cve20160728e.stp\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "processes_listening_int": [], - "processes_listening_ext": [], - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "processes_listening": [], - "processes_names": [], - "vulnerable_package": "openssl-libs-1.0.1e-34.el7" - }, - "id": 709784475, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned CVE-2016-0800 and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.

\n", - "generic_html": "

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_0800_openssl_drown|OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "error_key": "OPENSSL_CVE_2016_0800_SPECIAL_DROWN", - "plugin": "CVE_2016_0800_openssl_drown", - "description": "OpenSSL vulnerable to very efficient session decryption (CVE-2016-0800/Special DROWN)", - "summary": "A new cross-protocol attack against SSLv2 protocol has been found. It has been assigned [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800) and is referred to as DROWN - Decrypting RSA using Obsolete and Weakened eNcryption. An attacker can decrypt passively collected TLS sessions between up-to-date client and server which supports SSLv2.", - "generic": "A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.\n\nA more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see [CVE-2015-0293](https://access.redhat.com/security/cve/CVE-2015-0293)).", - "reason": "

This host is vulnerable because it has vulnerable package openssl-libs-1.0.1e-34.el7 installed.

\n

This package does not have a patch for CVE-2015-0293 applied, which makes the system especially vulnerable. This is known as Special DROWN. An attacker can use this flaw to perform active man-in-the-middle (MITM) attacks and impersonate a TLS server to connecting TLS client in a matter of minutes.

\n

Fortunately, it does not seem to run any processes that use OpenSSL libraries.

\n

A new cross-protocol attack against a vulnerability in the SSLv2 protocol has been found. It can be used to passively decrypt collected TLS/SSL sessions from any connection that used an RSA key exchange cypher suite on a server that supports SSLv2. Even if a given service does not support SSLv2 the connection is still vulnerable if another service does and shares the same RSA private key.

\n

A more efficient variant of the attack exists against unpatched OpenSSL servers using versions that predate security advisories released on March 19, 2015 (see CVE-2015-0293).

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-0800](https://access.redhat.com/security/cve/CVE-2016-0800)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2174451", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 3, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update openssl and restart the affected system:

\n
# yum update openssl\n# reboot\n

Alternatively, you can restart all affected services (that is, the ones linked to the openssl library), especially those listening on public IP addresses.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "package": "bash-4.2.45-5.el7", - "error_key": "VULNERABLE_BASH_DETECTED" - }, - "id": 709784505, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.

\n", - "generic_html": "

Hosts running earlier versions of bash are affected by the code injection vulnerability known as Shellshock.

\n", - "more_info_html": "

For further information about this critical vulnerability, see:

\n\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": true, - "ansible_mitigation": false, - "rule_id": "bash_injection|VULNERABLE_BASH_DETECTED", - "error_key": "VULNERABLE_BASH_DETECTED", - "plugin": "bash_injection", - "description": "Bash locally vulnerable via environment variables (CVE-2014-6271, CVE-2014-7169/Shellshock)", - "summary": "In September 2014, an exploitable bug known as Shellshock was discovered in commonly shipped versions of the bash shell.", - "generic": "Hosts running earlier versions of `bash` are affected by the code injection vulnerability known as **Shellshock**.", - "reason": "

This host is running a version of bash that is affected by the code injection vulnerability known as Shellshock.

\n

The package affected is bash-4.2.45-5.el7.

\n", - "type": null, - "more_info": "For further information about this **critical** vulnerability, see:\n* [Bash Code Injection Vulnerability via Specially Crafted Environment Variables (CVE-2014-6271, CVE-2014-7169)](https://access.redhat.com/articles/1200223)\n* [CVE-2014-6271](https://access.redhat.com/security/cve/CVE-2014-6271)\n* [CVE-2014-7169](https://access.redhat.com/security/cve/CVE-2014-7169)", - "active": true, - "node_id": "1200223", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you upgrade bash immediately:

\n
# yum update bash\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "detected_problem_log_perms": [{ - "log_perms_dirfilename": "/var/log/cron", - "log_perms_sensitive": true, - "log_perms_ls_line": "-rw-r--r--. 1 root root 15438 May 25 10:01 cron" - }], - "error_key": "HARDENING_LOGGING_3_LOG_PERMS" - }, - "id": 709784525, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.

\n", - "generic_html": "

Issues related to system logging and auditing were detected on your system.

\n

Red Hat recommends that the logging service rsyslog and the auditing service auditd are enabled and that log files in /var/log have secure permissions.

\n", - "more_info_html": "\n", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "hardening_logging_log_perms|HARDENING_LOGGING_3_LOG_PERMS", - "error_key": "HARDENING_LOGGING_3_LOG_PERMS", - "plugin": "hardening_logging_log_perms", - "description": "Decreased security in system logging permissions", - "summary": "Issues related to system logging and auditing were detected on your system. Important services are disabled or log file permissions are not secure.\n", - "generic": "Issues related to system logging and auditing were detected on your system.\n\nRed Hat recommends that the logging service `rsyslog` and the auditing service `auditd` are enabled and that log files in `/var/log` have secure permissions.\n", - "reason": "

Log files have permission issues.

\n

The following files or directories in /var/log have file permissions that differ from the default RHEL configuration and are possibly non-secure. Red Hat recommends that the file permissions be adjusted to more secure settings.

\n\n \n \n \n \n \n\n\n\n\n\n\n\n
File or directory nameDetected problemOutput from ls -l
/var/log/cronUsers other than root can read or write.-rw-r--r--. 1 root root 15438 May 25 10:01 cron
\n\n\n\n", - "type": null, - "more_info": "* [Why is `/var/log/cron` world readable in RHEL7?](https://access.redhat.com/solutions/1491573)\n* [Using the chkconfig Utility](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-services-chkconfig.html) to configure services on RHEL 6\n* [Managing System Services](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Services.html) to configure services on RHEL 7\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2017-05-16T04:08:34.000Z", - "rec_impact": 1, - "rec_likelihood": 1, - "resolution": "

Red Hat recommends that you perform the following adjustments:

\n

Fixing permission issues depends on whether there is a designated safe group on your system that has Read access to the log files. This situation might exist if you want to allow certain administrators to see the log files without becoming root. To prevent log tampering, no other user than root should have permissions to Write to the log files. (The btmp and wtmp files are owned by the utmp group but other users should still be unable to write to them.)

\n

Fix for a default RHEL configuration

\n

(No designated group for reading log files)

\n
chown root:root /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n

Fix for a configuration with a designated safe group for reading log files

\n

In the following lines, substitute the name of your designated safe group for the string safegroup:

\n
chown root:safegroup /var/log/cron\nchmod u=rw,g-x,o-rwx /var/log/cron\n
" - }, - "maintenance_actions": [] - }, { - "details": { - "filesystems": [{ - "usage": "99", - "mountpoint": "/" - }, { - "usage": "99", - "mountpoint": "/" - }], - "error_key": "FILESYSTEM_CAPACITY" - }, - "id": 709784535, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "generic_html": "

File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.

\n", - "more_info_html": "

How to increase the filesystem size?\nHow do I find out what is using disk space?

\n", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "filesystem_capacity|FILESYSTEM_CAPACITY", - "error_key": "FILESYSTEM_CAPACITY", - "plugin": "filesystem_capacity", - "description": "Decreased stability and/or performance due to filesystem over 95% capacity", - "summary": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "generic": "File systems nearing full capacity can cause performance issues because blocks must be used from different block groups. \nBesides, file systems at or exceeding capacity will have stability issues because applications will no longer be able to write to the file system.\n", - "reason": "

This host has the following file systems nearing or at capacity:

\n
    \n\n
  • Filesystem: / Usage: 99%
  • \n\n
  • Filesystem: / Usage: 99%
  • \n\n
", - "type": null, - "more_info": "[How to increase the filesystem size?](https://access.redhat.com/solutions/21820)\n[How do I find out what is using disk space?](https://access.redhat.com/solutions/1154683)\n", - "active": true, - "node_id": "1154683", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:36.000Z", - "rec_impact": 2, - "rec_likelihood": 3, - "resolution": "

To solve the issue, Red Hat recommends that you either add more storage capacity to the identified file systems, or remove unnecessary files to reduce the current usage.\nPlease refer to more_information part for more detailed steps.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "msg": "[ 0.000000] crashkernel=auto resulted in zero bytes of reserved memory.", - "auto_with_low_ram": true, - "rhel_ver": 7, - "error_key": "CRASHKERNEL_RESERVATION_FAILED" - }, - "id": 709784555, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.

\n", - "generic_html": "

Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "more_info_html": "", - "severity": "WARN", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "crashkernel_reservation_failed|CRASHKERNEL_RESERVATION_FAILED", - "error_key": "CRASHKERNEL_RESERVATION_FAILED", - "plugin": "crashkernel_reservation_failed", - "description": "Kdump crashkernel reservation failed due to improper configuration of crashkernel parameter", - "summary": "The crashkernel configuration has failed to produce a working kdump environment. Configuration changes must be made to enable vmcore capture.\n", - "generic": "Kdump is unable to reserve memory for the kdump kernel. The kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.", - "reason": "

This host is unable to reserve memory for the kdump kernel:

\n
[    0.000000] crashkernel=auto resulted in zero bytes of reserved memory.\n

This means the kdump service has not started and a vmcore will not be captured if the host crashes, which will make it difficult for our support technicians to determine why the machine crashed.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "59432", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 1, - "rec_likelihood": 3, - "resolution": "

To fix this issue, Red Hat recommends that you change the crashkernel setting in the grub.conf file.

\n

This host failed to reserved memory with auto crashkernel parameter due to low physical memory. The memory must be reserved by explicitly requesting the reservation size, for example: crashkernel=128M.

\n

For details of crashkernel setting, please refer to the Knowledge article How should the crashkernel parameter be configured for using kdump on RHEL7? to pickup the setting specifically for your host.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION" - }, - "id": 709784565, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "generic_html": "

System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.

\n", - "more_info_html": "", - "severity": "INFO", - "ansible": false, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "tzdata_need_upgrade|TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "error_key": "TZDATA_NEED_UPGRADE_INFO_NEED_MANUAL_ACTION", - "plugin": "tzdata_need_upgrade", - "description": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale", - "summary": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "generic": "System clock inaccurate when a leap second event happens in a non-NTP system without following the TAI timescale.\n", - "reason": "

This system running as a non-NTP system is following the UTC timescale. In this situation, manual correction is required to avoid system clock inaccuracy when a leap second event happens.

\n", - "type": null, - "more_info": null, - "active": true, - "node_id": "1465713", - "category": "Stability", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 1, - "resolution": "

The system clock of this system needs manual correction when a leap second event happens. For example:

\n
\n\n# date -s \"20170101 HH:MM:SS\"\n\n
\n\n

You need to replace "HH:MM:SS" with the accurate time after the leap second occurs.

\n" - }, - "maintenance_actions": [] - }, { - "details": { - "selinux_info": true, - "package_name": "kernel", - "selinux_enforcing": true, - "selinux_can_help": true, - "minimal_selinux_policy": "selinux-policy-3.13.1-81.el7", - "selinux_enabled": true, - "vulnerable_kernel": "3.10.0-123.el7", - "active_policy": "selinux-policy-3.12.1-153.el7", - "dccp_loading_disabled": null, - "error_key": "KERNEL_CVE_2017_6074", - "enough_policy": false, - "dccp_loaded": null, - "mitigation_info": false - }, - "id": 709784575, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.

\n

An attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.

\n

Red Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_6074_kernel|KERNEL_CVE_2017_6074", - "error_key": "KERNEL_CVE_2017_6074", - "plugin": "CVE_2017_6074_kernel", - "description": "Kernel vulnerable to local privilege escalation via DCCP module (CVE-2017-6074)", - "summary": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074). An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system.\n", - "generic": "A use-after-free flaw was found in the Linux kernel IPv6 DCCP network protocol code. It has been assigned CVE-2017-6074. \n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. A local user could initiate a DCCP network connection on any local system network interface and then create specially-crafted memory allocations containing malicious instructions that can then either cause a crash or potentially escalate the user's privileges.\n\nAn attacker must have access to a local account on the system; this is not a remote attack and it requires IPv6 support to be enabled on the system.\n\nRed Hat recommends that you update the kernel when possible. Otherwise, you can use proposed mitigation to disable DCCP. SELinux in enforcing mode can also mitigate the issue under specific circumstances.\n", - "reason": "

A use-after-free flaw was found within the Linux kernel IPv6 DCCP network protocol code.

\n

This host is affected because:

\n
  • It is running kernel 3.10.0-123.el7.
  • SELinux policy is outdated.
\n\n\n\n\n\n\n

Your installed SELinux policy is selinux-policy-3.12.1-153.el7; however, to mitigate the issue, the earliest required version is selinux-policy-3.13.1-81.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-6074](https://access.redhat.com/security/cve/CVE-2017-6074).\n* To learn how to upgrade packages, see [What is yum and how do I use it?](https://access.redhat.com/solutions/9934).\n* For more information about SELinux, see [Benefits of running SELinux](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/chap-Security-Enhanced_Linux-Introduction.html#sect-Security-Enhanced_Linux-Introduction-Benefits_of_running_SELinux).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n

Alternatively, apply one of the following mitigations:

\n
Update SELinux policy
\n

Update your SELinux policy:

\n
# yum update selinux-policy\n

The system does not provide enough information for Insights about loaded kernel modules. It is not possible to recommend a mitigation based on kernel modules.

\n" - }, - "maintenance_actions": [] - } -] diff --git a/awx/ui/test/spec/inventories/insights/data/solvable.insights-data.js b/awx/ui/test/spec/inventories/insights/data/solvable.insights-data.js deleted file mode 100644 index 5e563e991202..000000000000 --- a/awx/ui/test/spec/inventories/insights/data/solvable.insights-data.js +++ /dev/null @@ -1,269 +0,0 @@ -export default [ - { - "details": { - "vulnerable_kernel": "3.10.0-123.el7", - "package_name": "kernel", - "error_key": "KERNEL_CVE_2016_5195" - }, - "id": 709784485, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.

\n", - "generic_html": "

A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.

\n

A process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5195_kernel|KERNEL_CVE_2016_5195", - "error_key": "KERNEL_CVE_2016_5195", - "plugin": "CVE_2016_5195_kernel", - "description": "Kernel vulnerable to privilege escalation via permission bypass (CVE-2016-5195)", - "summary": "A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally only have read-only access to and thus increase their privileges on the system.", - "generic": "A race condition was found in the way Linux kernel's memory subsystem handled breakage of the the read only shared mappings COW situation on write access. An unprivileged local user could use this flaw to write to files they should normally have read-only access to, and thus increase their privileges on the system.\n\nA process that is able to mmap a file is able to race Copy on Write (COW) page creation (within get_user_pages) with madvise(MADV_DONTNEED) kernel system calls. This would allow modified pages to bypass the page protection mechanism and modify the mapped file. The vulnerability could be abused by allowing an attacker to modify existing setuid files with instructions to elevate permissions. This attack has been found in the wild. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the Linux kernel's memory subsystem. An unprivileged local user could use this flaw to write to files they would normally have read-only access to and thus increase their privileges on the system.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5195](https://access.redhat.com/security/cve/CVE-2016-5195)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2706661", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:33.000Z", - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying mitigations until the machine is restarted with the updated kernel package.

\n

Please refer to the Resolve Tab in the vulnerability article for information about the mitigation and the latest information.

\n" - }, - "maintenance_actions": [{ - "done": false, - "id": 29885, - "maintenance_plan": { - "maintenance_id": 12195, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-jnewton", - "silenced": false, - "hidden": true, - "suggestion": "proposed", - "remote_branch": null - } - }] - }, - { - "details": { - "mitigation_conf": "no", - "sysctl_live_ack_limit": "100", - "package_name": "kernel", - "sysctl_live_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit = 100", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "vulnerable_kernel": "3.10.0-123.el7", - "sysctl_conf_ack_limit": "100", - "sysctl_conf_ack_limit_line": "net.ipv4.tcp_challenge_ack_limit=100", - "mitigation_live": "no" - }, - "id": 766342155, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the RFC 5961 challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n", - "generic_html": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

Red Hat recommends that you update the kernel package or apply mitigations.

\n", - "more_info_html": "\n", - "severity": "ERROR", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2016_5696_kernel|KERNEL_CVE_2016_5696_URGENT", - "error_key": "KERNEL_CVE_2016_5696_URGENT", - "plugin": "CVE_2016_5696_kernel", - "description": "Kernel vulnerable to man-in-the-middle via payload injection", - "summary": "A flaw in the Linux kernel's TCP/IP networking subsystem implementation of the [RFC 5961](https://tools.ietf.org/html/rfc5961) challenge ACK rate limiting was found that could allow an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.", - "generic": "A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack ([RFC 5961](https://tools.ietf.org/html/rfc5961)) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack. \n\nRed Hat recommends that you update the kernel package or apply mitigations.", - "reason": "

A flaw was found in the implementation of the Linux kernel's handling of networking challenge ack (RFC 5961) where an attacker is able to determine the\nshared counter. This flaw allows an attacker located on different subnet to inject or take over a TCP connection between a server and client without needing to use a traditional man-in-the-middle (MITM) attack.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n

Your currently loaded kernel configuration contains this setting:

\n
net.ipv4.tcp_challenge_ack_limit = 100\n

Your currently stored kernel configuration is:

\n
net.ipv4.tcp_challenge_ack_limit=100\n

There is currently no mitigation applied and your system is vulnerable.

\n", - "type": null, - "more_info": "* For more information about the flaw see [CVE-2016-5696](https://access.redhat.com/security/cve/CVE-2016-5696)\n* To learn how to upgrade packages, see \"[What is yum and how do I use it?](https://access.redhat.com/solutions/9934)\"\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat Products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).", - "active": true, - "node_id": "2438571", - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": "2016-10-31T04:08:32.000Z", - "rec_impact": 4, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends that you update the kernel package and restart the system:

\n
# yum update kernel\n# reboot\n

or

\n

Alternatively, this issue can be addressed by applying the following mitigations until the machine is restarted with the updated kernel package.

\n

Edit /etc/sysctl.conf file as root, add the mitigation configuration, and reload the kernel configuration:

\n
# echo "net.ipv4.tcp_challenge_ack_limit = 2147483647" >> /etc/sysctl.conf \n# sysctl -p\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 56045, - "maintenance_plan": { - "maintenance_id": 15875, - "name": "Payload Injection Fix", - "description": "", - "start": "2017-06-01T02:00:00.000Z", - "end": "2017-06-01T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61575, - "maintenance_plan": { - "maintenance_id": 16825, - "name": "Summit 2017 Plan 1", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66175, - "maintenance_plan": { - "maintenance_id": 19435, - "name": null, - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71015, - "maintenance_plan": { - "maintenance_id": 19835, - "name": "Optum Payload", - "description": "", - "start": "2017-05-27T02:00:00.000Z", - "end": "2017-05-27T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - }, - { - "details": { - "mod_loading_disabled": null, - "package_name": "kernel", - "error_key": "KERNEL_CVE_2017_2636", - "vulnerable_kernel": "3.10.0-123.el7", - "mod_loaded": null, - "mitigation_info": false - }, - "id": 766342165, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "system_id": "f31b6265939d4a8492d3ce9655dc94be", - "account_number": "540155", - "uuid": "d195e3c5e5e6469781c4e59fa3f5ba87", - "date": "2017-05-25T14:01:19.000Z", - "rule": { - "summary_html": "

A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as CVE-2017-2636.

\n", - "generic_html": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.

\n

An unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.

\n

An attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.

\n

Red Hat recommends that you use the proposed mitigation to disable the N_HDLC module.

\n", - "more_info_html": "\n", - "severity": "WARN", - "ansible": true, - "ansible_fix": false, - "ansible_mitigation": false, - "rule_id": "CVE_2017_2636_kernel|KERNEL_CVE_2017_2636", - "error_key": "KERNEL_CVE_2017_2636", - "plugin": "CVE_2017_2636_kernel", - "description": "Kernel vulnerable to local privilege escalation via n_hdlc module (CVE-2017-2636)", - "summary": "A vulnerability in the Linux kernel allowing local privilege escalation was discovered.\nThe issue was reported as [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636).\n", - "generic": "A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation. It has been assigned CVE-2017-2636.\n\nAn unprivileged local user could use this flaw to execute arbitrary code in kernel memory and increase their privileges on the system. The kernel uses a TTY subsystem to take and show terminal output to connected systems. An attacker crafting specific-sized memory allocations could abuse this mechanism to place a kernel function pointer with malicious instructions to be executed on behalf of the attacker.\n\nAn attacker must have access to a local account on the system; this is not a remote attack. Exploiting this flaw does not require Microgate or SyncLink hardware to be in use.\n\nRed Hat recommends that you use the proposed mitigation to disable the N_HDLC module.\n", - "reason": "

A use-after-free flaw was found in the Linux kernel implementation of the HDLC (High-Level Data Link Control) TTY line discipline implementation.

\n

This host is affected because it is running kernel 3.10.0-123.el7.

\n", - "type": null, - "more_info": "* For more information about the flaw, see [CVE-2017-2636](https://access.redhat.com/security/cve/CVE-2017-2636) and [CVE-2017-2636 article](https://access.redhat.com/security/vulnerabilities/CVE-2017-2636).\n* The Customer Portal page for the [Red Hat Security Team](https://access.redhat.com/security/) contains more information about policies, procedures, and alerts for Red Hat products.\n* The Security Team also maintains a frequently updated blog at [securityblog.redhat.com](https://securityblog.redhat.com).\n", - "active": true, - "node_id": null, - "category": "Security", - "retired": false, - "reboot_required": false, - "publish_date": null, - "rec_impact": 2, - "rec_likelihood": 2, - "resolution": "

Red Hat recommends updating the kernel package and rebooting the system.

\n
# yum update kernel\n# reboot\n
" - }, - "maintenance_actions": [{ - "done": false, - "id": 58335, - "maintenance_plan": { - "maintenance_id": 16545, - "name": "Insights Summit 2017 - n_HDLC", - "description": "", - "start": "2017-05-06T02:00:00.000Z", - "end": "2017-05-06T03:00:00.000Z", - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 61895, - "maintenance_plan": { - "maintenance_id": 16835, - "name": "Summit 2017 N_HDLC", - "description": "", - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 66225, - "maintenance_plan": { - "maintenance_id": 19445, - "name": "Seattle's Best Plan", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }, { - "done": false, - "id": 71075, - "maintenance_plan": { - "maintenance_id": 19845, - "name": "Optum N_HDLC FIX", - "description": null, - "start": null, - "end": null, - "created_by": "rhn-support-wnix", - "silenced": false, - "hidden": false, - "suggestion": null, - "remote_branch": null - } - }] - } -] diff --git a/awx/ui/test/spec/inventories/insights/insights.service-test.js b/awx/ui/test/spec/inventories/insights/insights.service-test.js deleted file mode 100644 index 93024a86b9a9..000000000000 --- a/awx/ui/test/spec/inventories/insights/insights.service-test.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -import insights_json from './data/insights-data.js'; -import solvable_insights_json from './data/solvable.insights-data.js'; -import not_solvable_insights_json from './data/not_solvable.insights-data.js'; -import high_insights_json from './data/high.insights-data.js'; -import medium_insights_json from './data/medium.insights-data.js'; -import low_insights_json from './data/low.insights-data.js'; - -describe('Service: InsightsService', () => { - let InsightsService; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(angular.mock.inject(( _InsightsService_) => { - InsightsService = _InsightsService_; - })); - - describe('filter()', () => { - it('filter for "total" returns the total set of reports', () => { - let filteredSet = InsightsService.filter('total', insights_json.reports); - expect(filteredSet).toEqual(insights_json.reports); - expect(filteredSet.length).toBe(12); - }); - - it('properly filters the reports dataset for solvable reports', () => { - let filteredSet = InsightsService.filter('solvable', insights_json.reports); - expect(filteredSet).toEqual(solvable_insights_json); - expect(filteredSet.length).toBe(3); - }); - - it('properly filters the reports dataset for not-solvable reports', () => { - let filteredSet = InsightsService.filter('not_solvable', insights_json.reports); - expect(filteredSet).toEqual(not_solvable_insights_json); - expect(filteredSet.length).toBe(9); - }); - - it('properly filters the reports dataset for CRITICAL reports', () => { - let filteredSet = InsightsService.filter('critical', insights_json.reports); - expect(filteredSet).toEqual([]); - expect(filteredSet.length).toBe(0); - }); - - it('properly filters the reports dataset for ERROR reports', () => { - let filteredSet = InsightsService.filter('high', insights_json.reports); - expect(filteredSet).toEqual(high_insights_json); - expect(filteredSet.length).toBe(2); - }); - - it('properly filters the reports dataset for WARN reports', () => { - let filteredSet = InsightsService.filter('medium', insights_json.reports); - expect(filteredSet).toEqual(medium_insights_json); - expect(filteredSet.length).toBe(8); - }); - - it('properly filters the reports dataset for INFO reports', () => { - let filteredSet = InsightsService.filter('low', insights_json.reports); - expect(filteredSet).toEqual(low_insights_json); - expect(filteredSet.length).toBe(2); - }); - }); -}); diff --git a/awx/ui/test/spec/inventories/manage/inventory-manage.service-test.js b/awx/ui/test/spec/inventories/manage/inventory-manage.service-test.js deleted file mode 100644 index c72e49c32e1d..000000000000 --- a/awx/ui/test/spec/inventories/manage/inventory-manage.service-test.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -describe('Service: InventoriesService', () => { - - let Rest, - InventoriesService; - - beforeEach(angular.mock.module('awApp'), ($provide)=>{ - $provide.value('Rest', Rest); - }); - beforeEach(angular.mock.module('inventoryManage')); - beforeEach(angular.mock.inject(($httpBackend, _InventoriesService_) =>{ - Rest = $httpBackend; - InventoriesService = _InventoriesService_; - })); - - xdescribe('RESTy methods should handle errors', () => { - - beforeEach(() => { - spyOn(InventoriesService, 'error'); - }); - it('InventoriesService.getInventory should handle errors', () => { - Rest.expectGET('/api/v2/inventory:id/').respond(400, {}); - Rest.flush(); - expect(InventoriesService.error).toHaveBeenCalled(); - }); - }); - - // Unit tests often reveal which pieces of our code should be factored out - xit('RESTy methods should start/stop spinny', function(){ - - }); - - afterEach(function() { - Rest.verifyNoOutstandingExpectation(); - Rest.verifyNoOutstandingRequest(); - }); -}); diff --git a/awx/ui/test/spec/karma.spec.js b/awx/ui/test/spec/karma.spec.js deleted file mode 100644 index 104f8d9ba8a6..000000000000 --- a/awx/ui/test/spec/karma.spec.js +++ /dev/null @@ -1,40 +0,0 @@ -const path = require('path'); - -const SRC_PATH = path.resolve(__dirname, '../../client/src'); -const NODE_MODULES = path.resolve(__dirname, '../../node_modules'); - -const webpackConfig = require('./webpack.spec'); - -module.exports = config => { - config.set({ - basePath: '../..', - autoWatch: true, - colors: true, - browsers: ['Chrome', 'Firefox'], - frameworks: ['jasmine'], - reporters: ['progress', 'junit'], - files:[ - 'test/spec/polyfills.js', - 'client/src/vendor.js', - path.join(NODE_MODULES, 'angular-mocks/angular-mocks.js'), - path.join(SRC_PATH, 'app.js'), - 'client/src/**/*.html', - 'test/spec/**/*-test.js', - ], - preprocessors: { - 'client/src/vendor.js': 'webpack', - [path.join(SRC_PATH, 'app.js')]: 'webpack', - 'client/src/**/*.html': 'html2js', - 'test/spec/**/*-test.js': 'webpack' - }, - webpack: webpackConfig, - webpackMiddleware: { - noInfo: true - }, - junitReporter: { - outputDir: 'reports', - outputFile: 'results.spec.xml', - useBrowserName: false - } - }); -}; diff --git a/awx/ui/test/spec/license/license.controller-test.js b/awx/ui/test/spec/license/license.controller-test.js deleted file mode 100644 index eb013776b4f1..000000000000 --- a/awx/ui/test/spec/license/license.controller-test.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -describe('Controller: LicenseController', () => { - // Setup - let scope, - LicenseController, - ConfigService, - ProcessErrors, - config; - - beforeEach(angular.mock.module('awApp')); - beforeEach(angular.mock.module('license', ($provide) => { - ConfigService = jasmine.createSpyObj('ConfigService', [ - 'getConfig', - 'delete' - ]); - - config = { - license_info: { - time_remaining: 1234567 // seconds - }, - version: '3.1.0-devel' - }; - - ProcessErrors = jasmine.createSpy('ProcessErrors'); - - $provide.value('ConfigService', ConfigService); - $provide.value('ProcessErrors', ProcessErrors); - $provide.value('config', config); - })); - - beforeEach(angular.mock.inject( ($rootScope, $controller, _ConfigService_, _ProcessErrors_, _config_) => { - scope = $rootScope.$new(); - ConfigService = _ConfigService_; - ProcessErrors = _ProcessErrors_; - config = _config_; - LicenseController = $controller('licenseController', { - $scope: scope, - ConfigService: ConfigService, - ProcessErrors: ProcessErrors, - config: config - }); - })); - - xit('should show correct expiration date', ()=>{ - let date = new Date(), - options = { - year: 'numeric', - month: '2-digit', - day: '2-digit' - }; - date.setDate(date.getDate() + 14); - expect(scope.time.expiresOn).toEqual(date.toLocaleDateString(undefined, options)); - }); - - it('should show correct time remaining', ()=>{ - expect(scope.time.remaining).toMatch('14 Days'); - }); - - xit('should throw an error if provided license is invalid JSON', ()=>{ - let event = { - target: {files: [new File(['asdf'], 'license.txt', {type: 'text/html'})]} - }; - scope.getKey(event); - expect(ProcessErrors).toHaveBeenCalled(); - }); - - xit('should submit a valid license'); -}); diff --git a/awx/ui/test/spec/lookup/lookup-modal.directive-test.js b/awx/ui/test/spec/lookup/lookup-modal.directive-test.js deleted file mode 100644 index cdd4d16cc973..000000000000 --- a/awx/ui/test/spec/lookup/lookup-modal.directive-test.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; - -xdescribe('Directive: lookupModal', () => { - - let dom, element, listHtml, listDefinition, Dataset, - lookupTemplate, paginateTemplate, searchTemplate, columnSortTemplate, - $scope, $parent, $compile, $state; - - // mock dependency chains - // (shared requires RestServices requires Authorization etc) - beforeEach(angular.mock.module('login')); - beforeEach(angular.mock.module('shared')); - - beforeEach(angular.mock.module('LookupModalModule', ($provide) => { - $provide.value('smartSearch', angular.noop); - $provide.value('columnSort', angular.noop); - $provide.value('paginate', angular.noop); - $state = jasmine.createSpyObj('$state', ['go']); - })); - - beforeEach(angular.mock.inject(($templateCache, _$rootScope_, _$compile_, _generateList_) => { - listDefinition = { - name: 'mocks', - iterator: 'mock', - fields: { - name: {} - } - }; - - listHtml = _generateList_.build({ - mode: 'lookup', - list: listDefinition, - input_type: 'radio' - }); - - Dataset = { - data: { - results: [ - { id: 1, name: 'Mock Resource 1' }, - { id: 2, name: 'Mock Resource 2' }, - { id: 3, name: 'Mock Resource 3' }, - { id: 4, name: 'Mock Resource 4' }, - { id: 5, name: 'Mock Resource 5' }, - ] - } - }; - - dom = angular.element(`${listHtml}`); - - // populate $templateCache with directive.templateUrl at test runtime, - lookupTemplate = window.__html__['client/src/shared/lookup/lookup-modal.partial.html']; - paginateTemplate = window.__html__['client/src/shared/paginate/paginate.partial.html']; - searchTemplate = window.__html__['client/src/shared/smart-search/smart-search.partial.html']; - columnSortTemplate = window.__html__['client/src/shared/column-sort/column-sort.partial.html']; - - $templateCache.put('/static/partials/shared/lookup/lookup-modal.partial.html', lookupTemplate); - $templateCache.put('/static/partials/shared/paginate/paginate.partial.html', paginateTemplate); - $templateCache.put('/static/partials/shared/smart-search/smart-search.partial.html', searchTemplate); - $templateCache.put('/static/partials/shared/column-sort/column-sort.partial.html', columnSortTemplate); - - $compile = _$compile_; - $parent = _$rootScope_.$new(); - - // mock resolvables - $scope = $parent.$new(); - $scope.$resolve = { - ListDefinition: listDefinition, - Dataset: Dataset - }; - })); - - it('Resource is pre-selected in form - corresponding radio should initialize checked', () => { - $parent.mock = 1; // resource id - $parent.mock_name = 'Mock Resource 1'; // resource name - - console.log($scope); - - element = $compile(dom)($scope); - $scope.$digest(); - - expect($(':radio')[0].is(':checked')).toEqual(true); - }); - - it('No resource pre-selected in form - no radio should initialize checked', () => { - element = $compile(dom)($scope); - $scope.$digest(); - - _.forEach($(':radio'), (radio) => { - expect(radio.is('checked')).toEqual(false); - }); - }); - - it('Should update $parent / form scope and exit $state on save', () => { - element = $compile(dom)($scope); - $scope.$digest(); - $(':radio')[1].click(); - $('.Lookup-save')[0].click(); - - expect($parent.mock).toEqual(2); - expect($parent.mock_name).toEqual('Mock Resource 2'); - expect($state.go).toHaveBeenCalled(); - }); - - it('Should not update $parent / form scope on exit via header', () => { - $parent.mock = 3; // resource id - $parent.mock_name = 'Mock Resource 3'; // resource name - element = $compile(dom)($scope); - $scope.$digest(); - - $(':radio')[1].click(); - $('.Form-exit')[0].click(); - - expect($parent.mock).toEqual(3); - expect($parent.mock_name).toEqual('Mock Resource 3'); - expect($state.go).toHaveBeenCalled(); - }); - - it('Should not update $parent / form scope on exit via cancel button', () => { - $parent.mock = 3; // resource id - $parent.mock_name = 'Mock Resource 3'; // resource name - element = $compile(dom)($scope); - $scope.$digest(); - - $(':radio')[1].click(); - $('.Lookup-cancel')[0].click(); - - expect($parent.mock).toEqual(3); - expect($parent.mock_name).toEqual('Mock Resource 3'); - expect($state.go).toHaveBeenCalled(); - }); -}); diff --git a/awx/ui/test/spec/paginate/paginate.directive-test.js b/awx/ui/test/spec/paginate/paginate.directive-test.js deleted file mode 100644 index b8d180272598..000000000000 --- a/awx/ui/test/spec/paginate/paginate.directive-test.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -xdescribe('Directive: Paginate', () => { - var dom = angular.element(''), - template, - element, - $scope, - $compile, - $state, - $stateParams = {}; - - beforeEach(angular.mock.module('shared'), ($provide) =>{ - $provide.value('Rest', angular.noop); - }); - beforeEach(angular.mock.module('PaginateModule', ($provide) => { - $state = jasmine.createSpyObj('$state', ['go']); - - $provide.value('$stateParams', $stateParams); - $provide.value('Rest', angular.noop); - })); - beforeEach(angular.mock.inject(($templateCache, _$rootScope_, _$compile_) => { - // populate $templateCache with directive.templateUrl at test runtime, - template = window.__html__['client/src/shared/paginate/paginate.partial.html']; - $templateCache.put('/static/partials/shared/paginate/paginate.partial.html', template); - - $compile = _$compile_; - $scope = _$rootScope_.$new(); - })); - - it('should be hidden if only 1 page of data', () => { - - $scope.mock_dataset = {count: 19}; - $scope.pageSize = 20; - element = $compile(dom)($scope); - $scope.$digest(); - - expect($('.Paginate-wrapper', element)).hasClass('ng-hide'); - }); - describe('it should show expected page range', () => { - - - it('should show 7 pages', () =>{ - - $scope.pageSize = 1; - $scope.mock_dataset = {count: 7}; - element = $compile(dom)($scope); - $scope.$digest(); - // next, previous, 7 pages - expect($('.Paginate-controls--item', element)).length.toEqual(9); - }); - it('should show 100 pages', () =>{ - $scope.pageSize = 1; - $scope.mock_dataset = {count: 100}; - element = $compile(dom)($scope); - $scope.$digest(); - // first, next, previous, last, 100 pages - expect($('.Paginate-controls--item', element)).length.toEqual(104); - }); - }); - describe('it should get expected page', () => { - - it('should get the next page', () =>{ - - $scope.mock_dataset = { - count: 42, - }; - - $stateParams.mock_search = { - page_size: 5, - page: 1 - }; - - element = $compile(dom)($scope); - $('.Paginate-controls--next').click(); - expect($stateParams.mock_search.page).toEqual(2); - }); - - it('should get the previous page', ()=>{ - - $scope.mock_dataset = { - count: 42 - }; - $stateParams.mock_search = { - page_size: 10, - page: 3 - }; - - element = $compile(dom)($scope); - $('.Paginate-controls--previous'); - expect($stateParams.mock_search.page).toEqual(2); - }); - it('should get the last page', ()=>{ - $scope.mock_dataset = { - count: 110 - }; - $stateParams.mock_search = { - page_size: 5, - page: 1 - }; - $('.Paginate-controls--last').click(); - expect($stateParams.mock_search.page).toEqual(42); - }); - it('should get the first page', () => { - $scope.mock_dataset = { - count: 110 - }; - $stateParams.mock_search = { - page_size: 5, - page: 35 - }; - $('.Paginate-controls--first').click(); - expect($stateParams.mock_search.page).toEqual(1); - }); - - }); -}); diff --git a/awx/ui/test/spec/polyfills.js b/awx/ui/test/spec/polyfills.js deleted file mode 100644 index 8b7342e5fda5..000000000000 --- a/awx/ui/test/spec/polyfills.js +++ /dev/null @@ -1,31 +0,0 @@ -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill - -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} diff --git a/awx/ui/test/spec/shared/filters/append.filter-test.js b/awx/ui/test/spec/shared/filters/append.filter-test.js deleted file mode 100644 index b687797aefde..000000000000 --- a/awx/ui/test/spec/shared/filters/append.filter-test.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -describe('Filter: append', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('append'); - }); - }); - - it('should append the two parameters passed', function(){ - expect(filter("foo", "bar")).toBe("foobar"); - }); - - it('should return string if no append param passed', function(){ - expect(filter("foo")).toBe("foo"); - }); - - it('should return empty string if no params passed', function(){ - expect(filter()).toBe(""); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/capitalize.filter-test.js b/awx/ui/test/spec/shared/filters/capitalize.filter-test.js deleted file mode 100644 index 671385ce4ada..000000000000 --- a/awx/ui/test/spec/shared/filters/capitalize.filter-test.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -describe('Filter: capitalize', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('capitalize'); - }); - }); - - it('should capitalize the first letter', function(){ - expect(filter("foo")).toBe("Foo"); - expect(filter("Foo")).toBe("Foo"); - expect(filter("FOO")).toBe("Foo"); - expect(filter("FoO")).toBe("Foo"); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/format-epoch.filter-test.js b/awx/ui/test/spec/shared/filters/format-epoch.filter-test.js deleted file mode 100644 index 5b6d54d2858f..000000000000 --- a/awx/ui/test/spec/shared/filters/format-epoch.filter-test.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -describe('Filter: formatEpoch', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('formatEpoch'); - }); - }); - - // TODO: this test is opinionated - it assumes that the - // system date on the machine that's running it is EST. - // I'm not quite sure how to foce a moment to use a specific - // timezone. If we can figure that out then we can re-enable - // these tests. - - xit('should convert epoch to datetime string', function(){ - expect(filter(11111)).toBe("Dec 31, 1969 10:05 PM"); - expect(filter(610430400)).toBe("May 6, 1989 12:00 AM"); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/is-empty.filter-test.js b/awx/ui/test/spec/shared/filters/is-empty.filter-test.js deleted file mode 100644 index db6c87ea2aad..000000000000 --- a/awx/ui/test/spec/shared/filters/is-empty.filter-test.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -describe('Filter: isEmpty', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('isEmpty'); - }); - }); - - it('check if an object is empty', function(){ - expect(filter({})).toBe(true); - expect(filter({foo: 'bar'})).toBe(false); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/long-date.filter-test.js b/awx/ui/test/spec/shared/filters/long-date.filter-test.js deleted file mode 100644 index 3bd3857f7a6e..000000000000 --- a/awx/ui/test/spec/shared/filters/long-date.filter-test.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -describe('Filter: longDate', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('longDate'); - }); - }); - - // TODO: this test is opinionated - it assumes that the - // system date on the machine that's running it is EST. - // I'm not quite sure how to foce a moment to use a specific - // timezone. If we can figure that out then we can re-enable - // these tests. - - xit('should convert the timestamp to a UI friendly date and time', function(){ - expect(filter("2017-02-13T22:00:14.106Z")).toBe("2/13/2017 5:00:14 PM"); - }); - it('should return an empty string if no timestamp is passed', function(){ - expect(filter()).toBe(""); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/prepend.filter-test.js b/awx/ui/test/spec/shared/filters/prepend.filter-test.js deleted file mode 100644 index 424b023fe8da..000000000000 --- a/awx/ui/test/spec/shared/filters/prepend.filter-test.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -describe('Filter: prepend', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('prepend'); - }); - }); - - it('should prepend the second param to the first', function(){ - expect(filter("foo", "bar")).toBe("barfoo"); - }); - - it('should return string if no prepend param passed', function(){ - expect(filter("foo")).toBe("foo"); - }); - - it('should return empty string if no params passed', function(){ - expect(filter()).toBe(""); - }); -}); diff --git a/awx/ui/test/spec/shared/filters/xss-sanitizer.filter-test.js b/awx/ui/test/spec/shared/filters/xss-sanitizer.filter-test.js deleted file mode 100644 index 2f4db9df83ae..000000000000 --- a/awx/ui/test/spec/shared/filters/xss-sanitizer.filter-test.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -describe('Filter: sanitize', () => { - var filter; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(function(){ - inject(function($injector){ - filter = $injector.get('$filter')('sanitize'); - }); - }); - - it('should sanitize xss-vulnerable strings', function(){ - expect(filter("
foobar
")).toBe("<div>foobar</div>"); - }); -}); diff --git a/awx/ui/test/spec/smart-search/queryset.service-test.js b/awx/ui/test/spec/smart-search/queryset.service-test.js deleted file mode 100644 index eb8563c37d09..000000000000 --- a/awx/ui/test/spec/smart-search/queryset.service-test.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -describe('Service: QuerySet', () => { - let $httpBackend, - QuerySet, - Authorization, - SmartSearchService; - - beforeEach(angular.mock.module('awApp', ($provide) =>{ - // @todo: improve app source / write testing utilities for interim - // we don't want to be concerned with this provision in every test that involves the Rest module - Authorization = { - getToken: () => true, - isUserLoggedIn: angular.noop - }; - $provide.value('LoadBasePaths', angular.noop); - $provide.value('Authorization', Authorization); - })); - beforeEach(angular.mock.module('RestServices')); - - beforeEach(angular.mock.inject((_$httpBackend_, _QuerySet_, _SmartSearchService_) => { - $httpBackend = _$httpBackend_; - QuerySet = _QuerySet_; - SmartSearchService = _SmartSearchService_; - - // @todo: improve app source - // config.js / local_settings emit $http requests in the app's run block - $httpBackend - .whenGET(/\/static\/*/) - .respond(200, {}); - // @todo: improve appsource - // provide api version via package.json config block - $httpBackend - .whenGET(/^\/api\/?$/) - .respond(200, ''); - })); - - describe('fn encodeParam', () => { - it('should encode parameters properly', () =>{ - expect(QuerySet.encodeParam({term: "name:foo", searchTerm: true})).toEqual({"name__icontains_DEFAULT" : "foo"}); - expect(QuerySet.encodeParam({term: "-name:foo", searchTerm: true})).toEqual({"not__name__icontains_DEFAULT" : "foo"}); - expect(QuerySet.encodeParam({term: "name:'foo bar'", searchTerm: true})).toEqual({"name__icontains_DEFAULT" : "'foo%20bar'"}); - expect(QuerySet.encodeParam({term: "-name:'foo bar'", searchTerm: true})).toEqual({"not__name__icontains_DEFAULT" : "'foo%20bar'"}); - expect(QuerySet.encodeParam({term: "organization:foo", relatedSearchTerm: true})).toEqual({"organization__search_DEFAULT" : "foo"}); - expect(QuerySet.encodeParam({term: "-organization:foo", relatedSearchTerm: true})).toEqual({"not__organization__search_DEFAULT" : "foo"}); - expect(QuerySet.encodeParam({term: "organization.name:foo", relatedSearchTerm: true})).toEqual({"organization__name" : "foo"}); - expect(QuerySet.encodeParam({term: "-organization.name:foo", relatedSearchTerm: true})).toEqual({"not__organization__name" : "foo"}); - expect(QuerySet.encodeParam({term: "id:11", searchTerm: true})).toEqual({"id__icontains_DEFAULT" : "11"}); - expect(QuerySet.encodeParam({term: "-id:11", searchTerm: true})).toEqual({"not__id__icontains_DEFAULT" : "11"}); - expect(QuerySet.encodeParam({term: "id:>11", searchTerm: true})).toEqual({"id__gt" : "11"}); - expect(QuerySet.encodeParam({term: "-id:>11", searchTerm: true})).toEqual({"not__id__gt" : "11"}); - expect(QuerySet.encodeParam({term: "id:>=11", searchTerm: true})).toEqual({"id__gte" : "11"}); - expect(QuerySet.encodeParam({term: "-id:>=11", searchTerm: true})).toEqual({"not__id__gte" : "11"}); - expect(QuerySet.encodeParam({term: "id:<11", searchTerm: true})).toEqual({"id__lt" : "11"}); - expect(QuerySet.encodeParam({term: "-id:<11", searchTerm: true})).toEqual({"not__id__lt" : "11"}); - expect(QuerySet.encodeParam({term: "id:<=11", searchTerm: true})).toEqual({"id__lte" : "11"}); - expect(QuerySet.encodeParam({term: "-id:<=11", searchTerm: true})).toEqual({"not__id__lte" : "11"}); - }); - }); - - describe('getSearchInputQueryset', () => { - it('creates the expected queryset', () =>{ - spyOn(QuerySet, 'encodeParam').and.callThrough(); - - const term = 'name:foo'; - const isFilterableBaseField = () => true; - const isRelatedField = () => false; - - expect(QuerySet.getSearchInputQueryset(term, isFilterableBaseField, isRelatedField)).toEqual({ name__icontains_DEFAULT: 'foo' }); - expect(QuerySet.encodeParam).toHaveBeenCalledWith({ term: "name:foo", searchTerm: true, singleSearchParam: null }); - }); - }); - - describe('removeTermsFromQueryset', () => { - it('creates the expected queryset', () =>{ - spyOn(QuerySet, 'encodeParam').and.callThrough(); - - const queryset = { page_size: "20", order_by: "name", project__search_DEFAULT: "foo" }; - const term = 'project:foo'; - const isFilterableBaseField = () => false; - const isRelatedField = () => true; - - expect(QuerySet.removeTermsFromQueryset(queryset, term, isFilterableBaseField, isRelatedField)).toEqual({ page_size: "20", order_by: "name" }); - expect(QuerySet.encodeParam).toHaveBeenCalledWith({ term: 'project:foo', relatedSearchTerm: true, singleSearchParam: null }); - }); - }); - - describe('fn search', () => { - let pattern = /\/api\/v2\/inventories\/(.+)\/groups\/*/, - endpoint = '/api/v2/inventories/1/groups/', - params = { - or__name: 'borg', - or__description__icontains: 'assimilate' - }; - - it('should GET expected URL', () =>{ - $httpBackend - .expectGET(pattern) - .respond(200, {}); - QuerySet.search(endpoint, params).then((data) =>{ - expect(data.config.url).toEqual('/api/v2/inventories/1/groups/?or__name=borg&or__description__icontains=assimilate'); - }); - $httpBackend.flush(); - }); - - xit('should memoize new DjangoModel', ()=>{}); - xit('should not replace memoized DjangoModel', ()=>{}); - xit('should provide an alias interface', ()=>{}); - - afterEach(() => { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); - }); - }); - -}); diff --git a/awx/ui/test/spec/smart-search/smart-search.directive-test.js b/awx/ui/test/spec/smart-search/smart-search.directive-test.js deleted file mode 100644 index afc6df33ed10..000000000000 --- a/awx/ui/test/spec/smart-search/smart-search.directive-test.js +++ /dev/null @@ -1,132 +0,0 @@ -'use strict'; - -describe('Directive: Smart Search', () => { - let $scope, - $q, - template, - element, - dom, - $compile, - $state = {}, - $stateParams, - GetBasePath, - QuerySet, - ConfigService = {}, - i18n, - $transitions, - translateFilter; - - beforeEach(angular.mock.module('shared')); - beforeEach(angular.mock.module('SmartSearchModule', ($provide) => { - QuerySet = jasmine.createSpyObj('QuerySet', [ - 'decodeParam', - 'search', - 'stripDefaultParams', - 'createSearchTagsFromQueryset', - 'initFieldset' - ]); - QuerySet.decodeParam.and.callFake((key, value) => { - return `${key.split('__').join(':')}:${value}`; - }); - QuerySet.stripDefaultParams.and.returnValue([]); - QuerySet.createSearchTagsFromQueryset.and.returnValue([]); - - $transitions = jasmine.createSpyObj('$transitions', [ - 'onSuccess' - ]); - $transitions.onSuccess.and.returnValue({}); - - ConfigService = jasmine.createSpyObj('ConfigService', [ - 'getConfig' - ]); - - GetBasePath = jasmine.createSpy('GetBasePath'); - translateFilter = jasmine.createSpy('translateFilter'); - i18n = jasmine.createSpy('i18n'); - $state = jasmine.createSpyObj('$state', ['go']); - - $provide.value('ConfigService', ConfigService); - $provide.value('QuerySet', QuerySet); - $provide.value('GetBasePath', GetBasePath); - $provide.value('$state', $state); - $provide.value('i18n', { '_': (a) => { return a; } }); - $provide.value('translateFilter', translateFilter); - })); - beforeEach(angular.mock.inject(($templateCache, _$rootScope_, _$compile_, _$q_) => { - $q = _$q_; - $compile = _$compile_; - $scope = _$rootScope_.$new(); - - ConfigService.getConfig.and.returnValue($q.when({})); - QuerySet.search.and.returnValue($q.when({})); - - QuerySet.initFieldset.and.callFake(() => { - var deferred = $q.defer(); - deferred.resolve({ - models: { - mock: { - base: {} - } - }, - options: { - data: null - } - }); - return deferred.promise; - }); - - // populate $templateCache with directive.templateUrl at test runtime, - template = window.__html__['client/src/shared/smart-search/smart-search.partial.html']; - $templateCache.put('/static/partials/shared/smart-search/smart-search.partial.html', template); - })); - - describe('clear all', () => { - it('should revert search back to non-null defaults and remove page', () => { - $state.$current = { - path: { - mock: { - params: { - mock_search: { - config: { - value: { - page_size: '20', - order_by: '-finished', - page: '1', - some_null_param: null - } - } - } - } - } - } - }; - $state.params = { - mock_search: { - page_size: '25', - order_by: 'name', - page: '11', - description_icontains: 'ansible', - name_icontains: 'ansible' - } - }; - $scope.list = { - iterator: 'mock' - }; - dom = angular.element(` - `); - element = $compile(dom)($scope); - $scope.$digest(); - const scope = element.isolateScope(); - scope.clearAllTerms(); - expect(QuerySet.search).toHaveBeenCalledWith('mock', {page_size: '20',order_by: '-finished',}); - }); - }); -}); diff --git a/awx/ui/test/spec/smart-search/smart-search.service-test.js b/awx/ui/test/spec/smart-search/smart-search.service-test.js deleted file mode 100644 index cd7aef484862..000000000000 --- a/awx/ui/test/spec/smart-search/smart-search.service-test.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -describe('Service: SmartSearch', () => { - let SmartSearchService; - - beforeEach(angular.mock.module('awApp')); - - beforeEach(angular.mock.module('SmartSearchModule')); - - beforeEach(angular.mock.inject((_SmartSearchService_) => { - SmartSearchService = _SmartSearchService_; - })); - - describe('fn splitSearchIntoTerms', () => { - it('should convert the search string to an array tag strings', () =>{ - expect(SmartSearchService.splitSearchIntoTerms('foo')).toEqual(["foo"]); - expect(SmartSearchService.splitSearchIntoTerms('foo bar')).toEqual(["foo", "bar"]); - expect(SmartSearchService.splitSearchIntoTerms('name:foo bar')).toEqual(["name:foo", "bar"]); - expect(SmartSearchService.splitSearchIntoTerms('name:foo description:bar')).toEqual(["name:foo", "description:bar"]); - expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar"')).toEqual(["name:\"foo bar\""]); - expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:\"foo bar\"", "description:\"bar foo\""]); - expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:\"foo bar\"", "description:\"bar foo\""]); - expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\'')).toEqual(["name:\'foo bar\'"]); - expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\' description:\'bar foo\'')).toEqual(["name:\'foo bar\'", "description:\'bar foo\'"]); - expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\' description:\'bar foo\'')).toEqual(["name:\'foo bar\'", "description:\'bar foo\'"]); - expect(SmartSearchService.splitSearchIntoTerms('name:\"foo bar\" description:\'bar foo\'')).toEqual(["name:\"foo bar\"", "description:\'bar foo\'"]); - expect(SmartSearchService.splitSearchIntoTerms('name:\"foo bar\" foo')).toEqual(["name:\"foo bar\"", "foo"]); - expect(SmartSearchService.splitSearchIntoTerms('inventory:¯\_(ツ)_/¯')).toEqual(["inventory:¯\_(ツ)_/¯"]); - expect(SmartSearchService.splitSearchIntoTerms('inventory:¯\_(ツ)_/¯ inventory.name:¯\_(ツ)_/¯')).toEqual(["inventory:¯\_(ツ)_/¯", "inventory.name:¯\_(ツ)_/¯"]); - }); - }); - - describe('fn splitTermIntoParts', () => { - it('should convert the search term to a key and value', () =>{ - expect(SmartSearchService.splitTermIntoParts('foo')).toEqual(["foo"]); - expect(SmartSearchService.splitTermIntoParts('foo:bar')).toEqual(["foo", "bar"]); - expect(SmartSearchService.splitTermIntoParts('foo:bar:foobar')).toEqual(["foo", "bar:foobar"]); - expect(SmartSearchService.splitTermIntoParts('name:\"foo bar\"')).toEqual(["name", "\"foo bar\""]); - expect(SmartSearchService.splitTermIntoParts('name:\"foo:bar\"')).toEqual(["name", "\"foo:bar\""]); - expect(SmartSearchService.splitTermIntoParts('name:\'foo bar\'')).toEqual(["name", "\'foo bar\'"]); - expect(SmartSearchService.splitTermIntoParts('name:\'foo:bar\'')).toEqual(["name", "\'foo:bar\'"]); - }); - }); - - describe('fn splitFilterIntoTerms', () => { - it('should convert the filter term to a key and value with encode quotes and spaces', () => { - expect(SmartSearchService.splitFilterIntoTerms()).toEqual(null); - expect(SmartSearchService.splitFilterIntoTerms('foo')).toEqual(["foo"]); - expect(SmartSearchService.splitFilterIntoTerms('foo bar')).toEqual(["foo", "bar"]); - expect(SmartSearchService.splitFilterIntoTerms('name:foo bar')).toEqual(["name:foo", "bar"]); - expect(SmartSearchService.splitFilterIntoTerms('name:foo description:bar')).toEqual(["name:foo", "description:bar"]); - expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar"')).toEqual(["name:%22foo%20bar%22"]); - expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:%22foo%20bar%22", "description:%22bar%20foo%22"]); - expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar" a b c')).toEqual(["name:%22foo%20bar%22", 'a', 'b', 'c']); - expect(SmartSearchService.splitFilterIntoTerms('name:"1"')).toEqual(["name:%221%22"]); - expect(SmartSearchService.splitFilterIntoTerms('name:1')).toEqual(["name:1"]); - expect(SmartSearchService.splitFilterIntoTerms('name:"foo ba\'r" a b c')).toEqual(["name:%22foo%20ba%27r%22", 'a', 'b', 'c']); - expect(SmartSearchService.splitFilterIntoTerms('name:"foobar" other:"barbaz"')).toEqual(["name:%22foobar%22", "other:%22barbaz%22"]); - expect(SmartSearchService.splitFilterIntoTerms('name:"foobar" other:"bar baz"')).toEqual(["name:%22foobar%22", "other:%22bar%20baz%22"]); - }); - }); - -}); diff --git a/awx/ui/test/spec/socket/socket.service-test.js b/awx/ui/test/spec/socket/socket.service-test.js deleted file mode 100644 index 8585fd2ddebc..000000000000 --- a/awx/ui/test/spec/socket/socket.service-test.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -xdescribe('Service: SocketService', () => { - - let SocketService, - rootScope, - event; - - beforeEach(angular.mock.module('shared')); - beforeEach(angular.mock.module('socket', function($provide){ - $provide.value('$rootScope', rootScope); - $provide.value('$location', {url: function(){}}); - })); - beforeEach(angular.mock.inject(($rootScope, _SocketService_) => { - var rootScope = $rootScope.$new(); - rootScope.$emit = jasmine.createSpy('$emit'); - SocketService = _SocketService_; - })); - - describe('socket onmessage() should broadcast to correct event listener', function(){ - - xit('should send to ws-jobs-summary', function(){ - event = {data : {group_name: "jobs"}}; - event.data = JSON.stringify(event.data); - SocketService.onMessage(event); - expect(rootScope.$emit).toHaveBeenCalledWith('ws-jobs-summary', event.data); - }); - }); - -}); diff --git a/awx/ui/test/spec/webpack.spec.js b/awx/ui/test/spec/webpack.spec.js deleted file mode 100644 index 099d6a996483..000000000000 --- a/awx/ui/test/spec/webpack.spec.js +++ /dev/null @@ -1,16 +0,0 @@ -const webpack = require('webpack'); -const merge = require('webpack-merge'); -const base = require('../../build/webpack.base'); - -const STATIC_URL = '/static/'; - -const test = { - devtool: 'inline-source-map', - plugins: [ - new webpack.DefinePlugin({ - $basePath: STATIC_URL - }) - ] -}; - -module.exports = merge(base, test); diff --git a/awx/ui/test/spec/workflow--results/data/workflow_job.js b/awx/ui/test/spec/workflow--results/data/workflow_job.js deleted file mode 100644 index 6893b6321601..000000000000 --- a/awx/ui/test/spec/workflow--results/data/workflow_job.js +++ /dev/null @@ -1,63 +0,0 @@ -export default { - "id": 109, - "type": "workflow_job", - "url": "/api/v2/workflow_jobs/109/", - "related": { - "created_by": "/api/v2/users/1/", - "unified_job_template": "/api/v2/workflow_job_templates/27/", - "workflow_job_template": "/api/v2/workflow_job_templates/27/", - "notifications": "/api/v2/workflow_jobs/109/notifications/", - "workflow_nodes": "/api/v2/workflow_jobs/109/workflow_nodes/", - "labels": "/api/v2/workflow_jobs/109/labels/", - "activity_stream": "/api/v2/workflow_jobs/109/activity_stream/", - "relaunch": "/api/v2/workflow_jobs/109/relaunch/", - "cancel": "/api/v2/workflow_jobs/109/cancel/" - }, - "summary_fields": { - "workflow_job_template": { - "id": 27, - "name": "workflow timer", - "description": "" - }, - "unified_job_template": { - "id": 27, - "name": "workflow timer", - "description": "", - "unified_job_type": "workflow_job" - }, - "created_by": { - "id": 1, - "username": "admin", - "first_name": "", - "last_name": "" - }, - "user_capabilities": { - "start": true, - "delete": true - }, - "labels": { - "count": 0, - "results": [] - } - }, - "created": "2017-02-01T14:56:47.416Z", - "modified": "2017-02-01T14:57:14.189Z", - "name": "workflow timer", - "description": "", - "unified_job_template": 27, - "launch_type": "manual", - "status": "successful", - "failed": false, - "started": "2017-02-01T14:56:47.754897Z", - "finished": "2017-02-01T14:57:14.182780Z", - "elapsed": 26.428, - "job_args": "", - "job_cwd": "", - "job_env": {}, - "job_explanation": "", - "result_stdout": "stdout capture is missing", - "execution_node": "", - "result_traceback": "", - "workflow_job_template": 27, - "extra_vars": "{}" -}; \ No newline at end of file diff --git a/awx/ui/test/spec/workflow--results/data/workflow_job_options.js b/awx/ui/test/spec/workflow--results/data/workflow_job_options.js deleted file mode 100644 index 657d6f41fe83..000000000000 --- a/awx/ui/test/spec/workflow--results/data/workflow_job_options.js +++ /dev/null @@ -1,203 +0,0 @@ -export default { - "name": "Workflow Job Detail", - "description": "# Retrieve Workflow Job:\n\nMake GET request to this resource to retrieve a single workflow job\nrecord containing the following fields:\n\n* `id`: Database ID for this workflow job. (integer)\n* `type`: Data type for this workflow job. (choice)\n* `url`: URL for this workflow job. (string)\n* `related`: Data structure with URLs of related resources. (object)\n* `summary_fields`: Data structure with name/description for related resources. (object)\n* `created`: Timestamp when this workflow job was created. (datetime)\n* `modified`: Timestamp when this workflow job was last modified. (datetime)\n* `name`: Name of this workflow job. (string)\n* `description`: Optional description of this workflow job. (string)\n* `unified_job_template`: (field)\n* `launch_type`: (choice)\n - `manual`: Manual\n - `relaunch`: Relaunch\n - `callback`: Callback\n - `scheduled`: Scheduled\n - `dependency`: Dependency\n - `workflow`: Workflow\n - `sync`: Sync\n* `status`: (choice)\n - `new`: New\n - `pending`: Pending\n - `waiting`: Waiting\n - `running`: Running\n - `successful`: Successful\n - `failed`: Failed\n - `error`: Error\n - `canceled`: Canceled\n* `failed`: (boolean)\n* `started`: The date and time the job was queued for starting. (datetime)\n* `finished`: The date and time the job finished execution. (datetime)\n* `elapsed`: Elapsed time in seconds that the job ran. (decimal)\n* `job_args`: (string)\n* `job_cwd`: (string)\n* `job_env`: (field)\n* `job_explanation`: A status field to indicate the state of the job if it wasn't able to run and capture stdout (string)\n* `result_stdout`: (field)\n* `execution_node`: The Tower node the job executed on. (string)\n* `result_traceback`: (string)\n* `workflow_job_template`: (field)\n* `extra_vars`: (string)\n\n\n\n# Delete Workflow Job:\n\nMake a DELETE request to this resource to delete this workflow job.\n\n\n\n\n\n\n\n\n\n\n\n> _New in Ansible Tower 3.1.0_", - "renders": [ - "application/json", - "text/html" - ], - "parses": [ - "application/json" - ], - "actions": { - "GET": { - "id": { - "type": "integer", - "label": "ID", - "help_text": "Database ID for this workflow job." - }, - "type": { - "type": "choice", - "label": "Type", - "help_text": "Data type for this workflow job.", - "choices": [ - [ - "workflow_job", - "Workflow Job" - ] - ] - }, - "url": { - "type": "string", - "label": "Url", - "help_text": "URL for this workflow job." - }, - "related": { - "type": "object", - "label": "Related", - "help_text": "Data structure with URLs of related resources." - }, - "summary_fields": { - "type": "object", - "label": "Summary fields", - "help_text": "Data structure with name/description for related resources." - }, - "created": { - "type": "datetime", - "label": "Created", - "help_text": "Timestamp when this workflow job was created." - }, - "modified": { - "type": "datetime", - "label": "Modified", - "help_text": "Timestamp when this workflow job was last modified." - }, - "name": { - "type": "string", - "label": "Name", - "help_text": "Name of this workflow job." - }, - "description": { - "type": "string", - "label": "Description", - "help_text": "Optional description of this workflow job." - }, - "unified_job_template": { - "type": "field", - "label": "unified job template" - }, - "launch_type": { - "type": "choice", - "label": "Launch type", - "choices": [ - [ - "manual", - "Manual" - ], - [ - "relaunch", - "Relaunch" - ], - [ - "callback", - "Callback" - ], - [ - "scheduled", - "Scheduled" - ], - [ - "dependency", - "Dependency" - ], - [ - "workflow", - "Workflow" - ], - [ - "sync", - "Sync" - ] - ] - }, - "status": { - "type": "choice", - "label": "Status", - "choices": [ - [ - "new", - "New" - ], - [ - "pending", - "Pending" - ], - [ - "waiting", - "Waiting" - ], - [ - "running", - "Running" - ], - [ - "successful", - "Successful" - ], - [ - "failed", - "Failed" - ], - [ - "error", - "Error" - ], - [ - "canceled", - "Canceled" - ] - ] - }, - "failed": { - "type": "boolean", - "label": "Failed" - }, - "started": { - "type": "datetime", - "label": "Started", - "help_text": "The date and time the job was queued for starting." - }, - "finished": { - "type": "datetime", - "label": "Finished", - "help_text": "The date and time the job finished execution." - }, - "elapsed": { - "type": "decimal", - "label": "Elapsed", - "help_text": "Elapsed time in seconds that the job ran." - }, - "job_args": { - "type": "string", - "label": "Job args" - }, - "job_cwd": { - "type": "string", - "label": "Job cwd" - }, - "job_env": { - "type": "field", - "label": "job_env" - }, - "job_explanation": { - "type": "string", - "label": "Job explanation", - "help_text": "A status field to indicate the state of the job if it wasn't able to run and capture stdout" - }, - "result_stdout": { - "type": "field", - "label": "Result stdout" - }, - "execution_node": { - "type": "string", - "label": "Execution node", - "help_text": "The Tower node the job executed on." - }, - "result_traceback": { - "type": "string", - "label": "Result traceback" - }, - "workflow_job_template": { - "type": "field", - "label": "Workflow job template" - }, - "extra_vars": { - "type": "string", - "label": "Extra vars" - } - } - }, - "added_in_version": "3.1.0", - "types": [ - "workflow_job" - ] -} \ No newline at end of file diff --git a/awx/ui/test/spec/workflow--results/workflow-results.controller-test.js b/awx/ui/test/spec/workflow--results/workflow-results.controller-test.js deleted file mode 100644 index 4976ce13060e..000000000000 --- a/awx/ui/test/spec/workflow--results/workflow-results.controller-test.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; -import moment from 'moment'; -import workflow_job_options_json from './data/workflow_job_options.js'; -import workflow_job_json from './data/workflow_job.js'; - -describe('Controller: workflowResults', () => { - let $controller; - let workflowResults; - let $rootScope; - let workflowResultsService; - let $interval; - - let treeData = { - data: { - children: [] - } - }; - - beforeEach(angular.mock.module('workflowResults', ($provide) => { - ['PromptDialog', 'Prompt', 'Wait', 'Rest', '$state', 'ProcessErrors', - 'jobLabels', 'workflowNodes', 'count', 'WorkflowJobModel', - ].forEach((item) => { - $provide.value(item, {}); - }); - $provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), }); - $provide.value('moment', moment); - $provide.value('workflowData', workflow_job_json); - $provide.value('workflowDataOptions', workflow_job_options_json); - $provide.value('ParseTypeChange', function() {}); - $provide.value('ParseVariableString', function() {}); - $provide.value('i18n', { '_': (a) => { return a; } }); - $provide.provider('$stateProvider', { '$get': function() { return function() {}; } }); - $provide.service('WorkflowService', function($q) { - return { - buildTree: function() { - var deferred = $q.defer(); - deferred.resolve(treeData); - return deferred.promise; - } - }; - }); - })); - - beforeEach(angular.mock.inject(function(_$controller_, _$rootScope_, _workflowResultsService_, _$interval_){ - $controller = _$controller_; - $rootScope = _$rootScope_; - workflowResultsService = _workflowResultsService_; - $interval = _$interval_; - - })); - - describe('elapsed timer', () => { - let scope; - - beforeEach(() => { - scope = $rootScope.$new(); - spyOn(workflowResultsService, 'createOneSecondTimer').and.callThrough(); - spyOn(workflowResultsService, 'destroyTimer').and.callThrough(); - }); - - - function jobWaitingWorkflowResultsControllerFixture(started, status) { - workflow_job_json.started = started; - workflow_job_json.status = status; - workflowResults = $controller('workflowResultsController', { - $scope: scope, - $rootScope: $rootScope, - }); - } - - describe('init()', () => { - describe('job running', () => { - beforeEach(() => { - jobWaitingWorkflowResultsControllerFixture(moment(), 'running'); - }); - - // Note: Ensuring the outside service method is called to create a timer may - // be overkill. Especially since we validate the side effect in the next test. - it('should call to start timer on load when job is already running', () => { - expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled(); - expect(workflowResultsService.createOneSecondTimer.calls.argsFor(0)[0]).toBe(workflow_job_json.started); - }); - - it('should set update scope var with elapsed time', () => { - $interval.flush(10 * 1000); - - // TODO: mock moment() so when we fast-forward time with $interval - // the system clocks seems to fast forward too. - //expect(scope.workflow.elapsed).toBe(10); - }); - - it('should call to destroy timer on destroy', () => { - scope.$destroy(); - expect(workflowResultsService.destroyTimer).toHaveBeenCalled(); - expect(workflowResultsService.destroyTimer.calls.argsFor(0)[0]).not.toBe(null); - }); - }); - - describe('job waiting', () => { - beforeEach(() => { - jobWaitingWorkflowResultsControllerFixture(null, 'waiting'); - }); - - it('should not start elapsed timer', () => { - expect(workflowResultsService.createOneSecondTimer).not.toHaveBeenCalled(); - }); - - }); - - describe('job finished', () => { - beforeEach(() => { - jobWaitingWorkflowResultsControllerFixture(moment(), 'successful'); - }); - - it('should start elapsed timer', () => { - expect(workflowResultsService.createOneSecondTimer).not.toHaveBeenCalled(); - }); - }); - }); - - describe('job transitions to running', () => { - beforeEach(() => { - jobWaitingWorkflowResultsControllerFixture(null, 'waiting'); - $rootScope.$broadcast('ws-jobs', { unified_job_id: workflow_job_json.id, status: "running" }); - }); - - it('should start elapsed timer', () => { - expect(scope.workflow.status).toBe("running"); - expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled(); - }); - }); - }); -}); diff --git a/awx/ui/test/spec/workflow--results/workflow-results.service-test.js b/awx/ui/test/spec/workflow--results/workflow-results.service-test.js deleted file mode 100644 index c730fc0dcfab..000000000000 --- a/awx/ui/test/spec/workflow--results/workflow-results.service-test.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; -import moment from 'moment'; - -describe('workflowResultsService', () => { - let workflowResultsService; - let $interval; - - beforeEach(angular.mock.module('workflowResults', ($provide) => { - ['PromptDialog', 'Prompt', 'Wait', 'Rest', 'ProcessErrors', '$state', 'WorkflowJobModel'] - .forEach(function(item) { - $provide.value(item, {}); - }); - $provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), }); - $provide.value('moment', moment); - })); - - beforeEach(angular.mock.inject((_workflowResultsService_, _$interval_) => { - workflowResultsService = _workflowResultsService_; - $interval = _$interval_; - })); - - describe('createOneSecondTimer()', () => { - it('should create a timer that runs every second, incremented by a second', (done) => { - let ticks = 0; - let ticks_expected = 10; - - workflowResultsService.createOneSecondTimer(moment(), function() { - ticks += 1; - if (ticks >= ticks_expected) { - expect(ticks).toBe(ticks_expected); - // TODO: should verify time is 10 but this requires mocking moment() - // because we "artificially" accelerate time. - done(); - } - }); - - $interval.flush(ticks_expected * 1000); - }); - }); - - describe('destroyTimer()', () => { - beforeEach(() => { - $interval.cancel = jasmine.createSpy('cancel'); - }); - - it('should not destroy null timer', () => { - workflowResultsService.destroyTimer(null); - - expect($interval.cancel).not.toHaveBeenCalled(); - }); - - it('should destroy passed in timer', () => { - let timer = jasmine.createSpy('timer'); - - workflowResultsService.destroyTimer(timer); - - expect($interval.cancel).toHaveBeenCalledWith(timer); - }); - }); -}); diff --git a/awx/ui/test/spec/workflows/workflow-add.controller-test.js b/awx/ui/test/spec/workflows/workflow-add.controller-test.js deleted file mode 100644 index 9eceb528ce20..000000000000 --- a/awx/ui/test/spec/workflows/workflow-add.controller-test.js +++ /dev/null @@ -1,164 +0,0 @@ -'use strict'; - -describe('Controller: WorkflowAdd', () => { - // Setup - let scope, - state, - WorkflowAdd, - Alert, - GenerateForm, - TemplatesService, - q, - createWorkflowJobTemplateDeferred, - httpBackend, - ProcessErrors, - CreateSelect2, - Wait, - ParseTypeChange, - ToJSON, - availableLabels, - resolvedModels; - - beforeEach(angular.mock.module('awApp')); - beforeEach(angular.mock.module('RestServices')); - beforeEach(angular.mock.module('templates', ($provide) => { - - state = jasmine.createSpyObj('state', [ - '$get', - 'transitionTo', - 'go' - ]); - - GenerateForm = jasmine.createSpyObj('GenerateForm', [ - 'inject', - 'reset', - 'clearApiErrors', - 'applyDefaults' - ]); - - TemplatesService = { - getLabelOptions: function(){ - return angular.noop; - }, - createWorkflowJobTemplate: function(){ - return angular.noop; - } - }; - - availableLabels = [{ - name: "foo", - id: "1" - }]; - - resolvedModels = [ - {}, - { - options: () => { - return true; - } - } - ]; - - Alert = jasmine.createSpy('Alert'); - ProcessErrors = jasmine.createSpy('ProcessErrors'); - CreateSelect2 = jasmine.createSpy('CreateSelect2'); - Wait = jasmine.createSpy('Wait'); - ParseTypeChange = jasmine.createSpy('ParseTypeChange'); - ToJSON = jasmine.createSpy('ToJSON'); - - $provide.value('Alert', Alert); - $provide.value('GenerateForm', GenerateForm); - $provide.value('state', state); - $provide.value('ProcessErrors', ProcessErrors); - $provide.value('CreateSelect2', CreateSelect2); - $provide.value('Wait', Wait); - $provide.value('ParseTypeChange', ParseTypeChange); - $provide.value('ToJSON', ToJSON); - $provide.value('availableLabels', availableLabels); - $provide.value('resolvedModels', resolvedModels); - })); - - beforeEach(angular.mock.inject( ($rootScope, $controller, $q, $httpBackend, _state_, _ConfigService_, _GetChoices_, _Alert_, _GenerateForm_, _ProcessErrors_, _CreateSelect2_, _Wait_, _ParseTypeChange_, _ToJSON_, _availableLabels_) => { - scope = $rootScope.$new(); - state = _state_; - q = $q; - Alert = _Alert_; - GenerateForm = _GenerateForm_; - httpBackend = $httpBackend; - ProcessErrors = _ProcessErrors_; - CreateSelect2 = _CreateSelect2_; - Wait = _Wait_; - createWorkflowJobTemplateDeferred = q.defer(); - ParseTypeChange = _ParseTypeChange_; - ToJSON = _ToJSON_; - availableLabels = _availableLabels_; - - $httpBackend - .whenGET(/^\/api\/?$/) - .respond(200, ''); - - $httpBackend - .whenGET(/\/static\/*/) - .respond(200, {}); - - TemplatesService.createWorkflowJobTemplate = jasmine.createSpy('createWorkflowJobTemplate').and.returnValue(createWorkflowJobTemplateDeferred.promise); - - WorkflowAdd = $controller('WorkflowAdd', { - $scope: scope, - $state: state, - Alert: Alert, - GenerateForm: GenerateForm, - TemplatesService: TemplatesService, - ProcessErrors: ProcessErrors, - CreateSelect2: CreateSelect2, - Wait: Wait, - ParseTypeChange: ParseTypeChange, - availableLabels: availableLabels, - ToJSON - }); - })); - - it('should get/set the label options and select2-ify the input', ()=>{ - // We expect the digest cycle to fire off this call to /static/config.js so we go ahead and handle it - httpBackend.expectGET('/static/config.js').respond(200); - scope.$digest(); - expect(scope.labelOptions).toEqual([{ - label: "foo", - value: "1" - }]); - expect(CreateSelect2).toHaveBeenCalledWith({ - element:'#workflow_job_template_labels', - multiple: true, - addNew: true - }); - }); - - describe('scope.formSave()', () => { - - it('should call TemplatesService.createWorkflowJobTemplate', ()=>{ - scope.name = "Test Workflow"; - scope.description = "This is a test description"; - scope.formSave(); - expect(TemplatesService.createWorkflowJobTemplate).toHaveBeenCalledWith({ - name: "Test Workflow", - description: "This is a test description", - labels: undefined, - organization: undefined, - variables: undefined, - extra_vars: undefined, - allow_simultaneous: undefined - }); - }); - - }); - - describe('scope.formCancel()', () => { - - it('should transition to templates', ()=>{ - scope.formCancel(); - expect(state.transitionTo).toHaveBeenCalledWith('templates'); - }); - - }); - -}); diff --git a/awx/ui/test/spec/workflows/workflow-maker.controller-test.js b/awx/ui/test/spec/workflows/workflow-maker.controller-test.js deleted file mode 100644 index 58e5db8abf71..000000000000 --- a/awx/ui/test/spec/workflows/workflow-maker.controller-test.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -describe('Controller: WorkflowMaker', () => { - // Setup - let scope, - WorkflowMakerController, - TemplatesService, - q, - getWorkflowJobTemplateNodesDeferred; - - beforeEach(angular.mock.module('awApp')); - beforeEach(angular.mock.module('templates', () => { - - TemplatesService = { - getWorkflowJobTemplateNodes: function(){ - return angular.noop; - } - }; - - })); - - beforeEach(angular.mock.inject( ($rootScope, $controller, $q) => { - scope = $rootScope.$new(); - scope.closeDialog = jasmine.createSpy(); - scope.treeData = { - data: { - id: 1, - canDelete: false, - canEdit: false, - canAddTo: true, - isStartNode: true, - unifiedJobTemplate: { - name: "Workflow Launch" - }, - children: [], - deletedNodes: [], - totalNodes: 0 - }, - nextIndex: 2 - }; - scope.workflowJobTemplateObj = { - id: 1 - }; - q = $q; - getWorkflowJobTemplateNodesDeferred = q.defer(); - TemplatesService.getWorkflowJobTemplateNodes = jasmine.createSpy('getWorkflowJobTemplateNodes').and.returnValue(getWorkflowJobTemplateNodesDeferred.promise); - WorkflowMakerController = $controller('WorkflowMakerController', { - $scope: scope, - TemplatesService: TemplatesService - }); - })); - - describe('scope.closeWorkflowMaker()', () => { - - it('should close the dialog', ()=>{ - scope.closeWorkflowMaker(); - expect(scope.closeDialog).toHaveBeenCalled(); - }); - - }); - -}); diff --git a/awx/ui/test/unit/.eslintrc.js b/awx/ui/test/unit/.eslintrc.js deleted file mode 100644 index c8aebfd81341..000000000000 --- a/awx/ui/test/unit/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - env: { - jasmine: true - } -}; - diff --git a/awx/ui/test/unit/components/file.unit.js b/awx/ui/test/unit/components/file.unit.js deleted file mode 100644 index 1bf7041b56fd..000000000000 --- a/awx/ui/test/unit/components/file.unit.js +++ /dev/null @@ -1,61 +0,0 @@ -describe('Components | Input | File', () => { - let $scope; - let element; - let state; - let controller; - - const getMockFileEvent = file => ({ target: { files: [file] } }); - - beforeEach(() => { - angular.mock.module('at.lib.services'); - angular.mock.module('at.lib.components'); - }); - - describe('AtInputFileController', () => { - beforeEach(angular.mock.inject(($rootScope, $compile) => { - const component = ''; - const dom = angular.element(`${component}`); - - $scope = $rootScope.$new(); - $scope.vm = { form: { disabled: false, unit: {} } }; - - $compile(dom)($scope); - $scope.$digest(); - - element = dom.find('#unit'); - state = $scope.vm.form.unit; - controller = element.controller('atInputFile'); - })); - - it('should initialize without a value by default', () => { - expect(state._value).not.toBeDefined(); - expect(state._displayValue).not.toBeDefined(); - }); - - it('should update display value with file name when file is read', () => { - const name = 'notavirus.exe'; - const reader = { result: 'AAAAAAA' }; - - controller.check = jasmine.createSpy('check'); - - controller.readFile(reader, getMockFileEvent({ name })); - - $scope.$digest(); - - expect(state._value).toBeDefined(); - expect(state._displayValue).toEqual(name); - - expect(controller.check).toHaveBeenCalled(); - }); - - it('should notify handler on file input change event', () => { - controller.handleFileChangeEvent = jasmine.createSpy('handleFileChangeEvent'); - - element.find('input')[0].dispatchEvent(new Event('change')); - - $scope.$digest(); - - expect(controller.handleFileChangeEvent).toHaveBeenCalled(); - }); - }); -}); diff --git a/awx/ui/test/unit/components/index.js b/awx/ui/test/unit/components/index.js deleted file mode 100644 index 8d75e3cf7153..000000000000 --- a/awx/ui/test/unit/components/index.js +++ /dev/null @@ -1,9 +0,0 @@ -// Import angular and angular-mocks to the global scope -import 'angular-mocks'; - -// Import tests -import './file.unit'; -import './layout.unit'; -import './side-nav.unit'; -import './side-nav-item.unit'; - diff --git a/awx/ui/test/unit/components/layout.unit.js b/awx/ui/test/unit/components/layout.unit.js deleted file mode 100644 index 76ecf0dcd675..000000000000 --- a/awx/ui/test/unit/components/layout.unit.js +++ /dev/null @@ -1,162 +0,0 @@ -describe('Components | Layout', () => { - let $compile; - let $rootScope; - let $httpBackend; - let element; - let scope; - - beforeEach(() => { - angular.mock.module('gettext'); - angular.mock.module('I18N'); - angular.mock.module('ui.router'); - angular.mock.module('at.lib.services'); - angular.mock.module('at.lib.components'); - angular.mock.module('Utilities'); - angular.mock.module('ngCookies'); - }); - - beforeEach(angular.mock.inject((_$compile_, _$rootScope_, _$httpBackend_) => { - $compile = _$compile_; - $rootScope = _$rootScope_; - $httpBackend = _$httpBackend_; - scope = $rootScope.$new(); - - element = angular.element(''); - element = $compile(element)(scope); - scope.$digest(); - })); - - describe('AtLayoutController', () => { - let controller; - - beforeEach(() => { - const mockResponse = { - data: { - count: 3 - } - }; - - controller = element.controller('atLayout'); - $httpBackend.when('GET', /admin_of_organizations/) - .respond(mockResponse); - }); - - xit('$scope.$on($stateChangeSuccess) should assign toState name to currentState', () => { - const next = { name: 'dashboard' }; - $rootScope.$broadcast('$stateChangeSuccess', next); - expect(controller.currentState).toBe('dashboard'); - }); - - describe('$root.current_user watcher should assign value to ', () => { - beforeEach(() => { - const val = { - username: 'admin', - id: 1 - }; - $rootScope.current_user = val; - scope.$digest(); - }); - - it('isLoggedIn', () => { - expect(controller.isLoggedIn).toBe('admin'); - - $rootScope.current_user = { id: 1 }; - scope.$digest(); - expect(controller.isLoggedIn).not.toBeDefined(); - }); - - it('isSuperUser', () => { - $rootScope.current_user = 'one'; - $rootScope.user_is_superuser = true; - $rootScope.user_is_system_auditor = false; - scope.$digest(); - expect(controller.isSuperUser).toBe(true); - - $rootScope.current_user = 'two'; - $rootScope.user_is_superuser = false; - $rootScope.user_is_system_auditor = true; - scope.$digest(); - expect(controller.isSuperUser).toBe(true); - - $rootScope.current_user = 'three'; - $rootScope.user_is_superuser = true; - $rootScope.user_is_system_auditor = true; - scope.$digest(); - expect(controller.isSuperUser).toBe(true); - - $rootScope.current_user = 'four'; - $rootScope.user_is_superuser = false; - $rootScope.user_is_system_auditor = false; - scope.$digest(); - expect(controller.isSuperUser).toBe(false); - }); - - it('currentUsername', () => { - expect(controller.currentUsername).toBeTruthy(); - expect(controller.currentUsername).toBe('admin'); - }); - - it('currentUserId', () => { - expect(controller.currentUserId).toBeTruthy(); - expect(controller.currentUserId).toBe(1); - }); - }); - - describe('$root.socketStatus watcher should assign newStatus to', () => { - const statuses = ['connecting', 'error', 'ok']; - - it('socketState', () => { - _.forEach(statuses, (status) => { - $rootScope.socketStatus = status; - scope.$digest(); - expect(controller.socketState).toBeTruthy(); - expect(controller.socketState).toBe(status); - }); - }); - - it('socketIconClass', () => { - _.forEach(statuses, (status) => { - $rootScope.socketStatus = status; - scope.$digest(); - expect(controller.socketIconClass).toBe(`icon-socket-${status}`); - }); - }); - }); - - describe('$root.licenseMissing watcher should assign true or false to', () => { - it('licenseIsMissing', () => { - $rootScope.licenseMissing = true; - scope.$digest(); - expect(controller.licenseIsMissing).toBe(true); - - $rootScope.licenseMissing = false; - scope.$digest(); - expect(controller.licenseIsMissing).toBe(false); - }); - }); - - describe('getString()', () => { - it('calls ComponentsStrings get() method', angular.mock.inject((_ComponentsStrings_) => { - spyOn(_ComponentsStrings_, 'get'); - controller.getString('VIEW_DOCS'); - expect(_ComponentsStrings_.get).toHaveBeenCalled(); - })); - - it('ComponentsStrings get() method should return undefined if string is not a property name of the layout class', () => { - expect(controller.getString('SUBMISSION_ERROR_TITLE')).toBe(undefined); - }); - - it('should return layout string', () => { - const layoutStrings = { - CURRENT_USER_LABEL: 'Logged in as', - VIEW_DOCS: 'View Documentation', - LOGOUT: 'Logout', - }; - - _.forEach(layoutStrings, (value, key) => { - expect(controller.getString(key)).toBe(value); - }); - }); - }); - }); -}); diff --git a/awx/ui/test/unit/components/side-nav-item.unit.js b/awx/ui/test/unit/components/side-nav-item.unit.js deleted file mode 100644 index e0deffa245de..000000000000 --- a/awx/ui/test/unit/components/side-nav-item.unit.js +++ /dev/null @@ -1,55 +0,0 @@ -describe('Components | Side Nav Item', () => { - let $compile; - let $rootScope; - let element; - let scope; - - beforeEach(() => { - angular.mock.module('gettext'); - angular.mock.module('I18N'); - angular.mock.module('ui.router'); - angular.mock.module('at.lib.services'); - angular.mock.module('at.lib.components'); - angular.mock.module('Utilities'); - angular.mock.module('ngCookies'); - }); - - beforeEach(angular.mock.inject((_$compile_, _$rootScope_) => { - $compile = _$compile_; - $rootScope = _$rootScope_; - scope = $rootScope.$new(); - - element = angular.element(''); - element = $compile(element)(scope); - scope.name = 'dashboard'; - scope.$digest(); - })); - - describe('Side Nav Item Controller', () => { - let SideNavItem; - let SideNavItemCtrl; - - beforeEach(() => { - SideNavItem = angular.element(element[0].querySelector('at-side-nav-item')); - SideNavItemCtrl = SideNavItem.controller('atSideNavItem'); - }); - - xit('layoutVm.currentState watcher should assign isRoute', () => { - let current = { name: 'dashboard' }; - $rootScope.$broadcast('$stateChangeSuccess', current); - scope.$digest(); - expect(SideNavItemCtrl.isRoute).toBe(true); - - current = { name: 'inventories' }; - $rootScope.$broadcast('$stateChangeSuccess', current); - scope.$digest(); - expect(SideNavItemCtrl.isRoute).toBe(false); - }); - - it('should load name, icon, and route from scope', () => { - expect(SideNavItem.isolateScope().name).toBeDefined(); - expect(SideNavItem.isolateScope().iconClass).toBeDefined(); - expect(SideNavItem.isolateScope().route).toBeDefined(); - }); - }); -}); diff --git a/awx/ui/test/unit/components/side-nav.unit.js b/awx/ui/test/unit/components/side-nav.unit.js deleted file mode 100644 index e460528a2e43..000000000000 --- a/awx/ui/test/unit/components/side-nav.unit.js +++ /dev/null @@ -1,80 +0,0 @@ -describe('Components | Side Nav', () => { - let $compile; - let $rootScope; - let element; - let scope; - const windowMock = { - innerWidth: 500 - }; - - beforeEach(() => { - angular.mock.module('gettext'); - angular.mock.module('I18N'); - angular.mock.module('ui.router'); - angular.mock.module('at.lib.services'); - angular.mock.module('at.lib.components', ($provide) => { - $provide.value('$window', windowMock); - }); - angular.mock.module('Utilities'); - angular.mock.module('ngCookies'); - }); - - beforeEach(angular.mock.inject((_$compile_, _$rootScope_) => { - $compile = _$compile_; - $rootScope = _$rootScope_; - scope = $rootScope.$new(); - - element = angular.element(''); - element = $compile(element)(scope); - scope.$digest(); - })); - - describe('Side Nav Controller', () => { - let sideNav; - let sideNavCtrl; - - beforeEach(() => { - sideNav = angular.element(element[0].querySelector('.at-Layout-side')); - sideNavCtrl = sideNav.controller('atSideNav'); - }); - - it('isExpanded defaults to false', () => { - expect(sideNavCtrl.isExpanded).toBe(false); - }); - - it('toggleExpansion()', () => { - expect(sideNavCtrl.isExpanded).toBe(false); - - sideNavCtrl.toggleExpansion(); - expect(sideNavCtrl.isExpanded).toBe(true); - - sideNavCtrl.toggleExpansion(); - expect(sideNavCtrl.isExpanded).toBe(false); - - sideNavCtrl.toggleExpansion(); - expect(sideNavCtrl.isExpanded).toBe(true); - - sideNavCtrl.toggleExpansion(); - expect(sideNavCtrl.isExpanded).toBe(false); - }); - - xit('isExpanded should be false after state change event', () => { - sideNavCtrl.isExpanded = true; - - const current = { - name: 'dashboard' - }; - $rootScope.$broadcast('$stateChangeSuccess', current); - scope.$digest(); - expect(sideNavCtrl.isExpanded).toBe(false); - }); - - it('clickOutsideSideNav watcher should assign isExpanded to false', () => { - sideNavCtrl.isExpanded = true; - - $rootScope.$broadcast('clickOutsideSideNav'); - scope.$digest(); - expect(sideNavCtrl.isExpanded).toBe(false); - }); - }); -}); diff --git a/awx/ui/test/unit/index.js b/awx/ui/test/unit/index.js deleted file mode 100644 index 7c8967ef87b2..000000000000 --- a/awx/ui/test/unit/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import './components'; -import './models'; diff --git a/awx/ui/test/unit/karma.unit.js b/awx/ui/test/unit/karma.unit.js deleted file mode 100644 index d839aff5f279..000000000000 --- a/awx/ui/test/unit/karma.unit.js +++ /dev/null @@ -1,46 +0,0 @@ -const path = require('path'); - -const SRC_PATH = path.resolve(__dirname, '../../client/src'); - -const webpackConfig = require('./webpack.unit'); - -module.exports = config => { - config.set({ - basePath: '', - singleRun: true, - autoWatch: false, - colors: true, - frameworks: ['jasmine'], - browsers: ['PhantomJS'], - reporters: ['progress', 'junit'], - files: [ - './polyfills.js', - path.join(SRC_PATH, 'vendor.js'), - path.join(SRC_PATH, 'app.js'), - path.join(SRC_PATH, '**/*.html'), - 'index.js' - ], - plugins: [ - 'karma-webpack', - 'karma-jasmine', - 'karma-junit-reporter', - 'karma-phantomjs-launcher', - 'karma-html2js-preprocessor' - ], - preprocessors: { - [path.join(SRC_PATH, 'vendor.js')]: 'webpack', - [path.join(SRC_PATH, 'app.js')]: 'webpack', - [path.join(SRC_PATH, '**/*.html')]: 'html2js', - 'index.js': 'webpack' - }, - webpack: webpackConfig, - webpackMiddleware: { - noInfo: 'errors-only' - }, - junitReporter: { - outputDir: 'reports', - outputFile: 'results.unit.xml', - useBrowserName: false - } - }); -}; diff --git a/awx/ui/test/unit/models/base.unit.js b/awx/ui/test/unit/models/base.unit.js deleted file mode 100644 index f721c12a0ad9..000000000000 --- a/awx/ui/test/unit/models/base.unit.js +++ /dev/null @@ -1,25 +0,0 @@ -describe('Models | BaseModel', () => { - let baseModel; - - beforeEach(() => { - angular.mock.module('at.lib.services'); - angular.mock.module('at.lib.models'); - }); - - beforeEach(angular.mock.inject(($injector) => { - baseModel = new ($injector.get('BaseModel'))('test'); - })); - - describe('parseRequestConfig', () => { - it('always returns the expected configuration', () => { - const { parseRequestConfig } = baseModel; - const data = { name: 'foo' }; - - expect(parseRequestConfig('get')).toEqual({ method: 'get', resource: undefined }); - expect(parseRequestConfig('get', 1)).toEqual({ method: 'get', resource: 1 }); - expect(parseRequestConfig('post', { data })).toEqual({ method: 'post', data }); - expect(parseRequestConfig(['get', 'post'], [1, 2], { data })) - .toEqual({ resource: [1, 2], method: ['get', 'post'] }); - }); - }); -}); diff --git a/awx/ui/test/unit/models/index.js b/awx/ui/test/unit/models/index.js deleted file mode 100644 index a1a9b3452a2d..000000000000 --- a/awx/ui/test/unit/models/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Import angular and angular-mocks to the global scope -import 'angular-mocks'; - -// Import tests -import './base.unit'; diff --git a/awx/ui/test/unit/polyfills.js b/awx/ui/test/unit/polyfills.js deleted file mode 100644 index 25b18055bd1c..000000000000 --- a/awx/ui/test/unit/polyfills.js +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable */ - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill - -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} diff --git a/awx/ui/test/unit/webpack.unit.js b/awx/ui/test/unit/webpack.unit.js deleted file mode 100644 index 7ec1a9a7235f..000000000000 --- a/awx/ui/test/unit/webpack.unit.js +++ /dev/null @@ -1,16 +0,0 @@ -const webpack = require('webpack'); -const merge = require('webpack-merge'); -const base = require('../../build/webpack.base'); - -const STATIC_URL = '/static/'; - -const test = { - devtool: 'cheap-source-map', - plugins: [ - new webpack.DefinePlugin({ - $basePath: STATIC_URL - }) - ] -}; - -module.exports = merge(base, test); diff --git a/awx/ui/urls.py b/awx/ui/urls.py deleted file mode 100644 index 1b4e6775d2c3..000000000000 --- a/awx/ui/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -from django.conf.urls import url -from awx.ui.views import ( - index, - portal_redirect, - migrations_notran, -) - - -app_name = 'ui' -urlpatterns = [ - url(r'^$', index, name='index'), - url(r'^migrations_notran/$', migrations_notran, name='migrations_notran'), - url(r'^portal/$', portal_redirect, name='portal_redirect'), -] diff --git a/awx/ui/views.py b/awx/ui/views.py deleted file mode 100644 index 9e99ad9d22b1..000000000000 --- a/awx/ui/views.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -from django.views.generic.base import TemplateView, RedirectView -from django.conf import settings - -class IndexView(TemplateView): - - template_name = 'ui/index.html' - - def get_context_data(self, **kwargs): - context = super(IndexView, self).get_context_data(**kwargs) - context['UI_LIVE_UPDATES_ENABLED'] = settings.UI_LIVE_UPDATES_ENABLED - # Add any additional context info here. - return context - -index = IndexView.as_view() - -class PortalRedirectView(RedirectView): - - permanent = True - url = '/#/portal' - -portal_redirect = PortalRedirectView.as_view() - -class MigrationsNotran(TemplateView): - - template_name = 'ui/installing.html' - -migrations_notran = MigrationsNotran.as_view() diff --git a/awx/ui_next/.eslintignore b/awx/ui_next/.eslintignore new file mode 100644 index 000000000000..eb4a217ff602 --- /dev/null +++ b/awx/ui_next/.eslintignore @@ -0,0 +1,10 @@ +jest.*.js +webpack.*.js + +etc +coverage +build +node_modules +dist +images +instrumented \ No newline at end of file diff --git a/awx/ui_next/.eslintrc b/awx/ui_next/.eslintrc new file mode 100644 index 000000000000..e2bf9305bdbb --- /dev/null +++ b/awx/ui_next/.eslintrc @@ -0,0 +1,59 @@ +{ + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "modules": true + } + }, + "plugins": ["react-hooks", "jsx-a11y"], + "extends": ["airbnb", "prettier", "prettier/react", "plugin:jsx-a11y/strict"], + "settings": { + "react": { + "version": "16.5.2" + } + }, + "env": { + "browser": true, + "node": true, + "jest": true + }, + "globals": { + "window": true + }, + "rules": { + "camelcase": "off", + "arrow-parens": "off", + "comma-dangle": "off", + // https://github.com/benmosher/eslint-plugin-import/issues/479#issuecomment-252500896 + "import/no-extraneous-dependencies": "off", + "max-len": [ + "error", + { + "code": 100, + "ignoreStrings": true, + "ignoreTemplateLiterals": true + } + ], + "no-continue": "off", + "no-debugger": "off", + "no-mixed-operators": "off", + "no-param-reassign": "off", + "no-plusplus": "off", + "no-underscore-dangle": "off", + "no-use-before-define": "off", + "no-multiple-empty-lines": ["error", { "max": 1 }], + "object-curly-newline": "off", + "no-trailing-spaces": ["error"], + "no-unused-expressions": ["error", { "allowShortCircuit": true }], + "react/prefer-stateless-function": "off", + "react/prop-types": "off", + "react/sort-comp": ["error", {}], + "jsx-a11y/label-has-for": "off", + "jsx-a11y/label-has-associated-control": "off", + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" + } +} diff --git a/awx/ui_next/.linguirc b/awx/ui_next/.linguirc new file mode 100644 index 000000000000..5b9ca7902b21 --- /dev/null +++ b/awx/ui_next/.linguirc @@ -0,0 +1,6 @@ +{ + "localeDir": "src/locales/", + "srcPathDirs": ["src/"], + "format": "po", + "sourceLocale": "en" +} diff --git a/awx/ui_next/.npmrc b/awx/ui_next/.npmrc new file mode 100644 index 000000000000..c42da845b449 --- /dev/null +++ b/awx/ui_next/.npmrc @@ -0,0 +1 @@ +engine-strict = true diff --git a/awx/ui_next/.prettierrc b/awx/ui_next/.prettierrc new file mode 100644 index 000000000000..93b2f46c80a0 --- /dev/null +++ b/awx/ui_next/.prettierrc @@ -0,0 +1,8 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/awx/ui_next/CONTRIBUTING.md b/awx/ui_next/CONTRIBUTING.md new file mode 100644 index 000000000000..c0a3eaefc44a --- /dev/null +++ b/awx/ui_next/CONTRIBUTING.md @@ -0,0 +1,347 @@ +# Ansible AWX UI With PatternFly + +Hi there! We're excited to have you as a contributor. + +Have questions about this document or anything not covered here? Feel free to reach out to any of the contributors of this repository. + +## Table of contents + +- [Ansible AWX UI With PatternFly](#ansible-awx-ui-with-patternfly) + - [Table of contents](#table-of-contents) + - [Things to know prior to submitting code](#things-to-know-prior-to-submitting-code) + - [Setting up your development environment](#setting-up-your-development-environment) + - [Prerequisites](#prerequisites) + - [Node and npm](#node-and-npm) + - [Build the User Interface](#build-the-user-interface) + - [Accessing the AWX web interface](#accessing-the-awx-web-interface) + - [AWX REST API Interaction](#awx-rest-api-interaction) + - [Handling API Errors](#handling-api-errors) + - [Forms](#forms) + - [Working with React](#working-with-react) + - [App structure](#app-structure) + - [Patterns](#patterns) + - [Bootstrapping the application (root src/ files)](#bootstrapping-the-application-root-src-files) + - [Naming files](#naming-files) + - [Naming components that use the context api](#naming-components-that-use-the-context-api) + - [Class constructors vs Class properties](#class-constructors-vs-class-properties) + - [Binding](#binding) + - [Typechecking with PropTypes](#typechecking-with-proptypes) + - [Custom Hooks](#custom-hooks) + - [Naming Functions](#naming-functions) + - [Default State Initialization](#default-state-initialization) + - [Testing components that use contexts](#testing-components-that-use-contexts) + - [Internationalization](#internationalization) + - [Marking strings for translation and replacement in the UI](#marking-strings-for-translation-and-replacement-in-the-ui) + - [Setting up .po files to give to translation team](#setting-up-po-files-to-give-to-translation-team) + - [Marking an issue to be translated](#marking-an-issue-to-be-translated) + + +## Things to know prior to submitting code + +- All code submissions are done through pull requests against the `devel` branch. +- If collaborating with someone else on the same branch, please use `--force-with-lease` instead of `--force` when pushing up code. This will prevent you from accidentally overwriting commits pushed by someone else. For more information, see https://git-scm.com/docs/git-push#git-push---force-with-leaseltrefnamegt +- We use a [code formatter](https://prettier.io/). Before adding a new commit or opening a PR, please apply the formatter using `npm run prettier` +- We adopt the following code style guide: + - functions should adopt camelCase + - constructors/classes should adopt PascalCase + - constants to be exported should adopt UPPERCASE +- For strings, we adopt the `sentence capitalization` since it is a [Patternfly style guide](https://www.patternfly.org/v4/design-guidelines/content/grammar-and-terminology#capitalization). + +## Setting up your development environment + +The UI is built using [ReactJS](https://reactjs.org/docs/getting-started.html) and [Patternfly](https://www.patternfly.org/). + +### Prerequisites + +#### Node and npm + +The AWX UI requires the following: + +- Node 14.x LTS +- NPM 6.x LTS + +Run the following to install all the dependencies: +```bash +(host) $ npm run install +``` + +#### Build the User Interface + +Run the following to build the AWX UI: + +```bash +(host) $ npm run start +``` + +## Accessing the AWX web interface + +You can now log into the AWX web interface at [https://127.0.0.1:3001](https://127.0.0.1:3001). + +## AWX REST API Interaction + +This interface is built on top of the AWX REST API. If a component needs to interact with the API then the model that corresponds to that base endpoint will need to be imported from the api module. + +Example: + +`import { OrganizationsAPI, UsersAPI } from '../../../api';` + +All models extend a `Base` class which provides an interface to the standard HTTP methods (GET, POST, PUT etc). Methods that are specific to that endpoint should be added directly to model's class. + +**Mixins** - For related endpoints that apply to several different models a mixin should be used. Mixins are classes with a number of methods and can be used to avoid adding the same methods to a number of different models. A good example of this is the Notifications mixin. This mixin provides generic methods for reading notification templates and toggling them on and off. +Note that mixins can be chained. See the example below. + +Example of a model using multiple mixins: + +```javascript +import NotificationsMixin from '../mixins/Notifications.mixin'; +import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; + +class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) { + ... +} + +export default Organizations; +``` + +**Testing** - The easiest way to mock the api module in tests is to use jest's [automatic mock](https://jestjs.io/docs/en/es6-class-mocks#automatic-mock). This syntax will replace the class with a mock constructor and mock out all methods to return undefined by default. If necessary, you can still override these mocks for specific tests. See the example below. + +Example of mocking a specific method for every test in a suite: + +```javascript +import { OrganizationsAPI } from '../../../../src/api'; + +// Mocks out all available methods. Comparable to: +// OrganizationsAPI.readAccessList = jest.fn(); +// but for every available method +jest.mock('../../../../src/api'); + +// Return a specific mock value for the readAccessList method +beforeEach(() => { + OrganizationsAPI.readAccessList.mockReturnValue({ foo: 'bar' }); +}); + +// Reset mocks +afterEach(() => { + jest.clearAllMocks(); +}); + +... +``` + +**Test Attributes** - +It should be noted that the `dataCy` prop, as well as its equivalent attribute `data-cy`, are used as flags for any UI test that wants to avoid relying on brittle CSS selectors such as `nth-of-type()`. + +## Handling API Errors +API requests can and will fail occasionally so they should include explicit error handling. The three _main_ categories of errors from our perspective are: content loading errors, form submission errors, and other errors. The patterns currently in place for these are described below: + +- **content loading errors** - These are any errors that occur when fetching data to initialize a page or populate a list. For these, we conditionally render a _content error component_ in place of the unresolved content. + +- **form submission errors** - If an error is encountered when submitting a form, we display the error message on the form. For field-specific validation errors, we display the error message beneath the specific field(s). For general errors, we display the error message at the bottom of the form near the action buttons. An error that happens when requesting data to populate a form is not a form submission error, it is still a content error and is handled as such (see above). + +- **other errors** - Most errors will fall into the first two categories, but for miscellaneous actions like toggling notifications, deleting a list item, etc. we display an alert modal to notify the user that their requested action couldn't be performed. + +## Forms +Our forms should have a known, consistent, and fully-resolved starting state before it is possible for a user, keyboard-mouse, screen reader, or automated test to interact with them. If multiple network calls are needed to populate a form, resolve them all before displaying the form or showing a content error. When multiple requests are needed to create or update the resources represented by a form, resolve them all before transitioning the ui to a success or failure state. + +## Working with React + +### App structure + +All source code lives in the `/src` directory and all tests are colocated with the components that they test. + +Inside these folders, the internal structure is: +- **/api** - All classes used to interact with API's are found here. See [AWX REST API Interaction](#awx-rest-api-interaction) for more information. +- **/components** - All generic components that are meant to be used in multiple contexts throughout awx. Things like buttons, tabs go here. +- **/contexts** - Components which utilize react's context api. +- **/locales** - [Internationalization](#internationalization) config and source files. +- **/screens** - Based on the various routes of awx. + - **/shared** - Components that are meant to be used specifically by a particular route, but might be sharable across pages of that route. For example, a form component which is used on both add and edit screens. +- **/util** - Stateless helper functions that aren't tied to react. + +### Patterns +- A **screen** shouldn't import from another screen. If a component _needs_ to be shared between two or more screens, it is a generic and should be moved to `src/components`. + +#### Bootstrapping the application (root src/ files) + +In the root of `/src`, there are a few files which are used to initialize the react app. These are + +- **index.jsx** + - Connects react app to root dom node. + - Sets up root route structure, navigation grouping and login modal + - Calls base context providers + - Imports .scss styles. +- **app.jsx** + - Sets standard page layout, about modal, and root dialog modal. +- **RootProvider.jsx** + - Sets up all context providers. + - Initializes i18n and router + +### Naming files + +Ideally, files should be named the same as the component they export, and tests with `.test` appended. In other words, `` would be defined in `FooBar.jsx`, and its tests would be defined in `FooBar.test.jsx`. + +#### Naming components that use the context api + +**File naming** - Since contexts export both consumer and provider (and potentially in withContext function form), the file can be simplified to be named after the consumer export. In other words, the file containing the `Network` context components would be named `Network.jsx`. + +**Component naming and conventions** - In order to provide a consistent interface with react-router and [lingui](https://lingui.js.org/), as well as make their usage easier and less verbose, context components follow these conventions: +- Providers are wrapped in a component in the `FooProvider` format. + - The value prop of the provider should be pulled from state. This is recommended by the react docs, [here](https://reactjs.org/docs/context.html#caveats). + - The provider should also be able to accept its value by prop for testing. + - Any sort of code related to grabbing data to put on the context should be done in this component. +- Consumers are wrapped in a component in the `Foo` format. +- If it makes sense, consumers can be exported as a function in the `withFoo()` format. If a component is wrapped in this function, its context values are available on the component as props. + +### Class constructors vs Class properties +It is good practice to use constructor-bound instance methods rather than methods as class properties. Methods as arrow functions provide lexical scope and are bound to the Component class instance instead of the class itself. This makes it so we cannot easily test a Component's methods without invoking an instance of the Component and calling the method directly within our tests. + +BAD: + ```javascript + class MyComponent extends React.Component { + constructor(props) { + super(props); + } + + myEventHandler = () => { + // do a thing + } + } + ``` +GOOD: + ```javascript + class MyComponent extends React.Component { + constructor(props) { + super(props); + this.myEventHandler = this.myEventHandler.bind(this); + } + + myEventHandler() { + // do a thing + } + } + ``` + +### Binding +It is good practice to bind our class methods within our class constructor method for the following reasons: + 1. Avoid defining the method every time `render()` is called. + 2. [Performance advantages](https://stackoverflow.com/a/44844916). + 3. Ease of [testing](https://github.com/airbnb/enzyme/issues/365). + +### Typechecking with PropTypes +Shared components should have their prop values typechecked. This will help catch bugs when components get refactored/renamed. +```javascript +About.propTypes = { + ansible_version: PropTypes.string, + isOpen: PropTypes.bool, + onClose: PropTypes.func.isRequired, + version: PropTypes.string, +}; + +About.defaultProps = { + ansible_version: null, + isOpen: false, + version: null, +}; +``` + +### Custom Hooks + +There are currently a few custom hooks: + +1. [useRequest](https://github.com/ansible/awx/blob/devel/awx/ui_next/src/util/useRequest.js#L21) encapsulates main actions related to requests. +2. [useDismissableError](https://github.com/ansible/awx/blob/devel/awx/ui_next/src/util/useRequest.js#L71) provides controls for "dismissing" an error message. +3. [useDeleteItems](https://github.com/ansible/awx/blob/devel/awx/ui_next/src/util/useRequest.js#L98) handles deletion of items from a paginated item list. +4. [useSelected](https://github.com/ansible/awx/blob/devel/awx/ui_next/src/util/useSelected.jsx#L14) provides a way to read and update a selected list. + +### Naming Functions +Here are the guidelines for how to name functions. + +| Naming Convention | Description | +| ----------------- | --------------------------------------------------------------------------------- | +| `handle` | Use for methods that process events | +| `on` | Use for component prop names | +| `toggle` | Use for methods that flip one value to the opposite value | +| `show` | Use for methods that always set a value to show or add an element | +| `hide` | Use for methods that always set a value to hide or remove an element | +| `create` | Use for methods that make API `POST` requests | +| `read` | Use for methods that make API `GET` requests | +| `update` | Use for methods that make API `PATCH` requests | +| `destroy` | Use for methods that make API `DESTROY` requests | +| `replace` | Use for methods that make API `PUT` requests | +| `disassociate` | Use for methods that pass `{ disassociate: true }` as a data param to an endpoint | +| `associate` | Use for methods that pass a resource id as a data param to an endpoint | +| `can` | Use for props dealing with RBAC to denote whether a user has access to something | + +### Default State Initialization +When declaring empty initial states, prefer the following instead of leaving them undefined: + +```javascript +this.state = { + somethingA: null, + somethingB: [], + somethingC: 0, + somethingD: {}, + somethingE: '', +} +``` + +### Testing components that use contexts + +We have several React contexts that wrap much of the app, including those from react-router, lingui, and some of our own. When testing a component that depends on one or more of these, you can use the `mountWithContexts()` helper function found in `testUtils/enzymeHelpers.jsx`. This can be used just like Enzyme's `mount()` function, except it will wrap the component tree with the necessary context providers and basic stub data. + +If you want to stub the value of a context, or assert actions taken on it, you can customize a contexts value by passing a second parameter to `mountWithContexts`. For example, this provides a custom value for the `Config` context: + +```javascript +const config = { + custom_virtualenvs: ['foo', 'bar'], +}; +mountWithContexts(, { + context: { config }, +}); +``` + +Now that these custom virtual environments are available in this `OrganizationForm` test we can assert that the component that displays +them is rendering properly. + +The object containing context values looks for five known contexts, identified by the keys `linguiPublisher`, `router`, `config`, `network`, and `dialog` — the latter three each referring to the contexts defined in `src/contexts`. You can pass `false` for any of these values, and the corresponding context will be omitted from your test. For example, this will mount your component without the dialog context: + +```javascript +mountWithContexts(< { + context: { + dialog: false, + } +}); +``` + +## Internationalization + +Internationalization leans on the [lingui](https://github.com/lingui/js-lingui) project. [Official documentation here](https://lingui.js.org/). We use this library to mark our strings for translation. If you want to see this in action you'll need to take the following steps: + +### Marking strings for translation and replacement in the UI + +The lingui library provides various React helpers for dealing with both marking strings for translation, and replacing strings that have been translated. For consistency and ease of use, we have consolidated on one pattern for the codebase. To set strings to be translated in the UI: + +- import the withI18n function and wrap the export of your component in it (i.e. `export default withI18n()(Foo)`) +- doing the above gives you access to the i18n object on props. Make sure to put it in the scope of the function that contains strings needed to be translated (i.e. `const { i18n } = this.props;`) +- import the t template tag function from the @lingui/macro package. +- wrap your string using the following format: ```i18n._(t`String to be translated`)``` + +**Note:** Variables that are put inside the t-marked template tag will not be translated. If you have a variable string with text that needs translating, you must wrap it in ```i18n._(t``)``` where it is defined. + +**Note:** We try to avoid the `I18n` consumer, `i18nMark` function, or `` component lingui gives us access to in this repo. i18nMark does not actually replace the string in the UI (leading to the potential for untranslated bugs), and the other helpers are redundant. Settling on a consistent, single pattern helps us ease the mental overhead of the need to understand the ins and outs of the lingui API. + +You can learn more about the ways lingui and its React helpers at [this link](https://lingui.js.org/tutorials/react-patterns.html). + +### Setting up .po files to give to translation team + +1) `npm run add-locale` to add the language that you want to translate to (we should only have to do this once and the commit to repo afaik). Example: `npm run add-locale en es fr` # Add English, Spanish and French locale +2) `npm run extract-strings` to create .po files for each language specified. The .po files will be placed in src/locales. +3) Open up the .po file for the language you want to test and add some translations. In production we would pass this .po file off to the translation team. +4) Once you've edited your .po file (or we've gotten a .po file back from the translation team) run `npm run compile-strings`. This command takes the .po files and turns them into a minified JSON object and can be seen in the `messages.js` file in each locale directory. These files get loaded at the App root level (see: App.jsx). +5) Change the language in your browser and reload the page. You should see your specified translations in place of English strings. + +### Marking an issue to be translated + +1) Issues marked with `component:I10n` should not be closed after the issue was fixed. +2) Remove the label `state:needs_devel`. +3) Add the label `state:pending_translations`. At this point, the translations will be batch translated by a maintainer, creating relevant entries in the PO files. Then after those translations have been merged, the issue can be closed. diff --git a/awx/ui_next/Dockerfile b/awx/ui_next/Dockerfile new file mode 100644 index 000000000000..a710a820cd7c --- /dev/null +++ b/awx/ui_next/Dockerfile @@ -0,0 +1,15 @@ +FROM node:14 +ARG NPMRC_FILE=.npmrc +ENV NPMRC_FILE=${NPMRC_FILE} +ARG TARGET='https://awx:8043' +ENV TARGET=${TARGET} +ENV CI=true +WORKDIR /ui_next +ADD public public +ADD package.json package.json +ADD package-lock.json package-lock.json +COPY ${NPMRC_FILE} .npmrc +RUN npm install +ADD src src +EXPOSE 3001 +CMD [ "npm", "start" ] diff --git a/awx/ui_next/README.md b/awx/ui_next/README.md new file mode 100644 index 000000000000..2755f136d93d --- /dev/null +++ b/awx/ui_next/README.md @@ -0,0 +1,99 @@ +# AWX-PF + +## Requirements +- node 14.x LTS, npm 6.x LTS, make, git + +## Development +The API development server will need to be running. See [CONTRIBUTING.md](../../CONTRIBUTING.md). + +```shell +# install +npm --prefix=awx/ui_next install + +# Start the ui development server. While running, the ui will be reachable +# at https://127.0.0.1:3001 and updated automatically when code changes. +npm --prefix=awx/ui_next start +``` + +### Build for the Development Containers +If you just want to build a ui for the container-based awx development +environment, use these make targets: + +```shell +# The ui will be reachable at https://localhost:8043 or +# http://localhost:8013 +make ui-devel + +# clean up +make clean-ui +``` + +### Using an External Server +If you normally run awx on an external host/server (in this example, `awx.local`), +you'll need use the `TARGET` environment variable when starting the ui development +server: + +```shell +TARGET='https://awx.local:8043' npm --prefix awx/ui_next start +``` + +## Testing +```shell +# run code formatting check +npm --prefix awx/ui_next run prettier-check + +# run lint checks +npm --prefix awx/ui_next run lint + +# run all unit tests +npm --prefix awx/ui_next run test + +# run a single test (in this case the login page test): +npm --prefix awx/ui_next test -- src/screens/Login/Login.test.jsx + +# start the test watcher and run tests on files that you've changed +npm --prefix awx/ui_next run test-watch +``` +#### Note: +- Once the test watcher is up and running you can hit `a` to run all the tests. +- All commands are run on your host machine and not in the api development containers. + + +## Adding Dependencies +```shell +# add an exact development or build dependency +npm --prefix awx/ui_next install --save-dev --save-exact dev-package@1.2.3 + +# add an exact production dependency +npm --prefix awx/ui_next install --save --save-exact prod-package@1.23 + +# add the updated package.json and package-lock.json files to scm +git add awx/ui_next_next/package.json awx/ui_next_next/package-lock.json +``` + +## Removing Dependencies +```shell +# remove a development or build dependency +npm --prefix awx/ui_next uninstall --save-dev dev-package + +# remove a production dependency +npm --prefix awx/ui_next uninstall --save prod-package +``` + +## Building for Production +```shell +# built files are placed in awx/ui_next/build +npm --prefix awx/ui_next run build +``` + +## CI Container + +To run: + +```shell +cd awx/awx/ui_next +docker build -t awx-ui-next . +docker run --name tools_ui_next_1 --network tools_default --link 'tools_awx_1:awx' -e TARGET="https://awx:8043" -p '3001:3001' --rm -v $(pwd)/src:/ui_next/src awx-ui-next +``` + +**Note:** This is for CI, test systems, zuul, etc. For local development, see [usage](https://github.com/ansible/awx/blob/devel/awx/ui_next/README.md#Development) diff --git a/awx/ui_next/SEARCH.md b/awx/ui_next/SEARCH.md new file mode 100644 index 000000000000..111dfb2f56b0 --- /dev/null +++ b/awx/ui_next/SEARCH.md @@ -0,0 +1,389 @@ +# Simple Search + +## UX Considerations + +Historically, the code that powers search in the AngularJS version of the AWX/Tower UI is very complex and prone to bugs. In order to reduce that complexity, we've made some UX decisions to help make the code easier to maintain. + +**ALL query params namespaced and in url bar** + +This includes lists that aren't necessarily hyperlinked, like lookup lists. The reason behind this is so we can treat the url bar as the source of truth for queries always. Any params that have both a key AND value that is in the defaultParams section of the qs config are stripped out of the search string (see "Encoding for UI vs. API" for more info on this point) + +**Django fuzzy search (`?search=`) is not accessible outside of "advanced search"** + +In current smart search typing a term with no key utilizes `?search=` i.e. for "foo" tag, `?search=foo` is given. `?search=` looks on a static list of field name "guesses" (such as name, description, etc.), as well as specific fields as defined for each endpoint (for example, the events endpoint looks for a "stdout" field as well). Due to the fact a key will always be present on the left-hand of simple search, it doesn't make sense to use `?search=` as the default. + +We may allow passing of `?search=` through our future advanced search interface. Some details that were gathered in planning phases about `?search=` that might be helpful in the future: +- `?search=` tags are OR'd together (union is returned). +- `?search=foo&name=bar` returns items that have a name field of bar (not case insensitive) AND some text field with foo on it +- `?search=foo&search=bar&name=baz` returns (foo in name OR foo in description OR ...) AND (bar in name OR bar in description OR ...) AND (baz in name) +- similarly `?related__search=` looks on the static list of "guesses" for models related to the endpoint. The specific fields are not "searched" for `?related__search=`. +- `?related__search=` not currently used in awx ui + +**A note on clicking a tag to putting it back into the search bar** + +This was brought up as a nice to have when we were discussing our initial implementation of search in the new application. Since there isn't a way we would be able to know if the user created the tag from the simple or advanced search interface, we wouldn't know where to put it back. This breaks our idea of using the query params as the exclusive source of truth, so we've decided against implementing it for now. + +## Tasklist + +### DONE + +- DONE update handleSearch to follow handleSort param +- DONE update qsConfig columns to utilize isSearchable bool (just like isSortable bool) +- DONE enter keydown in text search bar to search +- DONE get decoded params and write test +- DONE make list header component +- DONE make filter component +- DONE make filters show up for empty list +- DONE make clear all button +- DONE styling of FilterTags component +- DONE clear out text input after tag has been made +- DONE deal with duplicate key tags being added/removed in qs util file +- DONE deal with widgetry changing between one dropdown option to the left of search and many +- DONE bug: figure out why ?name=org returning just org not “org 2” +- DONE update contrib file to have the first section with updated text as is in this pr description. +- DONE rebase with latest awx-pf changes +- DONE styling of search bar +- DONE make filter and list header tests +- DONE change api paramsSerializer to handle duplicate key stuff +- DONE update qs update function to be smaller, simple param functions, as opposed to one big one with a lot of params +- DONE add search filter removal test for qs. +- DONE remove button for search tags of duplicate keys are broken, fix that + +### TODO pre-holiday break +- Update COLUMNS to SORT_COLUMNS and SEARCH_COLUMNS +- Update to using new PF Toolbar component (currently an experimental component) +- Change the right-hand input based on the type of key selected on the left-hand side. In addition to text input, for our MVP we will support: + - number input + - select input (multiple-choice configured from UI or Options) +- Update the following lists to have the following keys: + +**Jobs list** (signed off earlier in chat) + - Name (which is also the name of the job template) - search is ?name=jt + - Job ID - search is ?id=13 + - Label name - search is ?labels__name=foo + - Job type (dropdown on right with the different types) ?type = job + - Created by (username) - search is ?created_by__username=admin + - Status - search (dropdown on right with different statuses) is ?status=successful + +Instances of jobs list include: + - Jobs list + - Host completed jobs list + - JT completed jobs list + +**Organization list** + - Name - search is ?name=org + - ? Team name (of a team in the org) - search is ?teams__name=ansible + - ? Username (of a user in the org) - search is ?users__username=johndoe + +Instances of orgs list include: + - Orgs list + - User orgs list + - Lookup on Project + - Lookup on Credential + - Lookup on Inventory + - User access add wizard list + - Team access add wizard list + +**Instance Groups list** + - Name - search is ?name=ig + - ? is_containerized boolean choice (doesn't work right now in API but will soon) - search is ?is_containerized=true + - ? credential name - search is ?credentials__name=kubey + +Instance of instance groups list include: + - Lookup on Org + - Lookup on JT + - Lookup on Inventory + +**Users list** + - Username - search is ?username=johndoe + - First Name - search is ?first_name=John + - Last Name - search is ?last_name=Doe + - ? (if not superfluous, would not include on Team users list) Team Name - search is ?teams__name=team_of_john_does (note API issue: User has no field named "teams") + - ? (only for access or permissions list) Role Name - search is ?roles__name=Admin (note API issue: Role has no field "name") + - ? (if not superfluous, would not include on Organization users list) ORg Name - search is ?organizations__name=org_of_jhn_does + +Instance of user lists include: + - User list + - Org user list + - Access list for Org, JT, Project, Credential, Inventory, User and Team + - Access list for JT + - Access list Project + - Access list for Credential + - Access list for Inventory + - Access list for User + - Access list for Team + - Team add users list + - Users list in access wizard (to add new roles for a particular list) for Org + - Users list in access wizard (to add new roles for a particular list) for JT + - Users list in access wizard (to add new roles for a particular list) for Project + - Users list in access wizard (to add new roles for a particular list) for Credential + - Users list in access wizard (to add new roles for a particular list) for Inventory + +**Teams list** + - Name - search is ?name=teamname + - ? Username (of a user in the team) - search is ?users__username=johndoe + - ? (if not superfluous, would not include on Organizations teams list) Org Name - search is ?organizations__name=org_of_john_does + +Instance of team lists include: + - Team list + - Org team list + - User team list + - Team list in access wizard (to add new roles for a particular list) for Org + - Team list in access wizard (to add new roles for a particular list) for JT + - Team list in access wizard (to add new roles for a particular list) for Project + - Team list in access wizard (to add new roles for a particular list) for Credential + - Team list in access wizard (to add new roles for a particular list) for Inventory + +**Credentials list** + - Name + - ? Type (dropdown on right with different types) + - ? Created by (username) + - ? Modified by (username) + +Instance of credential lists include: + - Credential list + - Lookup for JT + - Lookup for Project + - User access add wizard list + - Team access add wizard list + +**Projects list** + - Name - search is ?name=proj + - ? Type (dropdown on right with different types) - search is scm_type=git + - ? SCM URL - search is ?scm_url=github.com/ansible/test-playbooks + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of project lists include: + - Project list + - Lookup for JT + - User access add wizard list + - Team access add wizard list + +**Templates list** + - Name - search is ?name=cleanup + - ? Type (dropdown on right with different types) - search is ?type=playbook_run + - ? Playbook name - search is ?job_template__playbook=debug.yml + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of template lists include: + - Template list + - Project Templates list + +**Inventories list** + - Name - search is ?name=inv + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of inventory lists include: + - Inventory list + - Lookup for JT + - User access add wizard list + - Team access add wizard list + +**Groups list** + - Name - search is ?name=group_name + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of group lists include: + - Group list + +**Hosts list** + - Name - search is ?name=hostname + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of host lists include: + - Host list + +**Notifications list** + - Name - search is ?name=notification_template_name + - ? Type (dropdown on right with different types) - search is ?type=slack + - ? Created by (username) - search is ?created_by__username=admin + - ? Modified by (username) - search is ?modified_by__username=admin + +Instance of notification lists include: + - Org notification list + - JT notification list + - Project notification list + +### TODO backlog +- Change the right-hand input based on the type of key selected on the left-hand side. We will eventually want to support: + - lookup input (selection of particular resources, based on API list endpoints) + - date picker input +- Update the following lists to have the following keys: + - Update all __name and __username related field search-based keys to be type-ahead lookup based searches + +## Code Details + +### Search component + +The component looks like this: + +``` + +``` + +**qsConfig** is used to get namespace so that multiple lists can be on the page. When tags are modified they append namespace to query params. The qsConfig is also used to get "type" of fields in order to correctly parse values as int or date as it is translating. + +**columns** are passed as an array, as defined in the screen where the list is located. You pass a bool `isDefault` to indicate that should be the key that shows up in the left-hand dropdown as default in the UI. If you don't pass any columns, a default of `isDefault=true` will be added to a name column, which is nearly universally shared throughout the models of awx. + +There is a type attribute that can be `'string'`, `'number'` or `'choice'` (and in the future, `'date'` and `'lookup'`), which will change the type of input on the right-hand side of the search bar. For a key that has a set number of choices, you will pass a choices attribute, which is an array in the format choices: [{label: 'Foo', value: 'foo'}] + +**onSearch** calls the `mergeParams` qs util in order to add new tags to the queryset. mergeParams is used so that we can support duplicate keys (see mergeParams vs. replaceParams for more info). + +### ListHeader component + +`DataListToolbar`, `EmptyListControls`, and `FilterTags` components were created or moved to a new sub-component of `PaginatedDataList`, `ListHeader`. This allowed us to consolidate the logic between both lists with data (which need to show search, sort, any search tags currently active, and actions) as well as empty lists (which need to show search tags currently active so they can be removed, potentially getting you back to a "list-has-data" state, as well as a subset of options still valid, such as "add"). + +The ability to search and remove filters, as well as sort the list is handled through callbacks which are passed from functions defined in `ListHeader`. These are the following: + +- `handleSort(key, direction)` - use key and direction of sort to change the order_by value in the queryset +- `handleSearch(key, value)` - use key and value to push a new value to the param +- `handleRemove(key, value)` - use key and value to remove a value to the param +- `handleRemoveAll()` - remove all non-default params + +All of these functions act on the react-router history using the `pushHistoryState` function. This causes the query params in the url to update, which in turn triggers change handlers that will re-fetch data for the lists. + +**a note on sort_columns and search_columns** + +We have split out column configuration into separate search and sort column array props--these are passed to the search and sort columns. Both accept an isDefault prop for one of the items in the array to be the default option selected when going to the page. Sort column items can pass an isNumeric boolean in order to chnage the iconography of the sort UI element. Search column items can pass type and if applicable choices, in order to configure the right-hand side of the search bar. + +### FilterTags component + +Similar to the way the list grabs data based on changes to the react-router params, the `FilterTags` component updates when new params are added. This component is a fairly straight-forward map (only slightly complex, because it needed to do a nested map over any values with duplicate keys that were represented by an inner-array). Both key and value are displayed for the tag. + +### qs utility + +The qs (queryset) utility is used to make the search speak the language of the REST API. The main functions of the utilities are to: +- add, replace and remove filters +- translate filters as url params (for linking and maintaining state), in-memory representation (as JS objects), and params that Django REST Framework understands. + +More info in the below sections: + +#### Encoding for UI vs. API + +For the UI url params, we want to only encode those params that aren't defaults, as the default behavior was defined through configuration and we don't need these in the url as a source of truth. For the API, we need to pass these params so that they are taken into account when the response is built. + +#### mergeParams vs. replaceParams + +**mergeParams** is used to suppport putting values with the same key + +From a UX perspective, we wanted to be able to support searching on the same key multiple times (i.e. searching for things like `?foo=bar&foo=baz`). We do this by creating an array of all values. i.e.: + +``` +{ + foo: ['bar', 'baz'] +} +``` + +Concatenating terms in this way gives you the intersection of both terms (i.e. foo must be "bar" and "baz"). This is helpful for the most-common type of searching, substring (`__icontains`) searches. This will increase filtering, allowing the user to drill-down into the list as terms are added. + +**replaceParams** is used to support sorting, setting page_size, etc. These params only allow one choice, and we need to replace a particular key's value if one is passed. + +#### Working with REST API + +The REST API is coupled with the qs util through the `paramsSerializer`, due to the fact we need axios to support the array for duplicate key values in the object representation of the params to pass to the get request. This is done where axios is configured in the Base.js file, so all requests and request types should support our array syntax for duplicate keys automatically. + +# Advanced Search - this section is a mess, update eventually + +**a note on typing in a smart search query** + +In order to not support a special "language" or "syntax" for crafting the query like we have now (and is the cause of a large amount of bugs), we will not support the old way of typing in a filter like in the current implementation of search. + +Since all search bars are represented in the url, for users who want to input a string to filter results in a single step, typing directly in the url to achieve the filter is acceptable. + +# Advanced search notes + +Current thinking is Advanced Search will be post-3.6, or at least late 3.6 after awx features and "simple search" with the left dropdown and right input for the above phase 1 lists. + +That being said, we want to plan it out so we make sure the infrastructure of how we set up adding/removing tags, what shows up in the url bar, etc. all doesn't have to be redone. + +Users will get to advanced search with a button to the right of search bar. When selected type-ahead key thing opens, left dropdown of search bar goes away, and x is given to get back to regular search (this is in the mockups) + +It is okay to only make this typing representation available initially (i.e. they start doing stuff with the type-ahead and the phases, no more typing in to make a query that way). + +when you click through or type in the search bar for the various phases of crafting the query ("not", "related resource project", "related resource key name", "value foo") which might be represented in the top bar as a series of tags that can be added and removed before submitting the tag. + +We will try to form options data from a static file. Because options data is static, we may be able to generate and store as a static file of some sort (that we can use for managing smart search). Alan had ideas around this. If we do this it will mean we don't have to make a ton of requests as we craft smart search filters. It sounds like tower cli may start using something similar. + +## Smart search flow + +Smart search will be able to craft the tag through various states. Note that the phases don't necessarily need to be completed in sequential order. + + PHASE 1: prefix operators + +**TODO: Double check there's no reason we need to include or__ and chain__ and can just do not__** + + - not__ + - or__ + - chain__ + + how these work: + + To exclude results matching certain criteria, prefix the field parameter with not__: + + ?not__field=value + By default, all query string filters are AND'ed together, so only the results matching all filters will be returned. To combine results matching any one of multiple criteria, prefix each query string parameter with or__: + + ?or__field=value&or__field=othervalue + ?or__not__field=value&or__field=othervalue + (Added in Ansible Tower 1.4.5) The default AND filtering applies all filters simultaneously to each related object being filtered across database relationships. The chain filter instead applies filters separately for each related object. To use, prefix the query string parameter with chain__: + + ?chain__related__field=value&chain__related__field2=othervalue + ?chain__not__related__field=value&chain__related__field2=othervalue + If the first query above were written as ?related__field=value&related__field2=othervalue, it would return only the primary objects where the same related object satisfied both conditions. As written using the chain filter, it would return the intersection of primary objects matching each condition. + + PHASE 2: related fields, given by array, where __search is appended to them, i.e. + + ``` + "related_search_fields": [ + "credentials__search", + "labels__search", + "created_by__search", + "modified_by__search", + "notification_templates__search", + "custom_inventory_scripts__search", + "notification_templates_error__search", + "notification_templates_success__search", + "notification_templates_any__search", + "teams__search", + "projects__search", + "inventories__search", + "applications__search", + "workflows__search", + "instance_groups__search" + ], + ``` + + PHASE 3: keys, give by object key names for data.actions.GET + - type is given for each key which we could use to help craft the value + + PHASE 4: after key postfix operators can be + +**TODO: will need to figure out which ones we support** + + - exact: Exact match (default lookup if not specified). + - iexact: Case-insensitive version of exact. + - contains: Field contains value. + - icontains: Case-insensitive version of contains. + - startswith: Field starts with value. + - istartswith: Case-insensitive version of startswith. + - endswith: Field ends with value. + - iendswith: Case-insensitive version of endswith. + - regex: Field matches the given regular expression. + - iregex: Case-insensitive version of regex. + - gt: Greater than comparison. + - gte: Greater than or equal to comparison. + - lt: Less than comparison. + - lte: Less than or equal to comparison. + - isnull: Check whether the given field or related object is null; expects a boolean value. + - in: Check whether the given field's value is present in the list provided; expects a list of items. + + PHASE 5: The value. Based on options, we can give hints or validation based on type of value (like number fields don't accept "foo" or whatever) diff --git a/awx/ui_next/docs/APP_ARCHITECTURE.md b/awx/ui_next/docs/APP_ARCHITECTURE.md new file mode 100644 index 000000000000..4be18f17d23e --- /dev/null +++ b/awx/ui_next/docs/APP_ARCHITECTURE.md @@ -0,0 +1,27 @@ +# Application Architecture + +## Local Storage Integration +The `useStorage` hook integrates with the browser's localStorage api. +It accepts a localStorage key as its only argument and returns a state +variable and setter function for that state variable. The hook enables +bidirectional data transfer between tabs via an event listener that +is registered with the Web Storage api. + + +![Sequence Diagram for useStorage](images/useStorage.png) + +The `useStorage` hook currently lives in the `AppContainer` component. It +can be relocated to a more general location should and if the need +ever arise + +## Session Expiration +Session timeout state is communicated to the client in the HTTP(S) +response headers. Every HTTP(S) response is intercepted to read the +session expiration time before being passed into the rest of the +application. A timeout date is computed from the intercepted HTTP(S) +headers and is pushed into local storage, where it can be read using +standard Web Storage apis or other utilities, such as `useStorage`. + + +![Sequence Diagram for session expiration](images/sessionExpiration.png) + diff --git a/awx/ui_next/docs/images/sessionExpiration.png b/awx/ui_next/docs/images/sessionExpiration.png new file mode 100644 index 000000000000..fa740c44a5a6 Binary files /dev/null and b/awx/ui_next/docs/images/sessionExpiration.png differ diff --git a/awx/ui_next/docs/images/useStorage.png b/awx/ui_next/docs/images/useStorage.png new file mode 100644 index 000000000000..712b47712162 Binary files /dev/null and b/awx/ui_next/docs/images/useStorage.png differ diff --git a/awx/ui_next/package-lock.json b/awx/ui_next/package-lock.json new file mode 100644 index 000000000000..a64e834f552b --- /dev/null +++ b/awx/ui_next/package-lock.json @@ -0,0 +1,19174 @@ +{ + "name": "ui_next", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", + "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "dev": true + }, + "@babel/core": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", + "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.10", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", + "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "requires": { + "@babel/types": "^7.12.11", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", + "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", + "requires": { + "@babel/types": "^7.12.10" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz", + "integrity": "sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-react-jsx-experimental": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.11.tgz", + "integrity": "sha512-4oGVOekPI8dh9JphkPXC68iIuP6qp/RPbaPmorRmEFbRAHZjSqxPjqHudn18GVDPgCuFM/KdFXc63C17Ygfa9w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.10", + "@babel/helper-module-imports": "^7.12.5", + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", + "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.12.5", + "@babel/helper-validator-option": "^7.12.1", + "browserslist": "^4.14.5", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", + "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", + "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", + "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-function-name": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", + "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "requires": { + "@babel/helper-get-function-arity": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", + "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "requires": { + "@babel/types": "^7.12.10" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "dev": true, + "requires": { + "@babel/types": "^7.12.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", + "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "dev": true, + "requires": { + "@babel/types": "^7.12.10" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", + "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", + "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.12.7", + "@babel/helper-optimise-call-expression": "^7.12.10", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-simple-access": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", + "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "requires": { + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" + }, + "@babel/helper-validator-option": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", + "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", + "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", + "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", + "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", + "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", + "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", + "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", + "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", + "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", + "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", + "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", + "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", + "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", + "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.1.tgz", + "integrity": "sha512-ir9YW5daRrTYiy9UJ2TzdNIJEZu8KclVzDcfSt4iEmOtwQ4llPtWInNKJyKnVXp1vE4bbVd5S31M/im3mYMO1w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz", + "integrity": "sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.1.tgz", + "integrity": "sha512-UZNEcCY+4Dp9yYRCAHrHDU+9ZXLYaY9MgBXSRLkB9WjYFRR6quJBumfVrEkUxrePPBwFcpWfNKXqVRQQtm7mMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", + "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", + "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", + "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.11.tgz", + "integrity": "sha512-atR1Rxc3hM+VPg/NvNvfYw0npQEAcHuJ+MGZnFn6h3bo+1U3BWXMdFMlvVRApBTWKQMX7SOwRJZA5FBF/JQbvA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", + "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", + "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", + "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", + "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", + "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", + "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", + "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", + "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", + "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", + "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", + "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", + "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.12.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", + "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-identifier": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", + "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", + "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", + "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", + "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", + "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", + "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.12.1.tgz", + "integrity": "sha512-KOHd0tIRLoER+J+8f9DblZDa1fLGPwaaN1DI1TVHuQFOpjHV22C3CUB3obeC4fexHY9nx+fH0hQNvLFFfA1mxA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", + "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.11.tgz", + "integrity": "sha512-5nWOw6mTylaFU72BdZfa0dP1HsGdY3IMExpxn8LBE8dNmkQjB+W+sR+JwIdtbzkPvVuFviT3zyNbSUkuVTVxbw==", + "dev": true, + "requires": { + "@babel/helper-builder-react-jsx": "^7.10.4", + "@babel/helper-builder-react-jsx-experimental": "^7.12.11", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.11.tgz", + "integrity": "sha512-5MvsGschXeXJsbzQGR/BH89ATMzCsM7rx95n+R7/852cGoK2JgMbacDw/A9Pmrfex4tArdMab0L5SBV4SB/Nxg==", + "dev": true, + "requires": { + "@babel/helper-builder-react-jsx-experimental": "^7.12.11", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz", + "integrity": "sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz", + "integrity": "sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", + "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", + "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", + "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", + "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", + "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", + "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", + "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz", + "integrity": "sha512-VrsBByqAIntM+EYMqSm59SiMEf7qkmI9dqMt6RbD/wlwueWmYcI0FFK5Fj47pP6DRZm+3teXjosKlwcZJ5lIMw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-typescript": "^7.12.1" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", + "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", + "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/polyfill": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", + "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", + "dev": true, + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + } + } + }, + "@babel/preset-env": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", + "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.12.7", + "@babel/helper-compilation-targets": "^7.12.5", + "@babel/helper-module-imports": "^7.12.5", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.11", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.11", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.7", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.10", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.11", + "core-js-compat": "^3.8.0", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.10.tgz", + "integrity": "sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.10", + "@babel/plugin-transform-react-jsx-development": "^7.12.7", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + } + }, + "@babel/preset-typescript": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.9.0" + } + }, + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "requires": { + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + } + } + }, + "@babel/runtime-corejs3": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz", + "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "@babel/traverse": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz", + "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.10", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.10", + "@babel/types": "^7.12.10", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@babel/types": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", + "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", + "dev": true + }, + "@csstools/normalize.css": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", + "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==", + "dev": true + }, + "@cypress/instrument-cra": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@cypress/instrument-cra/-/instrument-cra-1.4.0.tgz", + "integrity": "sha512-gXf540xL0jcUXkWyrA2Ug9rzs+jRkc9EPhnRi8XfbnRjdF4lvnn108N6x0lgTApMTbbpCDbVuskHGXDmIuD3CQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "6.0.0", + "debug": "4.2.0", + "find-yarn-workspace-root": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", + "dev": true + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", + "dev": true + }, + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==", + "dev": true + }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "dev": true, + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "dev": true, + "requires": { + "@hapi/hoek": "^8.3.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@lingui/babel-plugin-extract-messages": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-2.9.2.tgz", + "integrity": "sha512-nkRufTupyWjRpzX5ZXB1qMKWT9B+gAuMXYD4blZ/HHCJlEOXeds9W5bugVd3N8Ts5m4o9iRoqeaCuVcH7sJ8Wg==", + "dev": true, + "requires": { + "@lingui/conf": "2.9.2", + "babel-generator": "^6.26.1" + } + }, + "@lingui/babel-plugin-transform-js": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-transform-js/-/babel-plugin-transform-js-2.9.2.tgz", + "integrity": "sha512-yWoyhOfjRa9744TbVb/WN1OWxZYFLuXcWH5aVCu/sZ2b1YpsGCtfhplc5lRVWN8QcsfpjYmFiPqzU6swE5OFdQ==", + "dev": true + }, + "@lingui/babel-plugin-transform-react": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-transform-react/-/babel-plugin-transform-react-2.9.2.tgz", + "integrity": "sha512-bxvrepiS6J9vZqRtpRiAgBIASQscjvu7aFmPqH4Y6001TDXrYuyhhNRt1BI3k2E6C2SckHh5vRtSpsqpjEiY3A==", + "dev": true + }, + "@lingui/cli": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-2.9.2.tgz", + "integrity": "sha512-j46vUe8hSgvsm3j2V4sPLxOdd2HacacGC5E+bWx4wHEhd/yxV4nwPfWpuC7wLoBwM/y2bcF8Q2V7ahEznKSO6A==", + "dev": true, + "requires": { + "@lingui/babel-plugin-extract-messages": "2.9.2", + "@lingui/babel-plugin-transform-js": "2.9.2", + "@lingui/babel-plugin-transform-react": "2.9.2", + "@lingui/conf": "2.9.2", + "babel-generator": "^6.26.1", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "bcp-47": "^1.0.5", + "chalk": "^2.3.0", + "cli-table": "^0.3.1", + "commander": "^2.20.0", + "date-fns": "^1.29.0", + "fuzzaldrin": "^2.1.0", + "glob": "^7.1.4", + "inquirer": "^6.3.1", + "make-plural": "^4.1.1", + "messageformat-parser": "^2.0.0", + "mkdirp": "^0.5.1", + "ora": "^3.4.0", + "pofile": "^1.0.11", + "pseudolocale": "^1.1.0", + "ramda": "^0.26.1" + } + }, + "@lingui/conf": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-2.9.2.tgz", + "integrity": "sha512-xHfH+zLhM7PaMawqeK1G+Pq+reVPYR8eU7XixH4VRHWK8n/itTb4fRl24xc5IUgeXJx+NX1qCzBYVz0i13xlVg==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "cosmiconfig": "^5.2.1", + "jest-regex-util": "^24.3.0", + "jest-validate": "^24.8.0", + "pkg-conf": "^3.1.0" + } + }, + "@lingui/core": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/core/-/core-2.9.2.tgz", + "integrity": "sha512-prrEGlhbvqbyvHMfgKXaaGDM4cGCofca1lOfIOEEX1rZreRjG7Y+cga0oEEQJ9xS59uMht9GGFOwQJsGHYIU0g==", + "requires": { + "babel-runtime": "^6.26.0", + "make-plural": "^4.1.1", + "messageformat-parser": "^2.0.0" + } + }, + "@lingui/macro": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-2.9.2.tgz", + "integrity": "sha512-IFv9h3LL/vjMz98JiDpckIsAlIcnCNuCD4+/C8KK33qGsU9MbCF+zjIztdEWlm3JlnFNm1/qIw7CkrtdoH0RpA==", + "dev": true, + "requires": { + "@lingui/babel-plugin-transform-react": "2.9.2" + } + }, + "@lingui/react": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@lingui/react/-/react-2.9.2.tgz", + "integrity": "sha512-grlarLgJt6vu9wkvGetLunbrImRlL5bsnc4CdtXCNwm0r+8srI+mow5PimtK+MrtOSjXSqLdt/giMYFBE3MOSw==", + "requires": { + "@lingui/core": "2.9.2", + "babel-runtime": "^6.26.0", + "hash-sum": "^1.0.2", + "hoist-non-react-statics": "3.3.0", + "prop-types": "^15.7.2" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@nteract/mockument": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@nteract/mockument/-/mockument-1.0.4.tgz", + "integrity": "sha1-9/hf2T5Dgo7HQcX0xXMRgu2w7LI=", + "dev": true + }, + "@patternfly/patternfly": { + "version": "4.70.2", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.70.2.tgz", + "integrity": "sha512-XKCHnOjx1JThY3s98AJhsApSsGHPvEdlY7r+b18OecqUnmThVGw3nslzYYrwfCGlJ/xQtV5so29SduH2/uhHzA==" + }, + "@patternfly/react-core": { + "version": "4.84.3", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.84.3.tgz", + "integrity": "sha512-VeCv/r09ay6yIER7Eb8Dp5ZhbDu6SCW9smwgUTNp80kt83wIfKvGvQOKg+/7cev/GC6VzfgPHhiS04Jm/N5loA==", + "requires": { + "@patternfly/react-icons": "^4.7.22", + "@patternfly/react-styles": "^4.7.22", + "@patternfly/react-tokens": "^4.9.22", + "focus-trap": "6.2.2", + "react-dropzone": "9.0.0", + "tippy.js": "5.1.2", + "tslib": "1.13.0" + } + }, + "@patternfly/react-icons": { + "version": "4.7.22", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.7.22.tgz", + "integrity": "sha512-JDsnebr9CNIyrv9yjaGFQ56OChbV6KcxMYBIpNc8/sZdU4TXHWNC7P7rlUM/BuGpbWvyaOJtscRuf5uteIKX3A==" + }, + "@patternfly/react-styles": { + "version": "4.7.22", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.7.22.tgz", + "integrity": "sha512-ojNuSNJx6CkNtsSFseZ2SJEVyzPMFYh0jOs204ICzYM1+fn9acsIi3Co0bcskFRzw8F6e2/x+8uVNx6QI8elxg==" + }, + "@patternfly/react-table": { + "version": "4.19.45", + "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.19.45.tgz", + "integrity": "sha512-HFOefgyZ8SGbLflGlEqefHrdxrV+X+x7+bBRvsB+zFZAYWDVau3Z6Pkv8gY5JselBsMywZYPb5juHBoBkzuezg==", + "requires": { + "@patternfly/patternfly": "4.70.2", + "@patternfly/react-core": "^4.84.4", + "@patternfly/react-icons": "^4.7.22", + "@patternfly/react-styles": "^4.7.22", + "@patternfly/react-tokens": "^4.9.22", + "lodash": "^4.17.19", + "tslib": "1.13.0" + }, + "dependencies": { + "@patternfly/react-core": { + "version": "4.84.4", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.84.4.tgz", + "integrity": "sha512-GIv6zJl+NGYIrSm2pATQFggRt4ZFYUKVNbLSsna2x8+eYeZscqIUFSPmBM+eNpQkGaoJk254Lu09pgm4hM/b4g==", + "requires": { + "@patternfly/react-icons": "^4.7.22", + "@patternfly/react-styles": "^4.7.22", + "@patternfly/react-tokens": "^4.9.22", + "focus-trap": "6.2.2", + "react-dropzone": "9.0.0", + "tippy.js": "5.1.2", + "tslib": "1.13.0" + } + } + } + }, + "@patternfly/react-tokens": { + "version": "4.9.22", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.9.22.tgz", + "integrity": "sha512-hN/8u7mFR62naFB2hdO7nl1p/0lCXtNq+VY+BAbp4UFC2/QyjNP0IOPBR+mR9Pbj5JwxrURI7G5blLp+k9RLvQ==" + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", + "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==", + "dev": true + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", + "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==", + "dev": true + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz", + "integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w==", + "dev": true + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", + "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==", + "dev": true + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", + "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==", + "dev": true + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", + "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==", + "dev": true + }, + "@svgr/babel-preset": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz", + "integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==", + "dev": true, + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.3", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + } + }, + "@svgr/core": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz", + "integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==", + "dev": true, + "requires": { + "@svgr/plugin-jsx": "^4.3.3", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@svgr/plugin-jsx": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz", + "integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.3", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + } + }, + "@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "dev": true, + "requires": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz", + "integrity": "sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.4.5", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.3.3", + "@svgr/plugin-jsx": "^4.3.3", + "@svgr/plugin-svgo": "^4.3.1", + "loader-utils": "^1.2.3" + } + }, + "@types/babel__core": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", + "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/cheerio": { + "version": "0.22.23", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.23.tgz", + "integrity": "sha512-QfHLujVMlGqcS/ePSf3Oe5hK3H8wi/yN2JYuxSB1U10VvW1fO3K8C+mURQesFYS1Hn7lspOsTT75SKq/XtydQg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.4.tgz", + "integrity": "sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "14.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", + "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz", + "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "airbnb-prop-types": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz", + "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", + "dev": true, + "requires": { + "array.prototype.find": "^2.1.1", + "function.prototype.name": "^1.1.2", + "is-regex": "^1.1.0", + "object-is": "^1.1.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2", + "prop-types": "^15.7.2", + "prop-types-exact": "^1.2.0", + "react-is": "^16.13.1" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-to-html": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.14.tgz", + "integrity": "sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA==", + "requires": { + "entities": "^1.1.2" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true + }, + "array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-includes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", + "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "get-intrinsic": "^1.0.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.find": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.1.tgz", + "integrity": "sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.4" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "attr-accept": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz", + "integrity": "sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==", + "requires": { + "core-js": "^2.5.0" + } + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "axe-core": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz", + "integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==", + "dev": true + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + }, + "dependencies": { + "follow-redirects": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", + "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" + } + } + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "dev": true, + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + } + } + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "parse-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", + "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==", + "dev": true + }, + "babel-plugin-styled-components": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz", + "integrity": "sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-module-imports": "^7.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11" + } + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", + "dev": true + }, + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "babel-preset-react-app": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", + "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", + "dev": true, + "requires": { + "@babel/core": "7.9.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-proposal-optional-chaining": "7.9.0", + "@babel/plugin-transform-flow-strip-types": "7.9.0", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.0", + "@babel/preset-env": "7.9.0", + "@babel/preset-react": "7.9.1", + "@babel/preset-typescript": "7.9.0", + "@babel/runtime": "7.9.0", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", + "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-react": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz", + "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.9.1", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" + } + }, + "@babel/runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz", + "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcp-47": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-1.0.8.tgz", + "integrity": "sha512-Y9y1QNBBtYtv7hcmoX0tR+tUNSFZGZ6OL6vKPObq8BbOhkCoyayF6ogfLTgAli/KuAEbsYHYUNq2AQuY6IuLag==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", + "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001165", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.621", + "escalade": "^3.1.1", + "node-releases": "^1.1.67" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "requires": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001168", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", + "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cheerio": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.1", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz", + "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==", + "dev": true + }, + "cli-table": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.4.tgz", + "integrity": "sha512-1vinpnX/ZERcmE443i3SZTmU5DF0rPO9DrL4I2iVAllhxzCM9SzPlHnz19fsZB78htkKZvYBvj6SZ6vXnaxmTA==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "string-width": "^4.2.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", + "dev": true, + "requires": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + } + }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "codemirror": { + "version": "5.58.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.58.3.tgz", + "integrity": "sha512-KBhB+juiyOOgn0AqtRmWyAT3yoElkuvWTI6hsHa9E6GQrl6bk/fdAYcvuqW1/upO9T9rtEtapWdw4XYcNiVDEA==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz", + "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "dev": true, + "requires": { + "arity-n": "^1.0.4" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "core-js-compat": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz", + "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==", + "dev": true, + "requires": { + "browserslist": "^4.15.0", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.1.tgz", + "integrity": "sha512-Se+LaxqXlVXGvmexKGPvnUIYC1jwXu1H6Pkyb3uBM5d8/NELMYCHs/4/roD7721NxrTLyv7e5nXd5/QLBO+10g==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "css-loader": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", + "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.23", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + } + } + }, + "css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-to-react-native": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz", + "integrity": "sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^3.3.0" + } + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "d3": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-axis": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", + "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" + }, + "d3-brush": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", + "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "d3-chord": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", + "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", + "requires": { + "d3-array": "1", + "d3-path": "1" + } + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "requires": { + "d3-array": "^1.1.1" + } + }, + "d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "requires": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "d3-dsv": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" + }, + "d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "requires": { + "d3-dsv": "1" + } + }, + "d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "requires": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" + }, + "d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-polygon": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", + "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" + }, + "d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==" + }, + "d3-random": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", + "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==" + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "requires": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "requires": { + "d3-time": "1" + } + }, + "d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, + "d3-transition": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", + "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", + "requires": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + }, + "d3-zoom": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", + "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "dagre": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", + "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "requires": { + "graphlib": "^2.1.8", + "lodash": "^4.17.15" + } + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", + "dev": true + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.628", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.628.tgz", + "integrity": "sha512-fmhO4YGo/kapy+xL9Eq/cZwDASaTHZu3psIFYo4yc+RY1LzbZr84xjKlDImDrlrmWhOxsrDi98nX097U/xK/cQ==", + "dev": true + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "enzyme": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", + "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", + "dev": true, + "requires": { + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", + "has": "^1.0.3", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", + "is-subset": "^0.1.1", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.2.1" + } + }, + "enzyme-adapter-react-16": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.5.tgz", + "integrity": "sha512-33yUJGT1nHFQlbVI5qdo5Pfqvu/h4qPwi1o0a6ZZsjpiqq92a3HjynDhwd1IeED+Su60HDWV8mxJqkTnLYdGkw==", + "dev": true, + "requires": { + "enzyme-adapter-utils": "^1.13.1", + "enzyme-shallow-equal": "^1.0.4", + "has": "^1.0.3", + "object.assign": "^4.1.0", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "react-is": "^16.13.1", + "react-test-renderer": "^16.0.0-0", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "enzyme-adapter-utils": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.14.0.tgz", + "integrity": "sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg==", + "dev": true, + "requires": { + "airbnb-prop-types": "^2.16.0", + "function.prototype.name": "^1.1.3", + "has": "^1.0.3", + "object.assign": "^4.1.2", + "object.fromentries": "^2.0.3", + "prop-types": "^15.7.2", + "semver": "^5.7.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "enzyme-shallow-equal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz", + "integrity": "sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==", + "dev": true, + "requires": { + "has": "^1.0.3", + "object-is": "^1.1.2" + } + }, + "enzyme-to-json": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.6.1.tgz", + "integrity": "sha512-15tXuONeq5ORoZjV/bUo2gbtZrN2IH+Z6DvL35QmZyKHgbY1ahn6wcnLd9Xv9OjiwbAXiiP8MRZwbZrCv1wYNg==", + "dev": true, + "requires": { + "@types/cheerio": "^0.22.22", + "lodash": "^4.17.15", + "react-is": "^16.12.0" + } + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "eslint-config-airbnb": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.1.tgz", + "integrity": "sha512-xCu//8a/aWqagKljt+1/qAM62BYZeNq04HmdevG5yUGWpja0I/xhqd6GdLRch5oetEGFiJAnvtGuTEAese53Qg==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^13.2.0", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-config-airbnb-base": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz", + "integrity": "sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.5", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-config-prettier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-5.1.0.tgz", + "integrity": "sha512-+tpiaLm3wl6fPW5nq0dDyVowQM0FT61lAdWZ+sDWgk6kKzgbOnCDwlcbwI38cyCBhq+Z3ret5Iofp6/gZpO0zw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-config-react-app": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", + "integrity": "sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-import-resolver-webpack": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.11.1.tgz", + "integrity": "sha512-eK3zR7xVQR/MaoBWwGuD+CULYVuqe5QFlDukman71aI6IboCGzggDUohHNfu1ZeBnbHcUHJc0ywWoXUBNB6qdg==", + "dev": true, + "requires": { + "array-find": "^1.0.0", + "debug": "^2.6.8", + "enhanced-resolve": "~0.9.0", + "find-root": "^1.1.0", + "has": "^1.0.1", + "interpret": "^1.0.0", + "lodash": "^4.17.4", + "node-libs-browser": "^1.0.0 || ^2.0.0", + "resolve": "^1.10.0", + "semver": "^5.3.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "eslint-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-3.0.3.tgz", + "integrity": "sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw==", + "dev": true, + "requires": { + "fs-extra": "^8.1.0", + "loader-fs-cache": "^1.0.2", + "loader-utils": "^1.2.3", + "object-hash": "^2.0.1", + "schema-utils": "^2.6.1" + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", + "integrity": "sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", + "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==", + "dev": true + } + } + }, + "eslint-plugin-react": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", + "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.1.tgz", + "integrity": "sha512-Y2c4b55R+6ZzwtTppKwSmK/Kar8AdLiC2f9NADCuxbcTgPPg41Gyqa6b9GppgXSvCtkRw43ZE86CT5sejKC6/g==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", + "integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + } + }, + "file-selector": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.19.tgz", + "integrity": "sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==", + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "filesize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", + "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "requires": { + "micromatch": "^4.0.2" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flatten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "focus-trap": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.2.2.tgz", + "integrity": "sha512-qWovH9+LGoKqREvJaTCzJyO0hphQYGz+ap5Hc4NqXHNhZBdxCi5uBPPcaOUw66fHmzXLVwvETLvFgpwPILqKpg==", + "requires": { + "tabbable": "^5.1.4" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^3.3.0", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formik": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.6.tgz", + "integrity": "sha512-Kxk2zQRafy56zhLmrzcbryUpMBvT0tal5IvcifK5+4YNGelKsnrODFJ0sZQRMQboblWNym4lAW3bt+tf2vApSA==", + "requires": { + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.14", + "lodash-es": "^4.17.14", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.3.tgz", + "integrity": "sha512-H51qkbNSp8mtkJt+nyW1gyStBiKZxfRqySNUR99ylq6BPXHKI4SEvIlTKp4odLfjRKJV04DFWMU3G/YRlQOsag==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "functions-have-names": "^1.2.1" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "functions-have-names": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", + "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", + "dev": true + }, + "fuzzaldrin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", + "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "requires": { + "lodash": "^4.17.15" + } + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "harmony-reflect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz", + "integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-3.0.0.tgz", + "integrity": "sha1-Ngd+8dFfMzSEqn+neihgbxxlWzc=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=" + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-element-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.2.0.tgz", + "integrity": "sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw==", + "dev": true, + "requires": { + "array-filter": "^1.0.0" + } + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-entities": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.3.tgz", + "integrity": "sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "4.0.0-beta.11", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", + "integrity": "sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg==", + "dev": true, + "requires": { + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "dependencies": { + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.0.6.tgz", + "integrity": "sha512-NyL6ZB6cVni7pl+/IT2W0ni5ME00xR0sN27AQZZrpKn1b+qRh+mLbBxIq9Cq1oGfmTc7BUq4HB77mxwCaxAYNg==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.4", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.20", + "micromatch": "^4.0.2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "dev": true, + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "internal-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", + "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "has": "^1.0.3", + "side-channel": "^1.0.2" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-what": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.12.0.tgz", + "integrity": "sha512-2ilQz5/f/o9V7WRWJQmpFYNmQFZ9iM+OXRonZKcYgTkCzjb949Vi4h282PD1UfmgHk666rcWonbRJ++KI41VGw==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" + }, + "dependencies": { + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-jsdom-fourteen": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz", + "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==", + "dev": true, + "requires": { + "@jest/environment": "^24.3.0", + "@jest/fake-timers": "^24.3.0", + "@jest/types": "^24.3.0", + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0", + "jsdom": "^14.1.0" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "jsdom": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", + "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", + "array-equal": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.3", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.5.0", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } + }, + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } + }, + "jest-watch-typeahead": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz", + "integrity": "sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.1", + "jest-regex-util": "^24.9.0", + "jest-watcher": "^24.3.0", + "slash": "^3.0.0", + "string-length": "^3.1.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "string-length": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", + "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + } + }, + "jest-websocket-mock": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.2.0.tgz", + "integrity": "sha512-lc3wwXOEyNa4ZpcgJtUG3mmKMAq5FAsKYiZph0p/+PAJrAPuX4JCIfJMdJ/urRsLBG51fwm/wlVPNbR6s2nzNw==", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dev": true, + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "loader-fs-cache": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", + "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash-es": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", + "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "luxon": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.25.0.tgz", + "integrity": "sha512-hEgLurSH8kQRjY6i4YLey+mcKVAWXbDNlZRmM6AgWDJ1cY3atl8Ztf5wEY7VBReFbmGnwQPz7KYJblL8B2k0jQ==", + "optional": true + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "make-plural": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", + "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==", + "requires": { + "minimist": "^1.2.0" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, + "memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, + "merge-anything": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-2.4.4.tgz", + "integrity": "sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ==", + "requires": { + "is-what": "^3.3.1" + } + }, + "merge-deep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", + "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "messageformat-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-2.0.0.tgz", + "integrity": "sha512-C2ZjB5GlLeikkeoMCTcwEeb68LrFl9osxQzXHIPh0Wcj+43wNsoKpRRKq9rm204sAIdknrdcoeQMUnzvDuMf6g==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "mime": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", + "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, + "mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mock-socket": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.0.3.tgz", + "integrity": "sha512-SxIiD2yE/By79p3cNAAXyLQWTvEFNEzcAO7PH+DzRqKSFaplAPFjiQLmw8ofmpCsZf+Rhfn2/xCJagpdGmYdTw==", + "dev": true, + "requires": { + "url-parse": "^1.4.4" + } + }, + "moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", + "dev": true + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.67", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", + "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==", + "dev": true + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object-is": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", + "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", + "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", + "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "open": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz", + "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "dependencies": { + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + } + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", + "dev": true, + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", + "dev": true, + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "pofile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.0.tgz", + "integrity": "sha512-6XYcNkXWGiJ2CVXogTP7uJ6ZXQCldYLZc16wgRp8tqRaBTTyIfF+TUT3EQJPXTLAT7OTPpTAoaFdoXKfaTRU1w==", + "dev": true + }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + } + }, + "postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "dev": true, + "requires": { + "postcss": "^7" + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + } + } + }, + "postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "dev": true, + "requires": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "dev": true, + "requires": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "dev": true, + "requires": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", + "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-font-variant": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", + "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-initial": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz", + "integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==", + "dev": true, + "requires": { + "lodash.template": "^4.5.0", + "postcss": "^7.0.2" + } + }, + "postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + } + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-nesting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-normalize": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz", + "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", + "dev": true, + "requires": { + "@csstools/normalize.css": "^10.1.0", + "browserslist": "^4.6.2", + "postcss": "^7.0.17", + "postcss-browser-comments": "^3.0.0", + "sanitize.css": "^10.0.0" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-preset-env": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", + "dev": true, + "requires": { + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.3", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-safe-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-not": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz", + "integrity": "sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "dev": true, + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "pretty-bytes": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz", + "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==", + "dev": true + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "prop-types-exact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz", + "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", + "dev": true, + "requires": { + "has": "^1.0.3", + "object.assign": "^4.1.0", + "reflect.ownkeys": "^0.2.0" + } + }, + "prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "requires": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudolocale": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.2.0.tgz", + "integrity": "sha512-k0OQFvIlvpRdzR0dPVrrbWX7eE9EaZ6gpZtTlFSDi1Gf9tMy9wiANCNu7JZ0drcKgUri/39a2mBbH0goiQmrmQ==", + "dev": true, + "requires": { + "commander": "*" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "requires": { + "performance-now": "^2.1.0" + } + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", + "dev": true + }, + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", + "dev": true + }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "requires": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-app-polyfill": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", + "integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==", + "dev": true, + "requires": { + "core-js": "^3.5.0", + "object-assign": "^4.1.1", + "promise": "^8.0.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.3", + "whatwg-fetch": "^3.0.0" + }, + "dependencies": { + "core-js": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz", + "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + } + } + }, + "react-codemirror2": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-6.0.1.tgz", + "integrity": "sha512-rutEKVgvFhWcy/GeVA1hFbqrO89qLqgqdhUr7YhYgIzdyICdlRQv+ztuNvOFQMXrO0fLt0VkaYOdMdYdQgsSUA==" + }, + "react-dev-utils": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", + "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", + "dev": true, + "requires": { + "@babel/code-frame": "7.8.3", + "address": "1.1.2", + "browserslist": "4.10.0", + "chalk": "2.4.2", + "cross-spawn": "7.0.1", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.0.1", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "3.1.1", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "7.0.4", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "react-error-overlay": "^6.0.7", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "browserslist": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", + "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001035", + "electron-to-chromium": "^1.3.378", + "node-releases": "^1.1.52", + "pkg-up": "^3.1.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-dropzone": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-9.0.0.tgz", + "integrity": "sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==", + "requires": { + "attr-accept": "^1.1.3", + "file-selector": "^0.1.8", + "prop-types": "^15.6.2", + "prop-types-extra": "^1.1.0" + } + }, + "react-error-overlay": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz", + "integrity": "sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==", + "dev": true + }, + "react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-scripts": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.4.tgz", + "integrity": "sha512-7J7GZyF/QvZkKAZLneiOIhHozvOMHey7hO9cdO9u68jjhGZlI8hDdOm6UyuHofn6Ajc9Uji5I6Psm/nKNuWdyw==", + "dev": true, + "requires": { + "@babel/core": "7.9.0", + "@svgr/webpack": "4.3.3", + "@typescript-eslint/eslint-plugin": "^2.10.0", + "@typescript-eslint/parser": "^2.10.0", + "babel-eslint": "10.1.0", + "babel-jest": "^24.9.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.6", + "babel-preset-react-app": "^9.1.2", + "camelcase": "^5.3.1", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "3.4.2", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^6.6.0", + "eslint-config-react-app": "^5.2.1", + "eslint-loader": "3.0.3", + "eslint-plugin-flowtype": "4.6.0", + "eslint-plugin-import": "2.20.1", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.19.0", + "eslint-plugin-react-hooks": "^1.6.1", + "file-loader": "4.3.0", + "fs-extra": "^8.1.0", + "fsevents": "2.1.2", + "html-webpack-plugin": "4.0.0-beta.11", + "identity-obj-proxy": "3.0.0", + "jest": "24.9.0", + "jest-environment-jsdom-fourteen": "1.0.1", + "jest-resolve": "24.9.0", + "jest-watch-typeahead": "0.4.2", + "mini-css-extract-plugin": "0.9.0", + "optimize-css-assets-webpack-plugin": "5.0.3", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "4.0.1", + "react-app-polyfill": "^1.0.6", + "react-dev-utils": "^10.2.1", + "resolve": "1.15.0", + "resolve-url-loader": "3.1.2", + "sass-loader": "8.0.2", + "semver": "6.3.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "2.3.8", + "ts-pnp": "1.1.6", + "url-loader": "2.3.0", + "webpack": "4.42.0", + "webpack-dev-server": "3.11.0", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "4.3.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "eslint-plugin-import": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", + "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", + "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.5", + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.1" + } + }, + "eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", + "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "jsx-ast-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", + "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "react-test-renderer": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.14.0.tgz", + "integrity": "sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "react-is": "^16.8.6", + "scheduler": "^0.19.1" + } + }, + "react-virtualized": { + "version": "9.22.2", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.2.tgz", + "integrity": "sha512-5j4h4FhxTdOpBKtePSs1yk6LDNT4oGtUwjT7Nkh61Z8vv3fTG/XeOf8J4li1AYaexOwTXnw0HFVxsV0GBUqwRw==", + "requires": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "reflect.ownkeys": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", + "integrity": "sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=", + "dev": true + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.4.tgz", + "integrity": "sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "resolve-url-loader": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz", + "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.21", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "dev": true, + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", + "dev": true + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rrule": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.6.tgz", + "integrity": "sha512-h6tb/hRo9SNv8xKjcvsEfdmhXvElMXsU3Yz0KmqMehUqxP6a4Qjmth2EuL1FsjdawADjajLS0eBbWfsZzn3SIw==", + "requires": { + "luxon": "^1.21.3", + "tslib": "^1.10.0" + } + }, + "rst-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", + "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", + "dev": true, + "requires": { + "lodash.flattendeep": "^4.4.0", + "nearley": "^2.7.10" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "sanitize.css": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", + "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==", + "dev": true + }, + "sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "dependencies": { + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "dev": true, + "requires": { + "xmlchars": "^2.1.1" + } + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "^1.0.2" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "side-channel": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", + "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", + "dev": true, + "requires": { + "es-abstract": "^1.18.0-next.0", + "object-inspect": "^1.8.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "sockjs": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz", + "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.4.0", + "websocket-driver": "0.6.5" + } + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stack-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.4.tgz", + "integrity": "sha512-IPDJfugEGbfizBwBZRZ3xpccMdRyP5lqsBWXGQWimVjua/ccLCeMOAVjlc1R7LxFjo5sEDhyNIXd8mo/AiDS9w==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.matchall": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", + "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3" + } + }, + "string.prototype.trim": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.3.tgz", + "integrity": "sha512-16IL9pIBA5asNOSukPfxX2W68BaBvxyiRK16H3RA/lWW9BDosh+w7f+LhomPHpXJ82QEe7w7/rY/S1CV97raLg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "dev": true, + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "styled-components": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-4.4.1.tgz", + "integrity": "sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@emotion/is-prop-valid": "^0.8.1", + "@emotion/unitless": "^0.7.0", + "babel-plugin-styled-components": ">= 1", + "css-to-react-native": "^2.2.2", + "memoize-one": "^5.0.0", + "merge-anything": "^2.2.4", + "prop-types": "^15.5.4", + "react-is": "^16.6.0", + "stylis": "^3.5.0", + "stylis-rule-sheet": "^0.0.10", + "supports-color": "^5.5.0" + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" + }, + "stylis-rule-sheet": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", + "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + } + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "tabbable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.1.5.tgz", + "integrity": "sha512-oVAPrWgLLqrbvQE8XqcU7CVBq6SQbaIbHkhOca3u7/jzuQvyZycrUKPCGr04qpEIUslmUlULbSeN+m3QrKEykA==" + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "dev": true, + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tippy.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-5.1.2.tgz", + "integrity": "sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==", + "requires": { + "popper.js": "^1.16.0" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-pnp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", + "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==", + "dev": true + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz", + "integrity": "sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.5.0" + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "optional": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "optional": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", + "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.20", + "sockjs-client": "1.4.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-manifest-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", + "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", + "dev": true, + "requires": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "object.entries": "^1.1.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "websocket-driver": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "dev": true, + "requires": { + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz", + "integrity": "sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A==", + "dev": true + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workbox-background-sync": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", + "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-broadcast-update": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", + "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-build": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-4.3.1.tgz", + "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.4", + "@hapi/joi": "^15.0.0", + "common-tags": "^1.8.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.3", + "lodash.template": "^4.4.0", + "pretty-bytes": "^5.1.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^4.3.1", + "workbox-broadcast-update": "^4.3.1", + "workbox-cacheable-response": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-expiration": "^4.3.1", + "workbox-google-analytics": "^4.3.1", + "workbox-navigation-preload": "^4.3.1", + "workbox-precaching": "^4.3.1", + "workbox-range-requests": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1", + "workbox-streams": "^4.3.1", + "workbox-sw": "^4.3.1", + "workbox-window": "^4.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "workbox-cacheable-response": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", + "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-4.3.1.tgz", + "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==", + "dev": true + }, + "workbox-expiration": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-4.3.1.tgz", + "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-google-analytics": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", + "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", + "dev": true, + "requires": { + "workbox-background-sync": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1" + } + }, + "workbox-navigation-preload": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", + "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-precaching": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-4.3.1.tgz", + "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-range-requests": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", + "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-routing": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-4.3.1.tgz", + "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-strategies": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-4.3.1.tgz", + "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-streams": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-4.3.1.tgz", + "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-sw": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-4.3.1.tgz", + "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==", + "dev": true + }, + "workbox-webpack-plugin": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^4.3.1" + } + }, + "workbox-window": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-4.3.1.tgz", + "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "dev": true, + "requires": { + "microevent.ts": "~0.1.1" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xregexp": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", + "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/awx/ui_next/package.json b/awx/ui_next/package.json new file mode 100644 index 000000000000..b052a3183f40 --- /dev/null +++ b/awx/ui_next/package.json @@ -0,0 +1,95 @@ +{ + "name": "ui_next", + "version": "0.1.0", + "private": true, + "engines": { + "node": "14.x" + }, + "dependencies": { + "@lingui/react": "^2.9.1", + "@patternfly/patternfly": "4.70.2", + "@patternfly/react-core": "4.84.3", + "@patternfly/react-icons": "4.7.22", + "@patternfly/react-table": "^4.19.15", + "ansi-to-html": "^0.6.11", + "axios": "^0.21.1", + "codemirror": "^5.47.0", + "d3": "^5.12.0", + "dagre": "^0.8.4", + "formik": "^2.1.2", + "has-ansi": "^3.0.0", + "html-entities": "^1.2.1", + "js-yaml": "^3.13.1", + "prop-types": "^15.6.2", + "react": "^16.13.1", + "react-codemirror2": "^6.0.0", + "react-dom": "^16.13.1", + "react-router-dom": "^5.1.2", + "react-virtualized": "^9.21.1", + "rrule": "^2.6.4", + "styled-components": "^4.2.0" + }, + "devDependencies": { + "@babel/polyfill": "^7.8.7", + "@cypress/instrument-cra": "^1.4.0", + "@lingui/cli": "^2.9.2", + "@lingui/macro": "^2.9.1", + "@nteract/mockument": "^1.0.4", + "babel-core": "^7.0.0-bridge.0", + "enzyme": "^3.10.0", + "enzyme-adapter-react-16": "^1.14.0", + "enzyme-to-json": "^3.3.5", + "eslint": "^6.8.0", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-prettier": "^5.0.0", + "eslint-import-resolver-webpack": "0.11.1", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react-hooks": "^2.2.0", + "http-proxy-middleware": "^1.0.3", + "jest-websocket-mock": "^2.0.2", + "mock-socket": "^9.0.3", + "prettier": "^1.18.2", + "react-scripts": "^3.4.4" + }, + "scripts": { + "start": "PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", + "start-instrumented": "DEBUG=instrument-cra PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts -r @cypress/instrument-cra start", + "build": "INLINE_RUNTIME_CHUNK=false react-scripts build", + "test": "TZ='UTC' react-scripts test --coverage --watchAll=false", + "test-watch": "TZ='UTC' react-scripts test", + "eject": "react-scripts eject", + "lint": "eslint --ext .js --ext .jsx .", + "add-locale": "lingui add-locale", + "extract-strings": "lingui extract", + "compile-strings": "lingui compile", + "prettier": "prettier --write \"src/**/*.{js,jsx,scss}\"", + "prettier-check": "prettier --check \"src/**/*.{js,jsx,scss}\"" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "jest": { + "snapshotSerializers": [ + "enzyme-to-json/serializer" + ], + "collectCoverageFrom": [ + "src/**/*.{js,jsx}", + "testUtils/**/*.{js,jsx}" + ], + "coveragePathIgnorePatterns": [ + "/src/locales", + "index.js" + ] + } +} diff --git a/awx/ui_next/public/index.html b/awx/ui_next/public/index.html new file mode 100644 index 000000000000..dc5174aa7c31 --- /dev/null +++ b/awx/ui_next/public/index.html @@ -0,0 +1,30 @@ + + + + <% if (process.env.NODE_ENV === 'production') { %> + + + <% } %> + + + + + AWX + + + + <% if (process.env.NODE_ENV === 'production') { %> +
+ <% } else { %> +
+ <% } %> + + diff --git a/awx/ui_next/public/installing.html b/awx/ui_next/public/installing.html new file mode 100644 index 000000000000..6495b7091c5d --- /dev/null +++ b/awx/ui_next/public/installing.html @@ -0,0 +1,25 @@ + + + + + + + + + + +
+ +

AWX is installing.

+

This page will refresh when complete.

+
+
+ + diff --git a/awx/ui_next/public/static/media/awx-logo.pdf b/awx/ui_next/public/static/media/awx-logo.pdf new file mode 100644 index 000000000000..e13670d97092 Binary files /dev/null and b/awx/ui_next/public/static/media/awx-logo.pdf differ diff --git a/awx/ui/client/assets/default.strings.json b/awx/ui_next/public/static/media/default.strings.json similarity index 100% rename from awx/ui/client/assets/default.strings.json rename to awx/ui_next/public/static/media/default.strings.json diff --git a/awx/ui_next/public/static/media/logo-header.svg b/awx/ui_next/public/static/media/logo-header.svg new file mode 100644 index 000000000000..2c2444b24436 --- /dev/null +++ b/awx/ui_next/public/static/media/logo-header.svg @@ -0,0 +1,2860 @@ + + + + + diff --git a/awx/ui_next/public/static/media/logo-header.svg.old b/awx/ui_next/public/static/media/logo-header.svg.old new file mode 100644 index 000000000000..b78bfbd3c90b --- /dev/null +++ b/awx/ui_next/public/static/media/logo-header.svg.old @@ -0,0 +1 @@ +awl-logo-small \ No newline at end of file diff --git a/awx/ui_next/public/static/media/logo-login.svg b/awx/ui_next/public/static/media/logo-login.svg new file mode 100644 index 000000000000..2c2444b24436 --- /dev/null +++ b/awx/ui_next/public/static/media/logo-login.svg @@ -0,0 +1,2860 @@ + + + + + diff --git a/awx/ui_next/public/static/media/logo-login.svg.old b/awx/ui_next/public/static/media/logo-login.svg.old new file mode 100644 index 000000000000..6a010a2b0b34 --- /dev/null +++ b/awx/ui_next/public/static/media/logo-login.svg.old @@ -0,0 +1 @@ +awl-logo-small diff --git a/awx/ui_next/public/static/media/pfbg_2000.jpg b/awx/ui_next/public/static/media/pfbg_2000.jpg new file mode 100644 index 000000000000..0b2ceb367f39 Binary files /dev/null and b/awx/ui_next/public/static/media/pfbg_2000.jpg differ diff --git a/awx/ui_next/public/static/media/pfbg_576.jpg b/awx/ui_next/public/static/media/pfbg_576.jpg new file mode 100644 index 000000000000..a0a7fc3cdb07 Binary files /dev/null and b/awx/ui_next/public/static/media/pfbg_576.jpg differ diff --git a/awx/ui_next/public/static/media/pfbg_576@2x.jpg b/awx/ui_next/public/static/media/pfbg_576@2x.jpg new file mode 100644 index 000000000000..af83172425dc Binary files /dev/null and b/awx/ui_next/public/static/media/pfbg_576@2x.jpg differ diff --git a/awx/ui_next/public/static/media/pfbg_768.jpg b/awx/ui_next/public/static/media/pfbg_768.jpg new file mode 100644 index 000000000000..9a24ec7a21db Binary files /dev/null and b/awx/ui_next/public/static/media/pfbg_768.jpg differ diff --git a/awx/ui_next/public/static/media/pfbg_768@2x.jpg b/awx/ui_next/public/static/media/pfbg_768@2x.jpg new file mode 100644 index 000000000000..a4ca09cb8266 Binary files /dev/null and b/awx/ui_next/public/static/media/pfbg_768@2x.jpg differ diff --git a/awx/ui_next/src/App.jsx b/awx/ui_next/src/App.jsx new file mode 100644 index 000000000000..5833714d893d --- /dev/null +++ b/awx/ui_next/src/App.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { + useRouteMatch, + useLocation, + HashRouter, + Route, + Switch, + Redirect, +} from 'react-router-dom'; +import { I18n, I18nProvider } from '@lingui/react'; + +import AppContainer from './components/AppContainer'; +import Background from './components/Background'; +import NotFound from './screens/NotFound'; +import Login from './screens/Login'; + +import ja from './locales/ja/messages'; +import en from './locales/en/messages'; +import { isAuthenticated } from './util/auth'; +import { getLanguageWithoutRegionCode } from './util/language'; + +import getRouteConfig from './routeConfig'; + +const ProtectedRoute = ({ children, ...rest }) => + isAuthenticated(document.cookie) ? ( + {children} + ) : ( + + ); + +function App() { + const catalogs = { en, ja }; + let language = getLanguageWithoutRegionCode(navigator); + if (!Object.keys(catalogs).includes(language)) { + // If there isn't a string catalog available for the browser's + // preferred language, default to one that has strings. + language = 'en'; + } + const match = useRouteMatch(); + const { hash, search, pathname } = useLocation(); + + return ( + + + {({ i18n }) => ( + + + + + + + + + + + + + + + {getRouteConfig(i18n) + .flatMap(({ routes }) => routes) + .map(({ path, screen: Screen }) => ( + + + + )) + .concat( + + + + )} + + + + + + )} + + + ); +} + +export default () => ( + + + +); diff --git a/awx/ui_next/src/App.test.jsx b/awx/ui_next/src/App.test.jsx new file mode 100644 index 000000000000..a6fe414b3961 --- /dev/null +++ b/awx/ui_next/src/App.test.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '../testUtils/enzymeHelpers'; + +import App from './App'; + +jest.mock('./api'); + +describe('', () => { + test('renders ok', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); + expect(wrapper.length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/api/Base.js b/awx/ui_next/src/api/Base.js new file mode 100644 index 000000000000..cd0a76c1ec09 --- /dev/null +++ b/awx/ui_next/src/api/Base.js @@ -0,0 +1,70 @@ +import axios from 'axios'; + +import { SESSION_TIMEOUT_KEY } from '../constants'; +import { encodeQueryString } from '../util/qs'; +import debounce from '../util/debounce'; + +const updateStorage = debounce((key, val) => { + window.localStorage.setItem(key, val); + window.dispatchEvent(new Event('storage')); +}, 500); + +const defaultHttp = axios.create({ + xsrfCookieName: 'csrftoken', + xsrfHeaderName: 'X-CSRFToken', + paramsSerializer(params) { + return encodeQueryString(params); + }, +}); + +defaultHttp.interceptors.response.use(response => { + const timeout = response?.headers['session-timeout']; + if (timeout) { + const timeoutDate = new Date().getTime() + timeout * 1000; + updateStorage(SESSION_TIMEOUT_KEY, String(timeoutDate)); + } + return response; +}); + +class Base { + constructor(http = defaultHttp, baseURL) { + this.http = http; + this.baseUrl = baseURL; + } + + create(data) { + return this.http.post(this.baseUrl, data); + } + + destroy(id) { + return this.http.delete(`${this.baseUrl}${id}/`); + } + + read(params) { + return this.http.get(this.baseUrl, { + params, + }); + } + + readDetail(id) { + return this.http.get(`${this.baseUrl}${id}/`); + } + + readOptions() { + return this.http.options(this.baseUrl); + } + + replace(id, data) { + return this.http.put(`${this.baseUrl}${id}/`, data); + } + + update(id, data) { + return this.http.patch(`${this.baseUrl}${id}/`, data); + } + + copy(id, data) { + return this.http.post(`${this.baseUrl}${id}/copy/`, data); + } +} + +export default Base; diff --git a/awx/ui_next/src/api/Base.test.jsx b/awx/ui_next/src/api/Base.test.jsx new file mode 100644 index 000000000000..40907e79f7c4 --- /dev/null +++ b/awx/ui_next/src/api/Base.test.jsx @@ -0,0 +1,112 @@ +import Base from './Base'; + +describe('Base', () => { + const createPromise = () => Promise.resolve(); + const mockBaseURL = '/api/v2/organizations/'; + const mockHttp = { + delete: jest.fn(createPromise), + get: jest.fn(createPromise), + options: jest.fn(createPromise), + patch: jest.fn(createPromise), + post: jest.fn(createPromise), + put: jest.fn(createPromise), + }; + + const BaseAPI = new Base(mockHttp, mockBaseURL); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('create calls http method with expected data', async done => { + const data = { name: 'test ' }; + await BaseAPI.create(data); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect(mockHttp.post.mock.calls[0][1]).toEqual(data); + + done(); + }); + + test('destroy calls http method with expected data', async done => { + const resourceId = 1; + await BaseAPI.destroy(resourceId); + + expect(mockHttp.delete).toHaveBeenCalledTimes(1); + expect(mockHttp.delete.mock.calls[0][0]).toEqual( + `${mockBaseURL}${resourceId}/` + ); + + done(); + }); + + test('read calls http method with expected data', async done => { + const testParams = { foo: 'bar' }; + const testParamsDuplicates = { foo: ['bar', 'baz'] }; + + await BaseAPI.read(testParams); + await BaseAPI.read(); + await BaseAPI.read(testParamsDuplicates); + + expect(mockHttp.get).toHaveBeenCalledTimes(3); + expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: { foo: 'bar' } }); + expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: undefined }); + expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[2][1]).toEqual({ + params: { foo: ['bar', 'baz'] }, + }); + done(); + }); + + test('readDetail calls http method with expected data', async done => { + const resourceId = 1; + + await BaseAPI.readDetail(resourceId); + + expect(mockHttp.get).toHaveBeenCalledTimes(1); + expect(mockHttp.get.mock.calls[0][0]).toEqual( + `${mockBaseURL}${resourceId}/` + ); + done(); + }); + + test('readOptions calls http method with expected data', async done => { + await BaseAPI.readOptions(); + + expect(mockHttp.options).toHaveBeenCalledTimes(1); + expect(mockHttp.options.mock.calls[0][0]).toEqual(`${mockBaseURL}`); + done(); + }); + + test('replace calls http method with expected data', async done => { + const resourceId = 1; + const data = { name: 'test ' }; + + await BaseAPI.replace(resourceId, data); + + expect(mockHttp.put).toHaveBeenCalledTimes(1); + expect(mockHttp.put.mock.calls[0][0]).toEqual( + `${mockBaseURL}${resourceId}/` + ); + expect(mockHttp.put.mock.calls[0][1]).toEqual(data); + + done(); + }); + + test('update calls http method with expected data', async done => { + const resourceId = 1; + const data = { name: 'test ' }; + + await BaseAPI.update(resourceId, data); + + expect(mockHttp.patch).toHaveBeenCalledTimes(1); + expect(mockHttp.patch.mock.calls[0][0]).toEqual( + `${mockBaseURL}${resourceId}/` + ); + expect(mockHttp.patch.mock.calls[0][1]).toEqual(data); + + done(); + }); +}); diff --git a/awx/ui_next/src/api/index.js b/awx/ui_next/src/api/index.js new file mode 100644 index 000000000000..cddf01e25924 --- /dev/null +++ b/awx/ui_next/src/api/index.js @@ -0,0 +1,127 @@ +import ActivityStream from './models/ActivityStream'; +import AdHocCommands from './models/AdHocCommands'; +import Applications from './models/Applications'; +import Auth from './models/Auth'; +import Config from './models/Config'; +import CredentialInputSources from './models/CredentialInputSources'; +import CredentialTypes from './models/CredentialTypes'; +import Credentials from './models/Credentials'; +import Dashboard from './models/Dashboard'; +import Groups from './models/Groups'; +import Hosts from './models/Hosts'; +import InstanceGroups from './models/InstanceGroups'; +import Instances from './models/Instances'; +import Inventories from './models/Inventories'; +import InventoryScripts from './models/InventoryScripts'; +import InventorySources from './models/InventorySources'; +import InventoryUpdates from './models/InventoryUpdates'; +import JobTemplates from './models/JobTemplates'; +import Jobs from './models/Jobs'; +import Labels from './models/Labels'; +import Me from './models/Me'; +import NotificationTemplates from './models/NotificationTemplates'; +import Notifications from './models/Notifications'; +import Organizations from './models/Organizations'; +import ProjectUpdates from './models/ProjectUpdates'; +import Projects from './models/Projects'; +import Roles from './models/Roles'; +import Root from './models/Root'; +import Schedules from './models/Schedules'; +import Settings from './models/Settings'; +import SystemJobs from './models/SystemJobs'; +import Teams from './models/Teams'; +import Tokens from './models/Tokens'; +import UnifiedJobTemplates from './models/UnifiedJobTemplates'; +import UnifiedJobs from './models/UnifiedJobs'; +import Users from './models/Users'; +import WorkflowApprovals from './models/WorkflowApprovals'; +import WorkflowApprovalTemplates from './models/WorkflowApprovalTemplates'; +import WorkflowJobTemplateNodes from './models/WorkflowJobTemplateNodes'; +import WorkflowJobTemplates from './models/WorkflowJobTemplates'; +import WorkflowJobs from './models/WorkflowJobs'; + +const ActivityStreamAPI = new ActivityStream(); +const AdHocCommandsAPI = new AdHocCommands(); +const ApplicationsAPI = new Applications(); +const AuthAPI = new Auth(); +const ConfigAPI = new Config(); +const CredentialInputSourcesAPI = new CredentialInputSources(); +const CredentialTypesAPI = new CredentialTypes(); +const CredentialsAPI = new Credentials(); +const DashboardAPI = new Dashboard(); +const GroupsAPI = new Groups(); +const HostsAPI = new Hosts(); +const InstanceGroupsAPI = new InstanceGroups(); +const InstancesAPI = new Instances(); +const InventoriesAPI = new Inventories(); +const InventoryScriptsAPI = new InventoryScripts(); +const InventorySourcesAPI = new InventorySources(); +const InventoryUpdatesAPI = new InventoryUpdates(); +const JobTemplatesAPI = new JobTemplates(); +const JobsAPI = new Jobs(); +const LabelsAPI = new Labels(); +const MeAPI = new Me(); +const NotificationTemplatesAPI = new NotificationTemplates(); +const NotificationsAPI = new Notifications(); +const OrganizationsAPI = new Organizations(); +const ProjectUpdatesAPI = new ProjectUpdates(); +const ProjectsAPI = new Projects(); +const RolesAPI = new Roles(); +const RootAPI = new Root(); +const SchedulesAPI = new Schedules(); +const SettingsAPI = new Settings(); +const SystemJobsAPI = new SystemJobs(); +const TeamsAPI = new Teams(); +const TokensAPI = new Tokens(); +const UnifiedJobTemplatesAPI = new UnifiedJobTemplates(); +const UnifiedJobsAPI = new UnifiedJobs(); +const UsersAPI = new Users(); +const WorkflowApprovalsAPI = new WorkflowApprovals(); +const WorkflowApprovalTemplatesAPI = new WorkflowApprovalTemplates(); +const WorkflowJobTemplateNodesAPI = new WorkflowJobTemplateNodes(); +const WorkflowJobTemplatesAPI = new WorkflowJobTemplates(); +const WorkflowJobsAPI = new WorkflowJobs(); + +export { + ActivityStreamAPI, + AdHocCommandsAPI, + ApplicationsAPI, + AuthAPI, + ConfigAPI, + CredentialInputSourcesAPI, + CredentialTypesAPI, + CredentialsAPI, + DashboardAPI, + GroupsAPI, + HostsAPI, + InstanceGroupsAPI, + InstancesAPI, + InventoriesAPI, + InventoryScriptsAPI, + InventorySourcesAPI, + InventoryUpdatesAPI, + JobTemplatesAPI, + JobsAPI, + LabelsAPI, + MeAPI, + NotificationTemplatesAPI, + NotificationsAPI, + OrganizationsAPI, + ProjectUpdatesAPI, + ProjectsAPI, + RolesAPI, + RootAPI, + SchedulesAPI, + SettingsAPI, + SystemJobsAPI, + TeamsAPI, + TokensAPI, + UnifiedJobTemplatesAPI, + UnifiedJobsAPI, + UsersAPI, + WorkflowApprovalsAPI, + WorkflowApprovalTemplatesAPI, + WorkflowJobTemplateNodesAPI, + WorkflowJobTemplatesAPI, + WorkflowJobsAPI, +}; diff --git a/awx/ui_next/src/api/mixins/InstanceGroups.mixin.js b/awx/ui_next/src/api/mixins/InstanceGroups.mixin.js new file mode 100644 index 000000000000..e6745ac52265 --- /dev/null +++ b/awx/ui_next/src/api/mixins/InstanceGroups.mixin.js @@ -0,0 +1,23 @@ +const InstanceGroupsMixin = parent => + class extends parent { + readInstanceGroups(resourceId, params) { + return this.http.get(`${this.baseUrl}${resourceId}/instance_groups/`, { + params, + }); + } + + associateInstanceGroup(resourceId, instanceGroupId) { + return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { + id: instanceGroupId, + }); + } + + disassociateInstanceGroup(resourceId, instanceGroupId) { + return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { + id: instanceGroupId, + disassociate: true, + }); + } + }; + +export default InstanceGroupsMixin; diff --git a/awx/ui_next/src/api/mixins/LaunchUpdate.mixin.js b/awx/ui_next/src/api/mixins/LaunchUpdate.mixin.js new file mode 100644 index 000000000000..a4e62afb20bb --- /dev/null +++ b/awx/ui_next/src/api/mixins/LaunchUpdate.mixin.js @@ -0,0 +1,12 @@ +const LaunchUpdateMixin = parent => + class extends parent { + launchUpdate(id, data) { + return this.http.post(`${this.baseUrl}${id}/update/`, data); + } + + readLaunchUpdate(id) { + return this.http.get(`${this.baseUrl}${id}/update/`); + } + }; + +export default LaunchUpdateMixin; diff --git a/awx/ui_next/src/api/mixins/Notifications.mixin.js b/awx/ui_next/src/api/mixins/Notifications.mixin.js new file mode 100644 index 000000000000..87a7002ec5c3 --- /dev/null +++ b/awx/ui_next/src/api/mixins/Notifications.mixin.js @@ -0,0 +1,170 @@ +const NotificationsMixin = parent => + class extends parent { + readOptionsNotificationTemplates(id) { + return this.http.options(`${this.baseUrl}${id}/notification_templates/`); + } + + readNotificationTemplates(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates/`, + params + ); + } + + readNotificationTemplatesStarted(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates_started/`, + { params } + ); + } + + readNotificationTemplatesSuccess(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates_success/`, + { params } + ); + } + + readNotificationTemplatesError(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates_error/`, + { params } + ); + } + + associateNotificationTemplatesStarted(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_started/`, + { id: notificationId } + ); + } + + disassociateNotificationTemplatesStarted(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_started/`, + { id: notificationId, disassociate: true } + ); + } + + associateNotificationTemplatesSuccess(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_success/`, + { id: notificationId } + ); + } + + disassociateNotificationTemplatesSuccess(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_success/`, + { id: notificationId, disassociate: true } + ); + } + + associateNotificationTemplatesError(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_error/`, + { id: notificationId } + ); + } + + disassociateNotificationTemplatesError(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_error/`, + { id: notificationId, disassociate: true } + ); + } + + /** + * This is a helper method meant to simplify setting the "on" status of + * a related notification. + * + * @param[resourceId] - id of the base resource + * @param[notificationId] - id of the notification + * @param[notificationType] - the type of notification, options are "success" and "error" + */ + associateNotificationTemplate( + resourceId, + notificationId, + notificationType + ) { + if (notificationType === 'approvals') { + return this.associateNotificationTemplatesApprovals( + resourceId, + notificationId + ); + } + + if (notificationType === 'started') { + return this.associateNotificationTemplatesStarted( + resourceId, + notificationId + ); + } + + if (notificationType === 'success') { + return this.associateNotificationTemplatesSuccess( + resourceId, + notificationId + ); + } + + if (notificationType === 'error') { + return this.associateNotificationTemplatesError( + resourceId, + notificationId + ); + } + + throw new Error( + `Unsupported notificationType for association: ${notificationType}` + ); + } + + /** + * This is a helper method meant to simplify setting the "off" status of + * a related notification. + * + * @param[resourceId] - id of the base resource + * @param[notificationId] - id of the notification + * @param[notificationType] - the type of notification, options are "success" and "error" + */ + disassociateNotificationTemplate( + resourceId, + notificationId, + notificationType + ) { + if (notificationType === 'approvals') { + return this.disassociateNotificationTemplatesApprovals( + resourceId, + notificationId + ); + } + + if (notificationType === 'started') { + return this.disassociateNotificationTemplatesStarted( + resourceId, + notificationId + ); + } + + if (notificationType === 'success') { + return this.disassociateNotificationTemplatesSuccess( + resourceId, + notificationId + ); + } + + if (notificationType === 'error') { + return this.disassociateNotificationTemplatesError( + resourceId, + notificationId + ); + } + + throw new Error( + `Unsupported notificationType for disassociation: ${notificationType}` + ); + } + }; + +export default NotificationsMixin; diff --git a/awx/ui_next/src/api/mixins/Relaunch.mixin.js b/awx/ui_next/src/api/mixins/Relaunch.mixin.js new file mode 100644 index 000000000000..06594c6dd386 --- /dev/null +++ b/awx/ui_next/src/api/mixins/Relaunch.mixin.js @@ -0,0 +1,12 @@ +const RelaunchMixin = parent => + class extends parent { + relaunch(id, data) { + return this.http.post(`${this.baseUrl}${id}/relaunch/`, data); + } + + readRelaunch(id) { + return this.http.get(`${this.baseUrl}${id}/relaunch/`); + } + }; + +export default RelaunchMixin; diff --git a/awx/ui_next/src/api/mixins/Schedules.mixin.js b/awx/ui_next/src/api/mixins/Schedules.mixin.js new file mode 100644 index 000000000000..d7dad6d40abf --- /dev/null +++ b/awx/ui_next/src/api/mixins/Schedules.mixin.js @@ -0,0 +1,16 @@ +const SchedulesMixin = parent => + class extends parent { + createSchedule(id, data) { + return this.http.post(`${this.baseUrl}${id}/schedules/`, data); + } + + readSchedules(id, params) { + return this.http.get(`${this.baseUrl}${id}/schedules/`, { params }); + } + + readScheduleOptions(id) { + return this.http.options(`${this.baseUrl}${id}/schedules/`); + } + }; + +export default SchedulesMixin; diff --git a/awx/ui_next/src/api/models/ActivityStream.js b/awx/ui_next/src/api/models/ActivityStream.js new file mode 100644 index 000000000000..99b65bc63458 --- /dev/null +++ b/awx/ui_next/src/api/models/ActivityStream.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class ActivityStream extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/activity_stream/'; + } +} + +export default ActivityStream; diff --git a/awx/ui_next/src/api/models/AdHocCommands.js b/awx/ui_next/src/api/models/AdHocCommands.js new file mode 100644 index 000000000000..4879b81b3266 --- /dev/null +++ b/awx/ui_next/src/api/models/AdHocCommands.js @@ -0,0 +1,11 @@ +import Base from '../Base'; +import RelaunchMixin from '../mixins/Relaunch.mixin'; + +class AdHocCommands extends RelaunchMixin(Base) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/ad_hoc_commands/'; + } +} + +export default AdHocCommands; diff --git a/awx/ui_next/src/api/models/Applications.js b/awx/ui_next/src/api/models/Applications.js new file mode 100644 index 000000000000..a8fe15f6949d --- /dev/null +++ b/awx/ui_next/src/api/models/Applications.js @@ -0,0 +1,20 @@ +import Base from '../Base'; + +class Applications extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/applications/'; + } + + readTokens(appId, params) { + return this.http.get(`${this.baseUrl}${appId}/tokens/`, { + params, + }); + } + + readTokenOptions(appId) { + return this.http.options(`${this.baseUrl}${appId}/tokens/`); + } +} + +export default Applications; diff --git a/awx/ui_next/src/api/models/Auth.js b/awx/ui_next/src/api/models/Auth.js new file mode 100644 index 000000000000..5743b4f3d527 --- /dev/null +++ b/awx/ui_next/src/api/models/Auth.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Auth extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/auth/'; + } +} + +export default Auth; diff --git a/awx/ui_next/src/api/models/Config.js b/awx/ui_next/src/api/models/Config.js new file mode 100644 index 000000000000..878ddfad70b1 --- /dev/null +++ b/awx/ui_next/src/api/models/Config.js @@ -0,0 +1,11 @@ +import Base from '../Base'; + +class Config extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/config/'; + this.read = this.read.bind(this); + } +} + +export default Config; diff --git a/awx/ui_next/src/api/models/CredentialInputSources.js b/awx/ui_next/src/api/models/CredentialInputSources.js new file mode 100644 index 000000000000..ec09cba2673b --- /dev/null +++ b/awx/ui_next/src/api/models/CredentialInputSources.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class CredentialInputSources extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/credential_input_sources/'; + } +} + +export default CredentialInputSources; diff --git a/awx/ui_next/src/api/models/CredentialTypes.js b/awx/ui_next/src/api/models/CredentialTypes.js new file mode 100644 index 000000000000..39247b5ebcce --- /dev/null +++ b/awx/ui_next/src/api/models/CredentialTypes.js @@ -0,0 +1,36 @@ +import Base from '../Base'; + +class CredentialTypes extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/credential_types/'; + } + + async loadAllTypes( + acceptableKinds = ['machine', 'cloud', 'net', 'ssh', 'vault', 'kubernetes'] + ) { + const pageSize = 200; + // The number of credential types a user can have is unlimited. In practice, it is unlikely for + // users to have more than a page at the maximum request size. + const { + data: { next, results }, + } = await this.read({ page_size: pageSize }); + let nextResults = []; + if (next) { + const { data } = await this.read({ + page_size: pageSize, + page: 2, + }); + nextResults = data.results; + } + return results + .concat(nextResults) + .filter(type => acceptableKinds.includes(type.kind)); + } + + test(id, data) { + return this.http.post(`${this.baseUrl}${id}/test/`, data); + } +} + +export default CredentialTypes; diff --git a/awx/ui_next/src/api/models/CredentialTypes.test.js b/awx/ui_next/src/api/models/CredentialTypes.test.js new file mode 100644 index 000000000000..d68ff06a0cb1 --- /dev/null +++ b/awx/ui_next/src/api/models/CredentialTypes.test.js @@ -0,0 +1,68 @@ +import CredentialTypes from './CredentialTypes'; + +const typesData = [ + { id: 1, kind: 'machine' }, + { id: 2, kind: 'cloud' }, +]; + +describe('CredentialTypesAPI', () => { + test('should load all types', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(); + + expect(mockHttp.get).toHaveBeenCalledTimes(1); + expect(mockHttp.get.mock.calls[0]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200 } }, + ]); + expect(types).toEqual(typesData); + }); + + test('should load all types (2 pages)', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + next: 2, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(); + + expect(mockHttp.get).toHaveBeenCalledTimes(2); + expect(mockHttp.get.mock.calls[0]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200 } }, + ]); + expect(mockHttp.get.mock.calls[1]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200, page: 2 } }, + ]); + expect(types).toHaveLength(4); + }); + + test('should filter by acceptable kinds', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(['machine']); + + expect(types).toEqual([typesData[0]]); + }); +}); diff --git a/awx/ui_next/src/api/models/Credentials.js b/awx/ui_next/src/api/models/Credentials.js new file mode 100644 index 000000000000..1560357bd13f --- /dev/null +++ b/awx/ui_next/src/api/models/Credentials.js @@ -0,0 +1,62 @@ +import Base from '../Base'; + +class Credentials extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/credentials/'; + + this.readAccessList = this.readAccessList.bind(this); + this.readAccessOptions = this.readAccessOptions.bind(this); + this.readInputSources = this.readInputSources.bind(this); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { + params, + }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readInputSources(id) { + const maxRequests = 5; + let requestCounter = 0; + const fetchInputSources = async (pageNo = 1, inputSources = []) => { + try { + requestCounter++; + const { data } = await this.http.get( + `${this.baseUrl}${id}/input_sources/`, + { + params: { + page: pageNo, + page_size: 200, + }, + } + ); + if (data?.next && requestCounter <= maxRequests) { + return fetchInputSources( + pageNo + 1, + inputSources.concat(data.results) + ); + } + return Promise.resolve({ + data: { + results: inputSources.concat(data.results), + }, + }); + } catch (error) { + return Promise.reject(error); + } + }; + + return fetchInputSources(); + } + + test(id, data) { + return this.http.post(`${this.baseUrl}${id}/test/`, data); + } +} + +export default Credentials; diff --git a/awx/ui_next/src/api/models/Dashboard.js b/awx/ui_next/src/api/models/Dashboard.js new file mode 100644 index 000000000000..aa1d86340a2a --- /dev/null +++ b/awx/ui_next/src/api/models/Dashboard.js @@ -0,0 +1,16 @@ +import Base from '../Base'; + +class Dashboard extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/dashboard/'; + } + + readJobGraph(params) { + return this.http.get(`${this.baseUrl}graphs/jobs/`, { + params, + }); + } +} + +export default Dashboard; diff --git a/awx/ui_next/src/api/models/Groups.js b/awx/ui_next/src/api/models/Groups.js new file mode 100644 index 000000000000..3f9aa928e033 --- /dev/null +++ b/awx/ui_next/src/api/models/Groups.js @@ -0,0 +1,59 @@ +import Base from '../Base'; + +class Groups extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/groups/'; + + this.associateHost = this.associateHost.bind(this); + this.createHost = this.createHost.bind(this); + this.readAllHosts = this.readAllHosts.bind(this); + this.disassociateHost = this.disassociateHost.bind(this); + } + + associateHost(id, hostId) { + return this.http.post(`${this.baseUrl}${id}/hosts/`, { + id: hostId, + }); + } + + createHost(id, data) { + return this.http.post(`${this.baseUrl}${id}/hosts/`, data); + } + + readAllHosts(id, params) { + return this.http.get(`${this.baseUrl}${id}/all_hosts/`, { + params, + }); + } + + disassociateHost(id, host) { + return this.http.post(`${this.baseUrl}${id}/hosts/`, { + id: host.id, + disassociate: true, + }); + } + + readChildren(id, params) { + return this.http.get(`${this.baseUrl}${id}/children/`, { params }); + } + + associateChildGroup(id, childId) { + return this.http.post(`${this.baseUrl}${id}/children/`, { id: childId }); + } + + disassociateChildGroup(id, childId) { + return this.http.post(`${this.baseUrl}${id}/children/`, { + disassociate: id, + id: childId, + }); + } + + readPotentialGroups(id, params) { + return this.http.get(`${this.baseUrl}${id}/potential_children/`, { + params, + }); + } +} + +export default Groups; diff --git a/awx/ui_next/src/api/models/Hosts.js b/awx/ui_next/src/api/models/Hosts.js new file mode 100644 index 000000000000..ae90bf2826f9 --- /dev/null +++ b/awx/ui_next/src/api/models/Hosts.js @@ -0,0 +1,39 @@ +import Base from '../Base'; + +class Hosts extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/hosts/'; + + this.readFacts = this.readFacts.bind(this); + this.readAllGroups = this.readAllGroups.bind(this); + this.readGroupsOptions = this.readGroupsOptions.bind(this); + this.associateGroup = this.associateGroup.bind(this); + this.disassociateGroup = this.disassociateGroup.bind(this); + } + + readFacts(id) { + return this.http.get(`${this.baseUrl}${id}/ansible_facts/`); + } + + readAllGroups(id, params) { + return this.http.get(`${this.baseUrl}${id}/all_groups/`, { params }); + } + + readGroupsOptions(id) { + return this.http.options(`${this.baseUrl}${id}/groups/`); + } + + associateGroup(id, groupId) { + return this.http.post(`${this.baseUrl}${id}/groups/`, { id: groupId }); + } + + disassociateGroup(id, group) { + return this.http.post(`${this.baseUrl}${id}/groups/`, { + id: group.id, + disassociate: true, + }); + } +} + +export default Hosts; diff --git a/awx/ui_next/src/api/models/InstanceGroups.js b/awx/ui_next/src/api/models/InstanceGroups.js new file mode 100644 index 000000000000..82704c95d156 --- /dev/null +++ b/awx/ui_next/src/api/models/InstanceGroups.js @@ -0,0 +1,41 @@ +import Base from '../Base'; + +class InstanceGroups extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/instance_groups/'; + + this.associateInstance = this.associateInstance.bind(this); + this.disassociateInstance = this.disassociateInstance.bind(this); + this.readInstanceOptions = this.readInstanceOptions.bind(this); + this.readInstances = this.readInstances.bind(this); + this.readJobs = this.readJobs.bind(this); + } + + associateInstance(instanceGroupId, instanceId) { + return this.http.post(`${this.baseUrl}${instanceGroupId}/instances/`, { + id: instanceId, + }); + } + + disassociateInstance(instanceGroupId, instanceId) { + return this.http.post(`${this.baseUrl}${instanceGroupId}/instances/`, { + id: instanceId, + disassociate: true, + }); + } + + readInstances(id, params) { + return this.http.get(`${this.baseUrl}${id}/instances/`, { params }); + } + + readInstanceOptions(id) { + return this.http.options(`${this.baseUrl}${id}/instances/`); + } + + readJobs(id) { + return this.http.get(`${this.baseUrl}${id}/jobs/`); + } +} + +export default InstanceGroups; diff --git a/awx/ui_next/src/api/models/Instances.js b/awx/ui_next/src/api/models/Instances.js new file mode 100644 index 000000000000..41fa06d5f750 --- /dev/null +++ b/awx/ui_next/src/api/models/Instances.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Instances extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/instances/'; + } +} + +export default Instances; diff --git a/awx/ui_next/src/api/models/Inventories.js b/awx/ui_next/src/api/models/Inventories.js new file mode 100644 index 000000000000..c9d774e002b8 --- /dev/null +++ b/awx/ui_next/src/api/models/Inventories.js @@ -0,0 +1,115 @@ +import Base from '../Base'; +import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; + +class Inventories extends InstanceGroupsMixin(Base) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/inventories/'; + + this.readAccessList = this.readAccessList.bind(this); + this.readAccessOptions = this.readAccessOptions.bind(this); + this.readHosts = this.readHosts.bind(this); + this.readHostDetail = this.readHostDetail.bind(this); + this.readGroups = this.readGroups.bind(this); + this.readGroupsOptions = this.readGroupsOptions.bind(this); + this.promoteGroup = this.promoteGroup.bind(this); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { + params, + }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + createHost(id, data) { + return this.http.post(`${this.baseUrl}${id}/hosts/`, data); + } + + readHosts(id, params) { + return this.http.get(`${this.baseUrl}${id}/hosts/`, { + params, + }); + } + + async readHostDetail(inventoryId, hostId) { + const { + data: { results }, + } = await this.http.get( + `${this.baseUrl}${inventoryId}/hosts/?id=${hostId}` + ); + + if (Array.isArray(results) && results.length) { + return results[0]; + } + + throw new Error( + `How did you get here? Host not found for Inventory ID: ${inventoryId}` + ); + } + + readGroups(id, params) { + return this.http.get(`${this.baseUrl}${id}/groups/`, { + params, + }); + } + + readGroupsOptions(id) { + return this.http.options(`${this.baseUrl}${id}/groups/`); + } + + readHostsOptions(id) { + return this.http.options(`${this.baseUrl}${id}/hosts/`); + } + + promoteGroup(inventoryId, groupId) { + return this.http.post(`${this.baseUrl}${inventoryId}/groups/`, { + id: groupId, + disassociate: true, + }); + } + + readSources(inventoryId, params) { + return this.http.get(`${this.baseUrl}${inventoryId}/inventory_sources/`, { + params, + }); + } + + async readSourceDetail(inventoryId, sourceId) { + const { + data: { results }, + } = await this.http.get( + `${this.baseUrl}${inventoryId}/inventory_sources/?id=${sourceId}` + ); + + if (Array.isArray(results) && results.length) { + return results[0]; + } + + throw new Error( + `How did you get here? Source not found for Inventory ID: ${inventoryId}` + ); + } + + syncAllSources(inventoryId) { + return this.http.post( + `${this.baseUrl}${inventoryId}/update_inventory_sources/` + ); + } + + readAdHocOptions(inventoryId) { + return this.http.options(`${this.baseUrl}${inventoryId}/ad_hoc_commands/`); + } + + launchAdHocCommands(inventoryId, values) { + return this.http.post( + `${this.baseUrl}${inventoryId}/ad_hoc_commands/`, + values + ); + } +} + +export default Inventories; diff --git a/awx/ui_next/src/api/models/InventoryScripts.js b/awx/ui_next/src/api/models/InventoryScripts.js new file mode 100644 index 000000000000..17214cd5fd81 --- /dev/null +++ b/awx/ui_next/src/api/models/InventoryScripts.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class InventoryScripts extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/inventory_scripts/'; + } +} + +export default InventoryScripts; diff --git a/awx/ui_next/src/api/models/InventorySources.js b/awx/ui_next/src/api/models/InventorySources.js new file mode 100644 index 000000000000..8d20076ba815 --- /dev/null +++ b/awx/ui_next/src/api/models/InventorySources.js @@ -0,0 +1,32 @@ +import Base from '../Base'; +import NotificationsMixin from '../mixins/Notifications.mixin'; +import LaunchUpdateMixin from '../mixins/LaunchUpdate.mixin'; +import SchedulesMixin from '../mixins/Schedules.mixin'; + +class InventorySources extends LaunchUpdateMixin( + NotificationsMixin(SchedulesMixin(Base)) +) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/inventory_sources/'; + + this.createSyncStart = this.createSyncStart.bind(this); + this.destroyGroups = this.destroyGroups.bind(this); + this.destroyHosts = this.destroyHosts.bind(this); + } + + createSyncStart(sourceId, extraVars) { + return this.http.post(`${this.baseUrl}${sourceId}/update/`, { + extra_vars: extraVars, + }); + } + + destroyGroups(id) { + return this.http.delete(`${this.baseUrl}${id}/groups/`); + } + + destroyHosts(id) { + return this.http.delete(`${this.baseUrl}${id}/hosts/`); + } +} +export default InventorySources; diff --git a/awx/ui_next/src/api/models/InventoryUpdates.js b/awx/ui_next/src/api/models/InventoryUpdates.js new file mode 100644 index 000000000000..1700c7b26b46 --- /dev/null +++ b/awx/ui_next/src/api/models/InventoryUpdates.js @@ -0,0 +1,15 @@ +import Base from '../Base'; +import LaunchUpdateMixin from '../mixins/LaunchUpdate.mixin'; + +class InventoryUpdates extends LaunchUpdateMixin(Base) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/inventory_updates/'; + this.createSyncCancel = this.createSyncCancel.bind(this); + } + + createSyncCancel(sourceId) { + return this.http.post(`${this.baseUrl}${sourceId}/cancel/`); + } +} +export default InventoryUpdates; diff --git a/awx/ui_next/src/api/models/JobTemplates.js b/awx/ui_next/src/api/models/JobTemplates.js new file mode 100644 index 000000000000..44281f1511b3 --- /dev/null +++ b/awx/ui_next/src/api/models/JobTemplates.js @@ -0,0 +1,105 @@ +import Base from '../Base'; +import NotificationsMixin from '../mixins/Notifications.mixin'; +import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; +import SchedulesMixin from '../mixins/Schedules.mixin'; + +class JobTemplates extends SchedulesMixin( + InstanceGroupsMixin(NotificationsMixin(Base)) +) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/job_templates/'; + + this.launch = this.launch.bind(this); + this.readLaunch = this.readLaunch.bind(this); + this.associateLabel = this.associateLabel.bind(this); + this.disassociateLabel = this.disassociateLabel.bind(this); + this.readCredentials = this.readCredentials.bind(this); + this.readAccessList = this.readAccessList.bind(this); + this.readAccessOptions = this.readAccessOptions.bind(this); + this.readWebhookKey = this.readWebhookKey.bind(this); + } + + launch(id, data) { + return this.http.post(`${this.baseUrl}${id}/launch/`, data); + } + + readTemplateOptions(id) { + return this.http.options(`${this.baseUrl}${id}/`); + } + + readLaunch(id) { + return this.http.get(`${this.baseUrl}${id}/launch/`); + } + + associateLabel(id, label, orgId) { + return this.http.post(`${this.baseUrl}${id}/labels/`, { + name: label.name, + organization: orgId, + }); + } + + disassociateLabel(id, label) { + return this.http.post(`${this.baseUrl}${id}/labels/`, { + id: label.id, + disassociate: true, + }); + } + + readCredentials(id, params) { + return this.http.get(`${this.baseUrl}${id}/credentials/`, { + params, + }); + } + + associateCredentials(id, credentialId) { + return this.http.post(`${this.baseUrl}${id}/credentials/`, { + id: credentialId, + }); + } + + disassociateCredentials(id, credentialId) { + return this.http.post(`${this.baseUrl}${id}/credentials/`, { + id: credentialId, + disassociate: true, + }); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { + params, + }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readScheduleList(id, params) { + return this.http.get(`${this.baseUrl}${id}/schedules/`, { + params, + }); + } + + readSurvey(id) { + return this.http.get(`${this.baseUrl}${id}/survey_spec/`); + } + + updateSurvey(id, survey) { + return this.http.post(`${this.baseUrl}${id}/survey_spec/`, survey); + } + + destroySurvey(id) { + return this.http.delete(`${this.baseUrl}${id}/survey_spec/`); + } + + readWebhookKey(id) { + return this.http.get(`${this.baseUrl}${id}/webhook_key/`); + } + + updateWebhookKey(id) { + return this.http.post(`${this.baseUrl}${id}/webhook_key/`); + } +} + +export default JobTemplates; diff --git a/awx/ui_next/src/api/models/Jobs.js b/awx/ui_next/src/api/models/Jobs.js new file mode 100644 index 000000000000..fc9bbb233449 --- /dev/null +++ b/awx/ui_next/src/api/models/Jobs.js @@ -0,0 +1,58 @@ +import Base from '../Base'; +import RelaunchMixin from '../mixins/Relaunch.mixin'; + +const getBaseURL = type => { + switch (type) { + case 'playbook': + case 'job': + return '/jobs/'; + case 'project': + case 'project_update': + return '/project_updates/'; + case 'system': + case 'system_job': + return '/system_jobs/'; + case 'inventory': + case 'inventory_update': + return '/inventory_updates/'; + case 'command': + case 'ad_hoc_command': + return '/ad_hoc_commands/'; + case 'workflow': + case 'workflow_job': + return '/workflow_jobs/'; + default: + throw new Error('Unable to find matching job type'); + } +}; + +class Jobs extends RelaunchMixin(Base) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/jobs/'; + } + + cancel(id, type) { + return this.http.post(`/api/v2${getBaseURL(type)}${id}/cancel/`); + } + + readCredentials(id, type) { + return this.http.get(`/api/v2${getBaseURL(type)}${id}/credentials/`); + } + + readDetail(id, type) { + return this.http.get(`/api/v2${getBaseURL(type)}${id}/`); + } + + readEvents(id, type = 'playbook', params = {}) { + let endpoint; + if (type === 'playbook') { + endpoint = `/api/v2${getBaseURL(type)}${id}/job_events/`; + } else { + endpoint = `/api/v2${getBaseURL(type)}${id}/events/`; + } + return this.http.get(endpoint, { params }); + } +} + +export default Jobs; diff --git a/awx/ui_next/src/api/models/Labels.js b/awx/ui_next/src/api/models/Labels.js new file mode 100644 index 000000000000..0c0126b89821 --- /dev/null +++ b/awx/ui_next/src/api/models/Labels.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Labels extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/labels/'; + } +} + +export default Labels; diff --git a/awx/ui_next/src/api/models/Me.js b/awx/ui_next/src/api/models/Me.js new file mode 100644 index 000000000000..77663567e97a --- /dev/null +++ b/awx/ui_next/src/api/models/Me.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Me extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/me/'; + } +} + +export default Me; diff --git a/awx/ui_next/src/api/models/NotificationTemplates.js b/awx/ui_next/src/api/models/NotificationTemplates.js new file mode 100644 index 000000000000..69cd5f40228a --- /dev/null +++ b/awx/ui_next/src/api/models/NotificationTemplates.js @@ -0,0 +1,14 @@ +import Base from '../Base'; + +class NotificationTemplates extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/notification_templates/'; + } + + test(id) { + return this.http.post(`${this.baseUrl}${id}/test/`); + } +} + +export default NotificationTemplates; diff --git a/awx/ui_next/src/api/models/Notifications.js b/awx/ui_next/src/api/models/Notifications.js new file mode 100644 index 000000000000..68405c0986bc --- /dev/null +++ b/awx/ui_next/src/api/models/Notifications.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Notifications extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/notifications/'; + } +} + +export default Notifications; diff --git a/awx/ui_next/src/api/models/Organizations.js b/awx/ui_next/src/api/models/Organizations.js new file mode 100644 index 000000000000..ce236067b4b2 --- /dev/null +++ b/awx/ui_next/src/api/models/Organizations.js @@ -0,0 +1,72 @@ +import Base from '../Base'; +import NotificationsMixin from '../mixins/Notifications.mixin'; +import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; + +class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/organizations/'; + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readTeams(id, params) { + return this.http.get(`${this.baseUrl}${id}/teams/`, { params }); + } + + readTeamsOptions(id) { + return this.http.options(`${this.baseUrl}${id}/teams/`); + } + + readGalaxyCredentials(id, params) { + return this.http.get(`${this.baseUrl}${id}/galaxy_credentials/`, { + params, + }); + } + + createUser(id, data) { + return this.http.post(`${this.baseUrl}${id}/users/`, data); + } + + readNotificationTemplatesApprovals(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates_approvals/`, + { params } + ); + } + + associateNotificationTemplatesApprovals(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_approvals/`, + { id: notificationId } + ); + } + + disassociateNotificationTemplatesApprovals(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_approvals/`, + { id: notificationId, disassociate: true } + ); + } + + associateGalaxyCredential(resourceId, credentialId) { + return this.http.post(`${this.baseUrl}${resourceId}/galaxy_credentials/`, { + id: credentialId, + }); + } + + disassociateGalaxyCredential(resourceId, credentialId) { + return this.http.post(`${this.baseUrl}${resourceId}/galaxy_credentials/`, { + id: credentialId, + disassociate: true, + }); + } +} + +export default Organizations; diff --git a/awx/ui_next/src/api/models/Organizations.test.jsx b/awx/ui_next/src/api/models/Organizations.test.jsx new file mode 100644 index 000000000000..d9f45c954817 --- /dev/null +++ b/awx/ui_next/src/api/models/Organizations.test.jsx @@ -0,0 +1,60 @@ +import { describeNotificationMixin } from '../../../testUtils/apiReusable'; +import Organizations from './Organizations'; + +describe('OrganizationsAPI', () => { + const orgId = 1; + const createPromise = () => Promise.resolve(); + const mockHttp = { get: jest.fn(createPromise) }; + + const OrganizationsAPI = new Organizations(mockHttp); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('read access list calls get with expected params', async done => { + const testParams = { foo: 'bar' }; + const testParamsDuplicates = { foo: ['bar', 'baz'] }; + + const mockBaseURL = `/api/v2/organizations/${orgId}/access_list/`; + + await OrganizationsAPI.readAccessList(orgId); + await OrganizationsAPI.readAccessList(orgId, testParams); + await OrganizationsAPI.readAccessList(orgId, testParamsDuplicates); + + expect(mockHttp.get).toHaveBeenCalledTimes(3); + expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: undefined }); + expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: { foo: 'bar' } }); + expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[2][1]).toEqual({ + params: { foo: ['bar', 'baz'] }, + }); + done(); + }); + + test('read teams calls get with expected params', async done => { + const testParams = { foo: 'bar' }; + const testParamsDuplicates = { foo: ['bar', 'baz'] }; + + const mockBaseURL = `/api/v2/organizations/${orgId}/teams/`; + + await OrganizationsAPI.readTeams(orgId); + await OrganizationsAPI.readTeams(orgId, testParams); + await OrganizationsAPI.readTeams(orgId, testParamsDuplicates); + + expect(mockHttp.get).toHaveBeenCalledTimes(3); + expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: undefined }); + expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: { foo: 'bar' } }); + expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); + expect(mockHttp.get.mock.calls[2][1]).toEqual({ + params: { foo: ['bar', 'baz'] }, + }); + done(); + }); +}); + +describeNotificationMixin(Organizations, 'Organizations[NotificationsMixin]'); diff --git a/awx/ui_next/src/api/models/ProjectUpdates.js b/awx/ui_next/src/api/models/ProjectUpdates.js new file mode 100644 index 000000000000..46d0633f0df3 --- /dev/null +++ b/awx/ui_next/src/api/models/ProjectUpdates.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class ProjectUpdates extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/project_updates/'; + } +} + +export default ProjectUpdates; diff --git a/awx/ui_next/src/api/models/Projects.js b/awx/ui_next/src/api/models/Projects.js new file mode 100644 index 000000000000..38879a2bc2ef --- /dev/null +++ b/awx/ui_next/src/api/models/Projects.js @@ -0,0 +1,46 @@ +import Base from '../Base'; +import NotificationsMixin from '../mixins/Notifications.mixin'; +import LaunchUpdateMixin from '../mixins/LaunchUpdate.mixin'; +import SchedulesMixin from '../mixins/Schedules.mixin'; + +class Projects extends SchedulesMixin( + LaunchUpdateMixin(NotificationsMixin(Base)) +) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/projects/'; + + this.readAccessList = this.readAccessList.bind(this); + this.readAccessOptions = this.readAccessOptions.bind(this); + this.readInventories = this.readInventories.bind(this); + this.readPlaybooks = this.readPlaybooks.bind(this); + this.readSync = this.readSync.bind(this); + this.sync = this.sync.bind(this); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readInventories(id) { + return this.http.get(`${this.baseUrl}${id}/inventories/`); + } + + readPlaybooks(id) { + return this.http.get(`${this.baseUrl}${id}/playbooks/`); + } + + readSync(id) { + return this.http.get(`${this.baseUrl}${id}/update/`); + } + + sync(id) { + return this.http.post(`${this.baseUrl}${id}/update/`); + } +} + +export default Projects; diff --git a/awx/ui_next/src/api/models/Roles.js b/awx/ui_next/src/api/models/Roles.js new file mode 100644 index 000000000000..3f89c8eb5fcc --- /dev/null +++ b/awx/ui_next/src/api/models/Roles.js @@ -0,0 +1,23 @@ +import Base from '../Base'; + +class Roles extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/roles/'; + } + + disassociateUserRole(roleId, userId) { + return this.http.post(`${this.baseUrl}${roleId}/users/`, { + disassociate: true, + id: userId, + }); + } + + disassociateTeamRole(roleId, teamId) { + return this.http.post(`${this.baseUrl}${roleId}/teams/`, { + disassociate: true, + id: teamId, + }); + } +} +export default Roles; diff --git a/awx/ui_next/src/api/models/Root.js b/awx/ui_next/src/api/models/Root.js new file mode 100644 index 000000000000..e930d3cc59de --- /dev/null +++ b/awx/ui_next/src/api/models/Root.js @@ -0,0 +1,38 @@ +import Base from '../Base'; + +class Root extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/'; + this.redirectURL = '/api/v2/config/'; + } + + async login(username, password, redirect = this.redirectURL) { + const loginUrl = `${this.baseUrl}login/`; + const un = encodeURIComponent(username); + const pw = encodeURIComponent(password); + const next = encodeURIComponent(redirect); + + const data = `username=${un}&password=${pw}&next=${next}`; + const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; + + await this.http.get(loginUrl, { headers }); + const response = await this.http.post(loginUrl, data, { headers }); + + return response; + } + + logout() { + return this.http.get(`${this.baseUrl}logout/`); + } + + readAssetVariables() { + // TODO: There's better ways of doing this. Build tools, scripts, + // automation etc. should relocate this variable file to an importable + // location in src prior to building. That said, a raw http call + // works for now. + return this.http.get('/static/media/default.strings.json'); + } +} + +export default Root; diff --git a/awx/ui_next/src/api/models/Root.test.jsx b/awx/ui_next/src/api/models/Root.test.jsx new file mode 100644 index 000000000000..3fb79cdfc915 --- /dev/null +++ b/awx/ui_next/src/api/models/Root.test.jsx @@ -0,0 +1,52 @@ +import Root from './Root'; + +describe('RootAPI', () => { + const createPromise = () => Promise.resolve(); + const mockHttp = { + get: jest.fn(createPromise), + post: jest.fn(createPromise), + }; + + const RootAPI = new Root(mockHttp); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('login calls get and post with expected content headers', async done => { + const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; + + await RootAPI.login('username', 'password'); + + expect(mockHttp.get).toHaveBeenCalledTimes(1); + expect(mockHttp.get.mock.calls[0]).toContainEqual({ headers }); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect(mockHttp.post.mock.calls[0]).toContainEqual({ headers }); + + done(); + }); + + test('login sends expected data', async done => { + await RootAPI.login('foo', 'bar'); + await RootAPI.login('foo', 'bar', 'baz'); + + expect(mockHttp.post).toHaveBeenCalledTimes(2); + expect(mockHttp.post.mock.calls[0]).toContainEqual( + 'username=foo&password=bar&next=%2Fapi%2Fv2%2Fconfig%2F' + ); + expect(mockHttp.post.mock.calls[1]).toContainEqual( + 'username=foo&password=bar&next=baz' + ); + + done(); + }); + + test('logout calls expected http method', async done => { + await RootAPI.logout(); + + expect(mockHttp.get).toHaveBeenCalledTimes(1); + + done(); + }); +}); diff --git a/awx/ui_next/src/api/models/Schedules.js b/awx/ui_next/src/api/models/Schedules.js new file mode 100644 index 000000000000..7f20e992ae4d --- /dev/null +++ b/awx/ui_next/src/api/models/Schedules.js @@ -0,0 +1,22 @@ +import Base from '../Base'; + +class Schedules extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/schedules/'; + } + + createPreview(data) { + return this.http.post(`${this.baseUrl}preview/`, data); + } + + readCredentials(resourceId, params) { + return this.http.get(`${this.baseUrl}${resourceId}/credentials/`, params); + } + + readZoneInfo() { + return this.http.get(`${this.baseUrl}zoneinfo/`); + } +} + +export default Schedules; diff --git a/awx/ui_next/src/api/models/Settings.js b/awx/ui_next/src/api/models/Settings.js new file mode 100644 index 000000000000..3c85f68da64c --- /dev/null +++ b/awx/ui_next/src/api/models/Settings.js @@ -0,0 +1,30 @@ +import Base from '../Base'; + +class Settings extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/settings/'; + } + + readAllOptions() { + return this.http.options(`${this.baseUrl}all/`); + } + + updateAll(data) { + return this.http.patch(`${this.baseUrl}all/`, data); + } + + readCategory(category) { + return this.http.get(`${this.baseUrl}${category}/`); + } + + readCategoryOptions(category) { + return this.http.options(`${this.baseUrl}${category}/`); + } + + createTest(category, data) { + return this.http.post(`${this.baseUrl}${category}/test/`, data); + } +} + +export default Settings; diff --git a/awx/ui_next/src/api/models/SystemJobs.js b/awx/ui_next/src/api/models/SystemJobs.js new file mode 100644 index 000000000000..d7b6ec1750e3 --- /dev/null +++ b/awx/ui_next/src/api/models/SystemJobs.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class SystemJobs extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/system_jobs/'; + } +} + +export default SystemJobs; diff --git a/awx/ui_next/src/api/models/Teams.js b/awx/ui_next/src/api/models/Teams.js new file mode 100644 index 000000000000..180c59032ce1 --- /dev/null +++ b/awx/ui_next/src/api/models/Teams.js @@ -0,0 +1,47 @@ +import Base from '../Base'; + +class Teams extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/teams/'; + } + + associateRole(teamId, roleId) { + return this.http.post(`${this.baseUrl}${teamId}/roles/`, { + id: roleId, + }); + } + + disassociateRole(teamId, roleId) { + return this.http.post(`${this.baseUrl}${teamId}/roles/`, { + id: roleId, + disassociate: true, + }); + } + + readRoles(teamId, params) { + return this.http.get(`${this.baseUrl}${teamId}/roles/`, { + params, + }); + } + + readRoleOptions(teamId) { + return this.http.options(`${this.baseUrl}${teamId}/roles/`); + } + + readAccessList(teamId, params) { + return this.http.get(`${this.baseUrl}${teamId}/access_list/`, { + params, + }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readUsersAccessOptions(teamId) { + return this.http.options(`${this.baseUrl}${teamId}/users/`); + } +} + +export default Teams; diff --git a/awx/ui_next/src/api/models/Teams.test.jsx b/awx/ui_next/src/api/models/Teams.test.jsx new file mode 100644 index 000000000000..b618b1dddd63 --- /dev/null +++ b/awx/ui_next/src/api/models/Teams.test.jsx @@ -0,0 +1,40 @@ +import Teams from './Teams'; + +describe('TeamsAPI', () => { + const teamId = 1; + const roleId = 7; + const createPromise = () => Promise.resolve(); + const mockHttp = { post: jest.fn(createPromise) }; + + const TeamsAPI = new Teams(mockHttp); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('associate role calls post with expected params', async done => { + await TeamsAPI.associateRole(teamId, roleId); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect( + mockHttp.post.mock.calls[0] + ).toContainEqual(`/api/v2/teams/${teamId}/roles/`, { id: roleId }); + + done(); + }); + + test('read teams calls post with expected params', async done => { + await TeamsAPI.disassociateRole(teamId, roleId); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect(mockHttp.post.mock.calls[0]).toContainEqual( + `/api/v2/teams/${teamId}/roles/`, + { + id: roleId, + disassociate: true, + } + ); + + done(); + }); +}); diff --git a/awx/ui_next/src/api/models/Tokens.js b/awx/ui_next/src/api/models/Tokens.js new file mode 100644 index 000000000000..5dd490808d81 --- /dev/null +++ b/awx/ui_next/src/api/models/Tokens.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Tokens extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/tokens/'; + } +} + +export default Tokens; diff --git a/awx/ui_next/src/api/models/UnifiedJobTemplates.js b/awx/ui_next/src/api/models/UnifiedJobTemplates.js new file mode 100644 index 000000000000..79d70610eb4e --- /dev/null +++ b/awx/ui_next/src/api/models/UnifiedJobTemplates.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class UnifiedJobTemplates extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/unified_job_templates/'; + } +} + +export default UnifiedJobTemplates; diff --git a/awx/ui_next/src/api/models/UnifiedJobs.js b/awx/ui_next/src/api/models/UnifiedJobs.js new file mode 100644 index 000000000000..4ba18fdd00c6 --- /dev/null +++ b/awx/ui_next/src/api/models/UnifiedJobs.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class UnifiedJobs extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/unified_jobs/'; + } +} + +export default UnifiedJobs; diff --git a/awx/ui_next/src/api/models/Users.js b/awx/ui_next/src/api/models/Users.js new file mode 100644 index 000000000000..c9d47826e2e8 --- /dev/null +++ b/awx/ui_next/src/api/models/Users.js @@ -0,0 +1,69 @@ +import Base from '../Base'; + +class Users extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/users/'; + } + + associateRole(userId, roleId) { + return this.http.post(`${this.baseUrl}${userId}/roles/`, { + id: roleId, + }); + } + + createToken(userId, data) { + return this.http.post(`${this.baseUrl}${userId}/authorized_tokens/`, data); + } + + disassociateRole(userId, roleId) { + return this.http.post(`${this.baseUrl}${userId}/roles/`, { + id: roleId, + disassociate: true, + }); + } + + readOrganizations(userId, params) { + return this.http.get(`${this.baseUrl}${userId}/organizations/`, { + params, + }); + } + + readRoles(userId, params) { + return this.http.get(`${this.baseUrl}${userId}/roles/`, { + params, + }); + } + + readRoleOptions(userId) { + return this.http.options(`${this.baseUrl}${userId}/roles/`); + } + + readTeams(userId, params) { + return this.http.get(`${this.baseUrl}${userId}/teams/`, { + params, + }); + } + + readTeamsOptions(userId) { + return this.http.options(`${this.baseUrl}${userId}/teams/`); + } + + readTokens(userId, params) { + return this.http.get(`${this.baseUrl}${userId}/tokens/`, { + params, + }); + } + + readAdminOfOrganizations(userId, params) { + return this.http.get(`${this.baseUrl}${userId}/admin_of_organizations/`, { + params, + }); + } + + readTokenOptions(userId) { + return this.http.options(`${this.baseUrl}${userId}/tokens/`); + } +} + +export default Users; diff --git a/awx/ui_next/src/api/models/Users.test.jsx b/awx/ui_next/src/api/models/Users.test.jsx new file mode 100644 index 000000000000..6eb662f4d7a5 --- /dev/null +++ b/awx/ui_next/src/api/models/Users.test.jsx @@ -0,0 +1,40 @@ +import Users from './Users'; + +describe('UsersAPI', () => { + const userId = 1; + const roleId = 7; + const createPromise = () => Promise.resolve(); + const mockHttp = { post: jest.fn(createPromise) }; + + const UsersAPI = new Users(mockHttp); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('associate role calls post with expected params', async done => { + await UsersAPI.associateRole(userId, roleId); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect( + mockHttp.post.mock.calls[0] + ).toContainEqual(`/api/v2/users/${userId}/roles/`, { id: roleId }); + + done(); + }); + + test('read users calls post with expected params', async done => { + await UsersAPI.disassociateRole(userId, roleId); + + expect(mockHttp.post).toHaveBeenCalledTimes(1); + expect(mockHttp.post.mock.calls[0]).toContainEqual( + `/api/v2/users/${userId}/roles/`, + { + id: roleId, + disassociate: true, + } + ); + + done(); + }); +}); diff --git a/awx/ui_next/src/api/models/WorkflowApprovalTemplates.js b/awx/ui_next/src/api/models/WorkflowApprovalTemplates.js new file mode 100644 index 000000000000..83b14784ab74 --- /dev/null +++ b/awx/ui_next/src/api/models/WorkflowApprovalTemplates.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class WorkflowApprovalTemplates extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/workflow_approval_templates/'; + } +} + +export default WorkflowApprovalTemplates; diff --git a/awx/ui_next/src/api/models/WorkflowApprovals.js b/awx/ui_next/src/api/models/WorkflowApprovals.js new file mode 100644 index 000000000000..4674d338c56a --- /dev/null +++ b/awx/ui_next/src/api/models/WorkflowApprovals.js @@ -0,0 +1,18 @@ +import Base from '../Base'; + +class WorkflowApprovals extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/workflow_approvals/'; + } + + approve(id) { + return this.http.post(`${this.baseUrl}${id}/approve/`); + } + + deny(id) { + return this.http.post(`${this.baseUrl}${id}/deny/`); + } +} + +export default WorkflowApprovals; diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplateNodes.js b/awx/ui_next/src/api/models/WorkflowJobTemplateNodes.js new file mode 100644 index 000000000000..b628312d0389 --- /dev/null +++ b/awx/ui_next/src/api/models/WorkflowJobTemplateNodes.js @@ -0,0 +1,73 @@ +import Base from '../Base'; + +class WorkflowJobTemplateNodes extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/workflow_job_template_nodes/'; + } + + createApprovalTemplate(id, data) { + return this.http.post( + `${this.baseUrl}${id}/create_approval_template/`, + data + ); + } + + associateSuccessNode(id, idToAssociate) { + return this.http.post(`${this.baseUrl}${id}/success_nodes/`, { + id: idToAssociate, + }); + } + + associateFailureNode(id, idToAssociate) { + return this.http.post(`${this.baseUrl}${id}/failure_nodes/`, { + id: idToAssociate, + }); + } + + associateAlwaysNode(id, idToAssociate) { + return this.http.post(`${this.baseUrl}${id}/always_nodes/`, { + id: idToAssociate, + }); + } + + disassociateSuccessNode(id, idToDissociate) { + return this.http.post(`${this.baseUrl}${id}/success_nodes/`, { + id: idToDissociate, + disassociate: true, + }); + } + + disassociateFailuresNode(id, idToDissociate) { + return this.http.post(`${this.baseUrl}${id}/failure_nodes/`, { + id: idToDissociate, + disassociate: true, + }); + } + + disassociateAlwaysNode(id, idToDissociate) { + return this.http.post(`${this.baseUrl}${id}/always_nodes/`, { + id: idToDissociate, + disassociate: true, + }); + } + + readCredentials(id) { + return this.http.get(`${this.baseUrl}${id}/credentials/`); + } + + associateCredentials(id, credentialId) { + return this.http.post(`${this.baseUrl}${id}/credentials/`, { + id: credentialId, + }); + } + + disassociateCredentials(id, credentialId) { + return this.http.post(`${this.baseUrl}${id}/credentials/`, { + id: credentialId, + disassociate: true, + }); + } +} + +export default WorkflowJobTemplateNodes; diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplates.js b/awx/ui_next/src/api/models/WorkflowJobTemplates.js new file mode 100644 index 000000000000..beed5be9ad97 --- /dev/null +++ b/awx/ui_next/src/api/models/WorkflowJobTemplates.js @@ -0,0 +1,106 @@ +import Base from '../Base'; +import SchedulesMixin from '../mixins/Schedules.mixin'; +import NotificationsMixin from '../mixins/Notifications.mixin'; + +class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/workflow_job_templates/'; + } + + readWebhookKey(id) { + return this.http.get(`${this.baseUrl}${id}/webhook_key/`); + } + + readWorkflowJobTemplateOptions(id) { + return this.http.options(`${this.baseUrl}${id}/`); + } + + updateWebhookKey(id) { + return this.http.post(`${this.baseUrl}${id}/webhook_key/`); + } + + associateLabel(id, label, orgId) { + return this.http.post(`${this.baseUrl}${id}/labels/`, { + name: label.name, + organization: orgId, + }); + } + + createNode(id, data) { + return this.http.post(`${this.baseUrl}${id}/workflow_nodes/`, data); + } + + disassociateLabel(id, label) { + return this.http.post(`${this.baseUrl}${id}/labels/`, { + id: label.id, + disassociate: true, + }); + } + + launch(id, data) { + return this.http.post(`${this.baseUrl}${id}/launch/`, data); + } + + readLaunch(id) { + return this.http.get(`${this.baseUrl}${id}/launch/`); + } + + readNodes(id, params) { + return this.http.get(`${this.baseUrl}${id}/workflow_nodes/`, { + params, + }); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { + params, + }); + } + + readAccessOptions(id) { + return this.http.options(`${this.baseUrl}${id}/access_list/`); + } + + readSurvey(id) { + return this.http.get(`${this.baseUrl}${id}/survey_spec/`); + } + + updateSurvey(id, survey) { + return this.http.post(`${this.baseUrl}${id}/survey_spec/`, survey); + } + + destroySurvey(id) { + return this.http.delete(`${this.baseUrl}${id}/survey_spec/`); + } + + readNotificationTemplatesApprovals(id, params) { + return this.http.get( + `${this.baseUrl}${id}/notification_templates_approvals/`, + { + params, + } + ); + } + + associateNotificationTemplatesApprovals(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_approvals/`, + { + id: notificationId, + } + ); + } + + disassociateNotificationTemplatesApprovals(resourceId, notificationId) { + return this.http.post( + `${this.baseUrl}${resourceId}/notification_templates_approvals/`, + { + id: notificationId, + disassociate: true, + } + ); + } +} + +export default WorkflowJobTemplates; diff --git a/awx/ui_next/src/api/models/WorkflowJobs.js b/awx/ui_next/src/api/models/WorkflowJobs.js new file mode 100644 index 000000000000..87e336e8f56b --- /dev/null +++ b/awx/ui_next/src/api/models/WorkflowJobs.js @@ -0,0 +1,15 @@ +import Base from '../Base'; +import RelaunchMixin from '../mixins/Relaunch.mixin'; + +class WorkflowJobs extends RelaunchMixin(Base) { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/workflow_jobs/'; + } + + readNodes(id, params) { + return this.http.get(`${this.baseUrl}${id}/workflow_nodes/`, { params }); + } +} + +export default WorkflowJobs; diff --git a/awx/ui_next/src/components/About/About.jsx b/awx/ui_next/src/components/About/About.jsx new file mode 100644 index 000000000000..f68f75b61305 --- /dev/null +++ b/awx/ui_next/src/components/About/About.jsx @@ -0,0 +1,80 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { + AboutModal, + TextContent, + TextList, + TextListItem, +} from '@patternfly/react-core'; + +import { BrandName } from '../../variables'; +import brandLogoImg from './brand-logo.svg'; + +function About({ ansible_version, version, isOpen, onClose, i18n }) { + const createSpeechBubble = () => { + let text = `${BrandName} ${version}`; + let top = ''; + let bottom = ''; + + for (let i = 0; i < text.length; i++) { + top += '_'; + bottom += '-'; + } + + top = ` __${top}__ \n`; + text = `< ${text} >\n`; + bottom = ` --${bottom}-- `; + + return top + text + bottom; + }; + + const speechBubble = createSpeechBubble(); + + return ( + +
+        {speechBubble}
+        {`
+          \\
+          \\   ^__^
+              (oo)\\_______
+              (__)      A )\\
+                  ||----w |
+                  ||     ||
+                    `}
+      
+ + + + {i18n._(t`Ansible Version`)} + + {ansible_version} + + +
+ ); +} + +About.propTypes = { + ansible_version: PropTypes.string, + isOpen: PropTypes.bool, + onClose: PropTypes.func.isRequired, + version: PropTypes.string, +}; + +About.defaultProps = { + ansible_version: null, + isOpen: false, + version: null, +}; + +export default withI18n()(About); diff --git a/awx/ui_next/src/components/About/About.test.jsx b/awx/ui_next/src/components/About/About.test.jsx new file mode 100644 index 000000000000..caed85e454be --- /dev/null +++ b/awx/ui_next/src/components/About/About.test.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import About from './About'; + +describe('', () => { + let aboutWrapper; + let closeButton; + const onClose = jest.fn(); + test('initially renders without crashing', () => { + aboutWrapper = mountWithContexts(); + expect(aboutWrapper.length).toBe(1); + aboutWrapper.unmount(); + }); + + test('close button calls onClose handler', () => { + aboutWrapper = mountWithContexts(); + closeButton = aboutWrapper.find('AboutModalBoxCloseButton Button'); + closeButton.simulate('click'); + expect(onClose).toBeCalled(); + aboutWrapper.unmount(); + }); +}); diff --git a/awx/ui/client/assets/logo-header.svg b/awx/ui_next/src/components/About/brand-logo.svg similarity index 100% rename from awx/ui/client/assets/logo-header.svg rename to awx/ui_next/src/components/About/brand-logo.svg diff --git a/awx/ui_next/src/components/About/index.js b/awx/ui_next/src/components/About/index.js new file mode 100644 index 000000000000..1ef71b80e713 --- /dev/null +++ b/awx/ui_next/src/components/About/index.js @@ -0,0 +1 @@ +export { default } from './About'; diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx new file mode 100644 index 000000000000..89387b9e8b51 --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx @@ -0,0 +1,160 @@ +import React, { useCallback, useEffect, useState, useContext } from 'react'; +import { useHistory, useParams } from 'react-router-dom'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import PropTypes from 'prop-types'; +import { Button, DropdownItem } from '@patternfly/react-core'; + +import useRequest, { useDismissableError } from '../../util/useRequest'; +import { InventoriesAPI, CredentialTypesAPI } from '../../api'; + +import AlertModal from '../AlertModal'; +import ErrorDetail from '../ErrorDetail'; +import AdHocCommandsWizard from './AdHocCommandsWizard'; +import { KebabifiedContext } from '../../contexts/Kebabified'; +import ContentLoading from '../ContentLoading'; +import ContentError from '../ContentError'; + +function AdHocCommands({ adHocItems, i18n, hasListItems }) { + const history = useHistory(); + const { id } = useParams(); + + const [isWizardOpen, setIsWizardOpen] = useState(false); + const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext); + + const verbosityOptions = [ + { value: '0', key: '0', label: i18n._(t`0 (Normal)`) }, + { value: '1', key: '1', label: i18n._(t`1 (Verbose)`) }, + { value: '2', key: '2', label: i18n._(t`2 (More Verbose)`) }, + { value: '3', key: '3', label: i18n._(t`3 (Debug)`) }, + { value: '4', key: '4', label: i18n._(t`4 (Connection Debug)`) }, + ]; + useEffect(() => { + if (isKebabified) { + onKebabModalChange(isWizardOpen); + } + }, [isKebabified, isWizardOpen, onKebabModalChange]); + + const { + result: { moduleOptions, credentialTypeId, isAdHocDisabled }, + request: fetchData, + error: fetchError, + } = useRequest( + useCallback(async () => { + const [options, cred] = await Promise.all([ + InventoriesAPI.readAdHocOptions(id), + CredentialTypesAPI.read({ namespace: 'ssh' }), + ]); + return { + moduleOptions: options.data.actions.GET.module_name.choices, + credentialTypeId: cred.data.results[0].id, + isAdHocDisabled: !options.data.actions.POST, + }; + }, [id]), + { moduleOptions: [], isAdHocDisabled: true } + ); + useEffect(() => { + fetchData(); + }, [fetchData]); + const { + isLoading: isLaunchLoading, + error: launchError, + request: launchAdHocCommands, + } = useRequest( + useCallback( + async values => { + const { data } = await InventoriesAPI.launchAdHocCommands(id, values); + history.push(`/jobs/command/${data.id}/output`); + }, + + [id, history] + ) + ); + + const { error, dismissError } = useDismissableError( + launchError || fetchError + ); + + const handleSubmit = async values => { + const { credential, ...remainingValues } = values; + const newCredential = credential[0].id; + + const manipulatedValues = { + credential: newCredential, + ...remainingValues, + }; + await launchAdHocCommands(manipulatedValues); + }; + + if (isLaunchLoading) { + return ; + } + + if (error && isWizardOpen) { + return ( + { + dismissError(); + setIsWizardOpen(false); + }} + > + {launchError ? ( + <> + {i18n._(t`Failed to launch job.`)} + + + ) : ( + + )} + + ); + } + return ( + // render buttons for drop down and for toolbar + // if modal is open render the modal + <> + {isKebabified ? ( + setIsWizardOpen(true)} + > + {i18n._(t`Run Command`)} + + ) : ( + + )} + + {isWizardOpen && ( + setIsWizardOpen(false)} + onLaunch={handleSubmit} + onDismissError={() => dismissError()} + /> + )} + + ); +} + +AdHocCommands.propTypes = { + adHocItems: PropTypes.arrayOf(PropTypes.object).isRequired, + hasListItems: PropTypes.bool.isRequired, +}; + +export default withI18n()(AdHocCommands); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommands.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.test.jsx new file mode 100644 index 000000000000..2cbe7250f0a0 --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.test.jsx @@ -0,0 +1,345 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import { CredentialTypesAPI, InventoriesAPI, CredentialsAPI } from '../../api'; +import AdHocCommands from './AdHocCommands'; + +jest.mock('../../api/models/CredentialTypes'); +jest.mock('../../api/models/Inventories'); +jest.mock('../../api/models/Credentials'); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ + id: 1, + }), +})); +const credentials = [ + { id: 1, kind: 'cloud', name: 'Cred 1', url: 'www.google.com' }, + { id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com' }, + { id: 3, kind: 'Ansible', name: 'Cred 3', url: 'www.google.com' }, + { id: 4, kind: 'Machine', name: 'Cred 4', url: 'www.google.com' }, + { id: 5, kind: 'Machine', name: 'Cred 5', url: 'www.google.com' }, +]; + +const adHocItems = [ + { + name: 'Inventory 1 Org 0', + }, + { name: 'Inventory 2 Org 0' }, +]; + +describe('', () => { + beforeEach(() => { + InventoriesAPI.readAdHocOptions.mockResolvedValue({ + data: { + actions: { + GET: { + module_name: { + choices: [ + ['command', 'command'], + ['shell', 'shell'], + ], + }, + }, + POST: {}, + }, + }, + }); + CredentialTypesAPI.read.mockResolvedValue({ + data: { count: 1, results: [{ id: 1, name: 'cred' }] }, + }); + }); + let wrapper; + afterEach(() => { + wrapper.unmount(); + jest.clearAllMocks(); + }); + + test('mounts successfully', async () => { + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + expect(wrapper.find('AdHocCommands').length).toBe(1); + }); + + test('should open the wizard', async () => { + InventoriesAPI.readAdHocOptions.mockResolvedValue({ + data: { + actions: { + GET: { + module_name: { + choices: [ + ['command', 'command'], + ['foo', 'foo'], + ], + }, + verbosity: { choices: [[1], [2]] }, + }, + }, + }, + }); + CredentialTypesAPI.read.mockResolvedValue({ + data: { results: [{ id: 1 }] }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await act(async () => + wrapper.find('button[aria-label="Run Command"]').prop('onClick')() + ); + + wrapper.update(); + + expect(wrapper.find('AdHocCommandsWizard').length).toBe(1); + }); + + test('should submit properly', async () => { + InventoriesAPI.launchAdHocCommands.mockResolvedValue({ data: { id: 1 } }); + CredentialsAPI.read.mockResolvedValue({ + data: { + results: credentials, + count: 5, + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + + await act(async () => + wrapper.find('button[aria-label="Run Command"]').prop('onClick')() + ); + wrapper.update(); + + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); + + expect( + wrapper + .find('WizardNavItem[content="Machine credential"]') + .prop('isDisabled') + ).toBe(true); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + }); + + wrapper.update(); + + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0); + // second step of wizard + + await act(async () => { + wrapper + .find('input[aria-labelledby="check-action-item-4"]') + .simulate('change', { target: { checked: true } }); + }); + + wrapper.update(); + + expect( + wrapper.find('CheckboxListItem[label="Cred 4"]').prop('isSelected') + ).toBe(true); + + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + expect(InventoriesAPI.launchAdHocCommands).toBeCalledWith(1, { + module_args: 'foo', + diff_mode: false, + credential: 4, + job_type: 'run', + become_enabled: '', + extra_vars: '---', + forks: 0, + limit: 'Inventory 1 Org 0, Inventory 2 Org 0', + module_name: 'command', + verbosity: 1, + }); + }); + + test('should throw error on submission properly', async () => { + InventoriesAPI.launchAdHocCommands.mockRejectedValue( + new Error({ + response: { + config: { + method: 'post', + url: '/api/v2/inventories/1/ad_hoc_commands', + }, + data: 'An error occurred', + status: 403, + }, + }) + ); + InventoriesAPI.readAdHocOptions.mockResolvedValue({ + data: { + actions: { + GET: { + module_name: { + choices: [ + ['command', 'command'], + ['foo', 'foo'], + ], + }, + verbosity: { choices: [[1], [2]] }, + }, + }, + }, + }); + CredentialTypesAPI.read.mockResolvedValue({ + data: { results: [{ id: 1 }] }, + }); + CredentialsAPI.read.mockResolvedValue({ + data: { + results: credentials, + count: 5, + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + + await act(async () => + wrapper.find('button[aria-label="Run Command"]').prop('onClick')() + ); + wrapper.update(); + + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); + expect( + wrapper + .find('WizardNavItem[content="Machine credential"]') + .prop('isDisabled') + ).toBe(true); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + }); + + wrapper.update(); + + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0); + + // second step of wizard + + await act(async () => { + wrapper + .find('input[aria-labelledby="check-action-item-4"]') + .simulate('change', { target: { checked: true } }); + }); + + wrapper.update(); + + expect( + wrapper.find('CheckboxListItem[label="Cred 4"]').prop('isSelected') + ).toBe(true); + + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + await waitForElement(wrapper, 'ErrorDetail', el => el.length > 0); + }); + + test('should disable run command button due to permissions', async () => { + InventoriesAPI.readHosts.mockResolvedValue({ + data: { results: [], count: 0 }, + }); + InventoriesAPI.readAdHocOptions.mockResolvedValue({ + data: { + actions: { + GET: { module_name: { choices: [['module']] } }, + }, + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); + const runCommandsButton = wrapper.find('button[aria-label="Run Command"]'); + expect(runCommandsButton.prop('disabled')).toBe(true); + }); + + test('should disable run command button due to lack of list items', async () => { + InventoriesAPI.readHosts.mockResolvedValue({ + data: { results: [], count: 0 }, + }); + InventoriesAPI.readAdHocOptions.mockResolvedValue({ + data: { + actions: { + GET: { module_name: { choices: [['module']] } }, + }, + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); + const runCommandsButton = wrapper.find('button[aria-label="Run Command"]'); + expect(runCommandsButton.prop('disabled')).toBe(true); + }); + + test('should open alert modal when error on fetching data', async () => { + InventoriesAPI.readAdHocOptions.mockRejectedValue( + new Error({ + response: { + config: { + method: 'options', + url: '/api/v2/inventories/1/', + }, + data: 'An error occurred', + status: 403, + }, + }) + ); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await act(async () => wrapper.find('button').prop('onClick')()); + wrapper.update(); + expect(wrapper.find('ErrorDetail').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.jsx new file mode 100644 index 000000000000..865564ba9263 --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.jsx @@ -0,0 +1,142 @@ +import React, { useState } from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { ExclamationCircleIcon as PFExclamationCircleIcon } from '@patternfly/react-icons'; +import { Tooltip } from '@patternfly/react-core'; +import { withFormik, useFormikContext } from 'formik'; +import PropTypes from 'prop-types'; + +import styled from 'styled-components'; +import Wizard from '../Wizard'; +import AdHocCredentialStep from './AdHocCredentialStep'; +import AdHocDetailsStep from './AdHocDetailsStep'; + +const AlertText = styled.div` + color: var(--pf-global--danger-color--200); + font-weight: var(--pf-global--FontWeight--bold); +`; + +const ExclamationCircleIcon = styled(PFExclamationCircleIcon)` + margin-left: 10px; + color: var(--pf-global--danger-color--100); +`; + +function AdHocCommandsWizard({ + onLaunch, + i18n, + moduleOptions, + verbosityOptions, + onCloseWizard, + credentialTypeId, +}) { + const [currentStepId, setCurrentStepId] = useState(1); + const [enableLaunch, setEnableLaunch] = useState(false); + + const { values, errors, touched } = useFormikContext(); + + const enabledNextOnDetailsStep = () => { + if (!values.module_name) { + return false; + } + + if (values.module_name === 'shell' || values.module_name === 'command') { + if (values.module_args) { + return true; + // eslint-disable-next-line no-else-return + } else { + return false; + } + } + return undefined; // makes the linter happy; + }; + const hasDetailsStepError = errors.module_args && touched.module_args; + + const steps = [ + { + id: 1, + key: 1, + name: hasDetailsStepError ? ( + + {i18n._(t`Details`)} + + + + + ) : ( + i18n._(t`Details`) + ), + component: ( + + ), + enableNext: enabledNextOnDetailsStep(), + nextButtonText: i18n._(t`Next`), + }, + { + id: 2, + key: 2, + name: i18n._(t`Machine credential`), + component: ( + setEnableLaunch(true)} + /> + ), + enableNext: enableLaunch && Object.values(errors).length === 0, + nextButtonText: i18n._(t`Launch`), + canJumpTo: currentStepId >= 2, + }, + ]; + + const currentStep = steps.find(step => step.id === currentStepId); + + return ( + setCurrentStepId(step.id)} + onClose={() => onCloseWizard()} + onSave={() => { + onLaunch(values); + }} + steps={steps} + title={i18n._(t`Run command`)} + nextButtonText={currentStep.nextButtonText || undefined} + backButtonText={i18n._(t`Back`)} + cancelButtonText={i18n._(t`Cancel`)} + /> + ); +} + +const FormikApp = withFormik({ + mapPropsToValues({ adHocItems, verbosityOptions }) { + const adHocItemStrings = adHocItems.map(item => item.name).join(', '); + return { + limit: adHocItemStrings || 'all', + credential: [], + module_args: '', + verbosity: verbosityOptions[0].value, + forks: 0, + diff_mode: false, + become_enabled: '', + module_name: '', + extra_vars: '---', + job_type: 'run', + }; + }, +})(AdHocCommandsWizard); + +FormikApp.propTypes = { + onLaunch: PropTypes.func.isRequired, + moduleOptions: PropTypes.arrayOf(PropTypes.array).isRequired, + verbosityOptions: PropTypes.arrayOf(PropTypes.object).isRequired, + onCloseWizard: PropTypes.func.isRequired, + credentialTypeId: PropTypes.number.isRequired, +}; +export default withI18n()(FormikApp); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx new file mode 100644 index 000000000000..fa2575fd8bec --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx @@ -0,0 +1,207 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import { CredentialsAPI } from '../../api'; +import AdHocCommandsWizard from './AdHocCommandsWizard'; + +jest.mock('../../api/models/CredentialTypes'); +jest.mock('../../api/models/Inventories'); +jest.mock('../../api/models/Credentials'); +const verbosityOptions = [ + { value: '0', key: '0', label: '0 (Normal)' }, + { value: '1', key: '1', label: '1 (Verbose)' }, + { value: '2', key: '2', label: '2 (More Verbose)' }, + { value: '3', key: '3', label: '3 (Debug)' }, + { value: '4', key: '4', label: '4 (Connection Debug)' }, +]; +const moduleOptions = [ + ['command', 'command'], + ['shell', 'shell'], +]; +const adHocItems = [ + { name: 'Inventory 1' }, + { name: 'Inventory 2' }, + { name: 'inventory 3' }, +]; +describe('', () => { + let wrapper; + const onLaunch = jest.fn(); + beforeEach(async () => { + await act(async () => { + wrapper = mountWithContexts( + {}} + credentialTypeId={1} + /> + ); + }); + }); + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('should mount properly', async () => { + expect(wrapper.find('AdHocCommandsWizard').length).toBe(1); + }); + + test('next and nav item should be disabled', async () => { + await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0); + expect( + wrapper.find('WizardNavItem[content="Details"]').prop('isCurrent') + ).toBe(true); + expect( + wrapper.find('WizardNavItem[content="Details"]').prop('isDisabled') + ).toBe(false); + expect( + wrapper + .find('WizardNavItem[content="Machine credential"]') + .prop('isDisabled') + ).toBe(true); + expect( + wrapper + .find('WizardNavItem[content="Machine credential"]') + .prop('isCurrent') + ).toBe(false); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); + }); + + test('next button should become active, and should navigate to the next step', async () => { + await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + }); + wrapper.update(); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + wrapper.update(); + }); + test('launch button should become active', async () => { + CredentialsAPI.read.mockResolvedValue({ + data: { + results: [ + { id: 1, name: 'Cred 1', url: '' }, + { id: 2, name: 'Cred2', url: '' }, + ], + count: 2, + }, + }); + await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + }); + wrapper.update(); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + wrapper.update(); + await waitForElement(wrapper, 'OptionsList', el => el.length > 0); + expect(wrapper.find('CheckboxListItem').length).toBe(2); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); + + await act(async () => { + wrapper + .find('input[aria-labelledby="check-action-item-1"]') + .simulate('change', { target: { checked: true } }); + }); + + wrapper.update(); + + expect( + wrapper.find('CheckboxListItem[label="Cred 1"]').prop('isSelected') + ).toBe(true); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + expect(onLaunch).toHaveBeenCalled(); + }); + test('should show error in navigation bar', async () => { + await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: '', name: 'module_args' }, + }); + }); + waitForElement(wrapper, 'ExclamationCircleIcon', el => el.length > 0); + }); + + test('expect credential step to throw error', async () => { + CredentialsAPI.read.mockRejectedValue( + new Error({ + response: { + config: { + method: 'get', + url: '/api/v2/credentals', + }, + data: 'An error occurred', + status: 403, + }, + }) + ); + await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + }); + wrapper.update(); + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( + false + ); + + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + + wrapper.update(); + expect(wrapper.find('ContentError').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx new file mode 100644 index 000000000000..e95f0b05cbcc --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx @@ -0,0 +1,128 @@ +import React, { useEffect, useCallback } from 'react'; +import { useHistory } from 'react-router-dom'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import PropTypes from 'prop-types'; +import { useField } from 'formik'; +import { Form, FormGroup } from '@patternfly/react-core'; +import { CredentialsAPI } from '../../api'; +import Popover from '../Popover'; + +import { getQSConfig, parseQueryString, mergeParams } from '../../util/qs'; +import useRequest from '../../util/useRequest'; +import ContentError from '../ContentError'; +import ContentLoading from '../ContentLoading'; +import { required } from '../../util/validators'; +import OptionsList from '../OptionsList'; + +const QS_CONFIG = getQSConfig('credentials', { + page: 1, + page_size: 5, + order_by: 'name', +}); + +function AdHocCredentialStep({ i18n, credentialTypeId, onEnableLaunch }) { + const history = useHistory(); + const { + error, + isLoading, + request: fetchCredentials, + result: { credentials, credentialCount }, + } = useRequest( + useCallback(async () => { + const params = parseQueryString(QS_CONFIG, history.location.search); + + const { + data: { results, count }, + } = await CredentialsAPI.read( + mergeParams(params, { credential_type: credentialTypeId }) + ); + + return { + credentials: results, + credentialCount: count, + }; + }, [credentialTypeId, history.location.search]), + { credentials: [], credentialCount: 0 } + ); + + useEffect(() => { + fetchCredentials(); + }, [fetchCredentials]); + + const [credentialField, credentialMeta, credentialHelpers] = useField({ + name: 'credential', + validate: required(null, i18n), + }); + if (error) { + return ; + } + if (isLoading) { + return ; + } + return ( +
+ + } + > + { + credentialHelpers.setValue([value]); + onEnableLaunch(); + }} + deselectItem={() => { + credentialHelpers.setValue([]); + }} + /> + +
+ ); +} + +AdHocCredentialStep.propTypes = { + credentialTypeId: PropTypes.number.isRequired, + onEnableLaunch: PropTypes.func.isRequired, +}; +export default withI18n()(AdHocCredentialStep); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.test.jsx new file mode 100644 index 000000000000..873b792278f1 --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.test.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { Formik } from 'formik'; +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import { CredentialsAPI } from '../../api'; +import AdHocCredentialStep from './AdHocCredentialStep'; + +jest.mock('../../api/models/Credentials'); + +describe('', () => { + const onEnableLaunch = jest.fn(); + let wrapper; + beforeEach(async () => { + CredentialsAPI.read.mockResolvedValue({ + data: { + results: [ + { id: 1, name: 'Cred 1', url: 'wwww.google.com' }, + { id: 2, name: 'Cred2', url: 'wwww.google.com' }, + ], + count: 2, + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + }); + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('should mount properly', async () => { + await waitForElement(wrapper, 'OptionsList', el => el.length > 0); + }); + + test('should call api', async () => { + await waitForElement(wrapper, 'OptionsList', el => el.length > 0); + expect(CredentialsAPI.read).toHaveBeenCalled(); + expect(wrapper.find('CheckboxListItem').length).toBe(2); + }); +}); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.jsx new file mode 100644 index 000000000000..46a3617d7e68 --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.jsx @@ -0,0 +1,323 @@ +/* eslint-disable react/no-unescaped-entities */ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import PropTypes from 'prop-types'; +import { useField } from 'formik'; +import { Form, FormGroup, Switch, Checkbox } from '@patternfly/react-core'; +import styled from 'styled-components'; + +import { BrandName } from '../../variables'; +import AnsibleSelect from '../AnsibleSelect'; +import FormField from '../FormField'; +import { VariablesField } from '../CodeMirrorInput'; +import { + FormColumnLayout, + FormFullWidthLayout, + FormCheckboxLayout, +} from '../FormLayout'; +import Popover from '../Popover'; +import { required } from '../../util/validators'; + +const TooltipWrapper = styled.div` + text-align: left; +`; + +// Setting BrandName to a variable here is necessary to get the jest tests +// passing. Attempting to use BrandName in the template literal results +// in failing tests. +const brandName = BrandName; + +function AdHocDetailsStep({ i18n, verbosityOptions, moduleOptions }) { + const [moduleNameField, moduleNameMeta, moduleNameHelpers] = useField({ + name: 'module_name', + validate: required(null, i18n), + }); + + const [variablesField] = useField('extra_vars'); + const [diffModeField, , diffModeHelpers] = useField('diff_mode'); + const [becomeEnabledField, , becomeEnabledHelpers] = useField( + 'become_enabled' + ); + const [verbosityField, verbosityMeta, verbosityHelpers] = useField({ + name: 'verbosity', + validate: required(null, i18n), + }); + + const argumentsRequired = + moduleNameField.value === 'command' || moduleNameField.value === 'shell'; + const [, argumentsMeta, argumentsHelpers] = useField({ + name: 'module_args', + validate: argumentsRequired && required(null, i18n), + }); + + const isValid = !argumentsMeta.error || !argumentsMeta.touched; + + return ( +
+ + + + } + > + ({ + value: value[0], + label: value[0], + key: value[0], + })), + ]} + onChange={(event, value) => { + if (value !== 'command' && value !== 'shell') { + argumentsHelpers.setTouched(false); + } + moduleNameHelpers.setValue(value); + }} + /> + + argumentsHelpers.setTouched(true)} + isRequired={ + moduleNameField.value === 'command' || + moduleNameField.value === 'shell' + } + tooltip={ + moduleNameField.value ? ( + <> + {i18n._( + t`These arguments are used with the specified module. You can find information about ${moduleNameField.value} by clicking ` + )} + + {' '} + {i18n._(t`here.`)} + + + ) : ( + i18n._(t`These arguments are used with the specified module.`) + ) + } + /> + + } + > + { + verbosityHelpers.setValue(parseInt(value, 10)); + }} + /> + + + {i18n._( + t`The pattern used to target hosts in the inventory. Leaving the field blank, all, and * will all target all hosts in the inventory. You can find more information about Ansible's host patterns` + )}{' '} + + {i18n._(t`here`)} + + + } + /> + + {i18n._( + t`The number of parallel or simultaneous processes to use while executing the playbook. Inputting no value will use the default value from the ansible configuration file. You can find more information` + )}{' '} + + {i18n._(t`here.`)} + + + } + /> + + + } + > + { + diffModeHelpers.setValue(!diffModeField.value); + }} + aria-label={i18n._(t`toggle changes`)} + /> + + + + + {i18n._(t`Enable privilege escalation`)} +   + + {i18n._(t`Enables creation of a provisioning + callback URL. Using the URL a host can contact ${brandName} + and request a configuration update using this job + template`)} +   + --become + {i18n._(t`option to the`)}   + ansible + {i18n._(t`command`)} +

+ } + /> + + } + id="become_enabled" + isChecked={becomeEnabledField.value} + onChange={checked => { + becomeEnabledHelpers.setValue(checked); + }} + /> +
+
+
+ + +

+ {i18n._( + t`Pass extra command line changes. There are two ansible command line parameters: ` + )} +
+ -e, --extra-vars +
+ {i18n._(t`Provide key/value pairs using either + YAML or JSON.`)} +

+ JSON: +
+ +
+                    {'{'}
+                    {'\n  '}"somevar": "somevalue",
+                    {'\n  '}"password": "magic"
+                    {'\n'}
+                    {'}'}
+                  
+
+ YAML: +
+ +
+                    ---
+                    {'\n'}somevar: somevalue
+                    {'\n'}password: magic
+                  
+
+ + } + label={i18n._(t`Extra variables`)} + aria-label={i18n._(t`Extra variables`)} + /> +
+
+
+ ); +} + +AdHocDetailsStep.propTypes = { + moduleOptions: PropTypes.arrayOf(PropTypes.array).isRequired, + verbosityOptions: PropTypes.arrayOf(PropTypes.object).isRequired, +}; + +export default withI18n()(AdHocDetailsStep); diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx new file mode 100644 index 000000000000..4b621b8e5f4a --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx @@ -0,0 +1,134 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { Formik } from 'formik'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import DetailsStep from './AdHocDetailsStep'; + +jest.mock('../../api/models/Credentials'); + +const verbosityOptions = [ + { key: -1, value: '', label: '', isDisabled: false }, + { key: 0, value: 0, label: '0', isDisabled: false }, + { key: 1, value: 1, label: '1', isDisabled: false }, +]; +const moduleOptions = [ + ['command', 'command'], + ['shell', 'shell'], +]; +const onLimitChange = jest.fn(); +const initialValues = { + limit: ['Inventory 1', 'inventory 2'], + credential: [], + module_args: '', + arguments: '', + verbosity: '', + forks: 0, + changes: false, + escalation: false, + extra_vars: '---', + module_name: 'shell', +}; + +describe('', () => { + let wrapper; + + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('should mount properly', async () => { + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + }); + + test('should show all the fields', async () => { + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + expect(wrapper.find('FormGroup[label="Module"]').length).toBe(1); + expect(wrapper.find('FormField[label="Arguments"]').length).toBe(1); + expect(wrapper.find('FormGroup[label="Verbosity"]').length).toBe(1); + expect(wrapper.find('FormField[label="Limit"]').length).toBe(1); + expect(wrapper.find('FormField[name="forks"]').length).toBe(1); + expect(wrapper.find('FormGroup[label="Show changes"]').length).toBe(1); + expect(wrapper.find('FormGroup[name="become_enabled"]').length).toBe(1); + expect(wrapper.find('VariablesField').length).toBe(1); + }); + + test('shold update form values', async () => { + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + + await act(async () => { + wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( + {}, + 'command' + ); + wrapper.find('input#module_args').simulate('change', { + target: { value: 'foo', name: 'module_args' }, + }); + wrapper.find('input#limit').simulate('change', { + target: { + value: 'Inventory 1, inventory 2, new inventory', + name: 'limit', + }, + }); + wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); + + wrapper.find('TextInputBase[name="forks"]').simulate('change', { + target: { value: 10, name: 'forks' }, + }); + wrapper.find('Switch').invoke('onChange')(); + wrapper + .find('Checkbox[aria-label="Enable privilege escalation"]') + .invoke('onChange')(true, { + currentTarget: { value: true, type: 'change', checked: true }, + }); + }); + wrapper.update(); + expect( + wrapper.find('AnsibleSelect[name="module_name"]').prop('value') + ).toBe('command'); + expect(wrapper.find('input#module_args').prop('value')).toBe('foo'); + expect(wrapper.find('AnsibleSelect[name="verbosity"]').prop('value')).toBe( + 1 + ); + expect(wrapper.find('TextInputBase[name="forks"]').prop('value')).toBe(10); + expect(wrapper.find('TextInputBase[name="limit"]').prop('value')).toBe( + 'Inventory 1, inventory 2, new inventory' + ); + expect(wrapper.find('Switch').prop('isChecked')).toBe(true); + expect( + wrapper + .find('Checkbox[aria-label="Enable privilege escalation"]') + .prop('isChecked') + ).toBe(true); + }); +}); diff --git a/awx/ui_next/src/components/AdHocCommands/index.js b/awx/ui_next/src/components/AdHocCommands/index.js new file mode 100644 index 000000000000..fa981f01e49b --- /dev/null +++ b/awx/ui_next/src/components/AdHocCommands/index.js @@ -0,0 +1 @@ +export { default } from './AdHocCommands'; diff --git a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx new file mode 100644 index 000000000000..c78bac17fb4a --- /dev/null +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx @@ -0,0 +1,55 @@ +import React, { useState, useRef, useEffect, Fragment } from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import PropTypes from 'prop-types'; +import { Dropdown, DropdownPosition } from '@patternfly/react-core'; +import { ToolbarAddButton } from '../PaginatedDataList'; +import { useKebabifiedMenu } from '../../contexts/Kebabified'; + +function AddDropDownButton({ dropdownItems, i18n }) { + const { isKebabified } = useKebabifiedMenu(); + const [isOpen, setIsOpen] = useState(false); + const element = useRef(null); + + useEffect(() => { + const toggle = e => { + if (!isKebabified && (!element || !element.current.contains(e.target))) { + setIsOpen(false); + } + }; + + document.addEventListener('click', toggle, false); + return () => { + document.removeEventListener('click', toggle); + }; + }, [isKebabified]); + + if (isKebabified) { + return {dropdownItems}; + } + + return ( +
+ setIsOpen(!isOpen)} + /> + } + dropdownItems={dropdownItems} + /> +
+ ); +} + +AddDropDownButton.propTypes = { + dropdownItems: PropTypes.arrayOf(PropTypes.element.isRequired).isRequired, +}; + +export { AddDropDownButton as _AddDropDownButton }; +export default withI18n()(AddDropDownButton); diff --git a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx new file mode 100644 index 000000000000..d1e16aaa223a --- /dev/null +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { DropdownItem } from '@patternfly/react-core'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import AddDropDownButton from './AddDropDownButton'; + +describe('', () => { + const dropdownItems = [ + Add, + Route, + ]; + test('should be closed initially', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false); + }); + + test('should render two links', () => { + const wrapper = mountWithContexts( + + ); + wrapper.find('button').simulate('click'); + expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); + expect(wrapper.find('DropdownItem')).toHaveLength(dropdownItems.length); + }); + + test('should close when button re-clicked', () => { + const wrapper = mountWithContexts( + + ); + wrapper.find('button').simulate('click'); + expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); + wrapper.find('button').simulate('click'); + expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false); + }); +}); diff --git a/awx/ui_next/src/components/AddDropDownButton/index.js b/awx/ui_next/src/components/AddDropDownButton/index.js new file mode 100644 index 000000000000..8c87c7df31db --- /dev/null +++ b/awx/ui_next/src/components/AddDropDownButton/index.js @@ -0,0 +1 @@ +export { default } from './AddDropDownButton'; diff --git a/awx/ui_next/src/components/AddRole/AddResourceRole.jsx b/awx/ui_next/src/components/AddRole/AddResourceRole.jsx new file mode 100644 index 000000000000..e339142b52e2 --- /dev/null +++ b/awx/ui_next/src/components/AddRole/AddResourceRole.jsx @@ -0,0 +1,294 @@ +import React, { Fragment, useState } from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import SelectableCard from '../SelectableCard'; +import Wizard from '../Wizard'; +import SelectResourceStep from './SelectResourceStep'; +import SelectRoleStep from './SelectRoleStep'; +import { TeamsAPI, UsersAPI } from '../../api'; + +const readUsers = async queryParams => + UsersAPI.read(Object.assign(queryParams, { is_superuser: false })); + +const readUsersOptions = async () => UsersAPI.readOptions(); + +const readTeams = async queryParams => TeamsAPI.read(queryParams); + +const readTeamsOptions = async () => TeamsAPI.readOptions(); + +function AddResourceRole({ onSave, onClose, roles, i18n, resource }) { + const [selectedResource, setSelectedResource] = useState(null); + const [selectedResourceRows, setSelectedResourceRows] = useState([]); + const [selectedRoleRows, setSelectedRoleRows] = useState([]); + const [currentStepId, setCurrentStepId] = useState(1); + const [maxEnabledStep, setMaxEnabledStep] = useState(1); + + const handleResourceCheckboxClick = user => { + const selectedIndex = selectedResourceRows.findIndex( + selectedRow => selectedRow.id === user.id + ); + if (selectedIndex > -1) { + selectedResourceRows.splice(selectedIndex, 1); + if (selectedResourceRows.length === 0) { + setMaxEnabledStep(currentStepId); + } + setSelectedRoleRows(selectedResourceRows); + } else { + setSelectedResourceRows([...selectedResourceRows, user]); + } + }; + + const handleRoleCheckboxClick = role => { + const selectedIndex = selectedRoleRows.findIndex( + selectedRow => selectedRow.id === role.id + ); + + if (selectedIndex > -1) { + selectedRoleRows.splice(selectedIndex, 1); + setSelectedRoleRows(selectedRoleRows); + } else { + setSelectedRoleRows([...selectedRoleRows, role]); + } + }; + + const handleResourceSelect = resourceType => { + setSelectedResource(resourceType); + setSelectedResourceRows([]); + setSelectedRoleRows([]); + }; + + const handleWizardNext = step => { + setCurrentStepId(step.id); + setMaxEnabledStep(step.id); + }; + + const handleWizardGoToStep = step => { + setCurrentStepId(step.id); + }; + + const handleWizardSave = async () => { + try { + const roleRequests = []; + + for (let i = 0; i < selectedResourceRows.length; i++) { + for (let j = 0; j < selectedRoleRows.length; j++) { + if (selectedResource === 'users') { + roleRequests.push( + UsersAPI.associateRole( + selectedResourceRows[i].id, + selectedRoleRows[j].id + ) + ); + } else if (selectedResource === 'teams') { + roleRequests.push( + TeamsAPI.associateRole( + selectedResourceRows[i].id, + selectedRoleRows[j].id + ) + ); + } + } + } + + await Promise.all(roleRequests); + onSave(); + } catch (err) { + // TODO: handle this error + } + }; + + // Object roles can be user only, so we remove them when + // showing role choices for team access + const selectableRoles = { ...roles }; + if (selectedResource === 'teams') { + Object.keys(roles).forEach(key => { + if (selectableRoles[key].user_only) { + delete selectableRoles[key]; + } + }); + } + + const userSearchColumns = [ + { + name: i18n._(t`Username`), + key: 'username__icontains', + isDefault: true, + }, + { + name: i18n._(t`First Name`), + key: 'first_name__icontains', + }, + { + name: i18n._(t`Last Name`), + key: 'last_name__icontains', + }, + ]; + const userSortColumns = [ + { + name: i18n._(t`Username`), + key: 'username', + }, + { + name: i18n._(t`First Name`), + key: 'first_name', + }, + { + name: i18n._(t`Last Name`), + key: 'last_name', + }, + ]; + const teamSearchColumns = [ + { + name: i18n._(t`Name`), + key: 'name', + isDefault: true, + }, + { + name: i18n._(t`Created By (Username)`), + key: 'created_by__username', + }, + { + name: i18n._(t`Modified By (Username)`), + key: 'modified_by__username', + }, + ]; + + const teamSortColumns = [ + { + name: i18n._(t`Name`), + key: 'name', + }, + ]; + + let wizardTitle = ''; + + switch (selectedResource) { + case 'users': + wizardTitle = i18n._(t`Add User Roles`); + break; + case 'teams': + wizardTitle = i18n._(t`Add Team Roles`); + break; + default: + wizardTitle = i18n._(t`Add Roles`); + } + + const steps = [ + { + id: 1, + name: i18n._(t`Select a Resource Type`), + component: ( +
+
+ {i18n._( + t`Choose the type of resource that will be receiving new roles. For example, if you'd like to add new roles to a set of users please choose Users and click Next. You'll be able to select the specific resources in the next step.` + )} +
+ handleResourceSelect('users')} + /> + {resource?.type === 'credential' && !resource?.organization ? null : ( + handleResourceSelect('teams')} + /> + )} +
+ ), + enableNext: selectedResource !== null, + }, + { + id: 2, + name: i18n._(t`Select Items from List`), + component: ( + + {selectedResource === 'users' && ( + + )} + {selectedResource === 'teams' && ( + + )} + + ), + enableNext: selectedResourceRows.length > 0, + canJumpTo: maxEnabledStep >= 2, + }, + { + id: 3, + name: i18n._(t`Select Roles to Apply`), + component: ( + + ), + nextButtonText: i18n._(t`Save`), + enableNext: selectedRoleRows.length > 0, + canJumpTo: maxEnabledStep >= 3, + }, + ]; + + const currentStep = steps.find(step => step.id === currentStepId); + + // TODO: somehow internationalize steps and currentStep.nextButtonText + return ( + handleWizardGoToStep(step)} + steps={steps} + title={wizardTitle} + nextButtonText={currentStep.nextButtonText || undefined} + backButtonText={i18n._(t`Back`)} + cancelButtonText={i18n._(t`Cancel`)} + /> + ); +} + +AddResourceRole.propTypes = { + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, + roles: PropTypes.shape(), + resource: PropTypes.shape(), +}; + +AddResourceRole.defaultProps = { + roles: {}, + resource: {}, +}; + +export { AddResourceRole as _AddResourceRole }; +export default withI18n()(AddResourceRole); diff --git a/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx b/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx new file mode 100644 index 000000000000..264f7cdb289f --- /dev/null +++ b/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx @@ -0,0 +1,242 @@ +/* eslint-disable react/jsx-pascal-case */ +import React from 'react'; +import { shallow } from 'enzyme'; +import { act } from 'react-dom/test-utils'; + +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import AddResourceRole, { _AddResourceRole } from './AddResourceRole'; +import { TeamsAPI, UsersAPI } from '../../api'; + +jest.mock('../../api/models/Teams'); +jest.mock('../../api/models/Users'); + +// TODO: Once error handling is functional in +// this component write tests for it + +describe('<_AddResourceRole />', () => { + UsersAPI.read.mockResolvedValue({ + data: { + count: 2, + results: [ + { id: 1, username: 'foo', url: '' }, + { id: 2, username: 'bar', url: '' }, + ], + }, + }); + UsersAPI.readOptions.mockResolvedValue({ + data: { related: {}, actions: { GET: {} } }, + }); + TeamsAPI.read.mockResolvedValue({ + data: { + count: 2, + results: [ + { id: 1, name: 'Team foo', url: '' }, + { id: 2, name: 'Team bar', url: '' }, + ], + }, + }); + TeamsAPI.readOptions.mockResolvedValue({ + data: { related: {}, actions: { GET: {} } }, + }); + const roles = { + admin_role: { + description: 'Can manage all aspects of the organization', + id: 1, + name: 'Admin', + }, + execute_role: { + description: 'May run any executable resources in the organization', + id: 2, + name: 'Execute', + }, + }; + test('initially renders without crashing', () => { + shallow( + <_AddResourceRole + onClose={() => {}} + onSave={() => {}} + roles={roles} + i18n={{ _: val => val.toString() }} + /> + ); + }); + test('should save properly', async () => { + let wrapper; + act(() => { + wrapper = mountWithContexts( + {}} onSave={() => {}} roles={roles} />, + { context: { network: { handleHttpError: () => {} } } } + ); + }); + wrapper.update(); + + // Step 1 + const selectableCardWrapper = wrapper.find('SelectableCard'); + expect(selectableCardWrapper.length).toBe(2); + act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); + wrapper.update(); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + wrapper.update(); + + // Step 2 + await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); + act(() => + wrapper.find('DataListCheck[name="foo"]').invoke('onChange')(true) + ); + wrapper.update(); + expect(wrapper.find('DataListCheck[name="foo"]').prop('checked')).toBe( + true + ); + act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); + wrapper.update(); + + // Step 3 + act(() => + wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) + ); + wrapper.update(); + expect(wrapper.find('Checkbox[aria-label="Admin"]').prop('isChecked')).toBe( + true + ); + + // Save + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + expect(UsersAPI.associateRole).toBeCalledWith(1, 1); + }); + + test('should successfuly click user/team cards', async () => { + let wrapper; + act(() => { + wrapper = mountWithContexts( + {}} onSave={() => {}} roles={roles} />, + { context: { network: { handleHttpError: () => {} } } } + ); + }); + wrapper.update(); + + const selectableCardWrapper = wrapper.find('SelectableCard'); + expect(selectableCardWrapper.length).toBe(2); + act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); + wrapper.update(); + + await waitForElement( + wrapper, + 'SelectableCard[label="Users"]', + el => el.prop('isSelected') === true + ); + act(() => wrapper.find('SelectableCard[label="Teams"]').prop('onClick')()); + wrapper.update(); + + await waitForElement( + wrapper, + 'SelectableCard[label="Teams"]', + el => el.prop('isSelected') === true + ); + }); + + test('should reset values with resource type changes', async () => { + let wrapper; + act(() => { + wrapper = mountWithContexts( + {}} onSave={() => {}} roles={roles} />, + { context: { network: { handleHttpError: () => {} } } } + ); + }); + wrapper.update(); + + // Step 1 + const selectableCardWrapper = wrapper.find('SelectableCard'); + expect(selectableCardWrapper.length).toBe(2); + act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); + wrapper.update(); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + wrapper.update(); + + // Step 2 + await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); + act(() => + wrapper.find('DataListCheck[name="foo"]').invoke('onChange')(true) + ); + wrapper.update(); + expect(wrapper.find('DataListCheck[name="foo"]').prop('checked')).toBe( + true + ); + act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); + wrapper.update(); + + // Step 3 + act(() => + wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) + ); + wrapper.update(); + expect(wrapper.find('Checkbox[aria-label="Admin"]').prop('isChecked')).toBe( + true + ); + + // Go back to step 1 + act(() => { + wrapper + .find('WizardNavItem[content="Select a Resource Type"]') + .find('button') + .prop('onClick')({ id: 1 }); + }); + wrapper.update(); + expect( + wrapper + .find('WizardNavItem[content="Select a Resource Type"]') + .prop('isCurrent') + ).toBe(true); + + // Go back to step 1 and this time select teams. Doing so should clear following steps + act(() => wrapper.find('SelectableCard[label="Teams"]').prop('onClick')()); + wrapper.update(); + await act(async () => + wrapper.find('Button[type="submit"]').prop('onClick')() + ); + wrapper.update(); + + // Make sure no teams have been selected + await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); + wrapper + .find('DataListCheck') + .map(item => expect(item.prop('checked')).toBe(false)); + act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); + wrapper.update(); + + // Make sure that no roles have been selected + wrapper + .find('Checkbox') + .map(card => expect(card.prop('isChecked')).toBe(false)); + + // Make sure the save button is disabled + expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); + }); + + test('should not display team as a choice in case credential does not have organization', () => { + const wrapper = mountWithContexts( + {}} + onSave={() => {}} + roles={roles} + resource={{ type: 'credential', organization: null }} + />, + { context: { network: { handleHttpError: () => {} } } } + ); + + expect(wrapper.find('SelectableCard').length).toBe(1); + wrapper.find('SelectableCard[label="Users"]').simulate('click'); + wrapper.update(); + expect( + wrapper.find('SelectableCard[label="Users"]').prop('isSelected') + ).toBe(true); + }); +}); diff --git a/awx/ui_next/src/components/AddRole/CheckboxCard.jsx b/awx/ui_next/src/components/AddRole/CheckboxCard.jsx new file mode 100644 index 000000000000..361bf1a60dfb --- /dev/null +++ b/awx/ui_next/src/components/AddRole/CheckboxCard.jsx @@ -0,0 +1,57 @@ +import React, { Component, Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { Checkbox as PFCheckbox } from '@patternfly/react-core'; +import styled from 'styled-components'; + +const CheckboxWrapper = styled.div` + display: flex; + border: 1px solid var(--pf-global--BorderColor--200); + border-radius: var(--pf-global--BorderRadius--sm); + padding: 10px; +`; + +const Checkbox = styled(PFCheckbox)` + width: 100%; + & label { + width: 100%; + } +`; + +class CheckboxCard extends Component { + render() { + const { name, description, isSelected, onSelect, itemId } = this.props; + return ( + + +
{name}
+
{description}
+ + } + value={itemId} + /> +
+ ); + } +} + +CheckboxCard.propTypes = { + name: PropTypes.string.isRequired, + description: PropTypes.string, + isSelected: PropTypes.bool, + onSelect: PropTypes.func, + itemId: PropTypes.number.isRequired, +}; + +CheckboxCard.defaultProps = { + description: '', + isSelected: false, + onSelect: null, +}; + +export default CheckboxCard; diff --git a/awx/ui_next/src/components/AddRole/CheckboxCard.test.jsx b/awx/ui_next/src/components/AddRole/CheckboxCard.test.jsx new file mode 100644 index 000000000000..637cbac403eb --- /dev/null +++ b/awx/ui_next/src/components/AddRole/CheckboxCard.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import CheckboxCard from './CheckboxCard'; + +describe('', () => { + let wrapper; + test('initially renders without crashing', () => { + wrapper = shallow(); + expect(wrapper.length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx b/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx new file mode 100644 index 000000000000..f9a73d24ceee --- /dev/null +++ b/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx @@ -0,0 +1,142 @@ +import React, { Fragment, useCallback, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { withRouter, useLocation } from 'react-router-dom'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import useRequest from '../../util/useRequest'; + +import { SearchColumns, SortColumns } from '../../types'; +import PaginatedDataList from '../PaginatedDataList'; +import DataListToolbar from '../DataListToolbar'; +import CheckboxListItem from '../CheckboxListItem'; +import SelectedList from '../SelectedList'; +import { getQSConfig, parseQueryString } from '../../util/qs'; + +const QS_Config = sortColumns => { + return getQSConfig('resource', { + page: 1, + page_size: 5, + order_by: `${ + sortColumns.filter(col => col.key === 'name').length ? 'name' : 'username' + }`, + }); +}; +function SelectResourceStep({ + searchColumns, + sortColumns, + displayKey, + onRowClick, + selectedLabel, + selectedResourceRows, + fetchItems, + fetchOptions, + i18n, +}) { + const location = useLocation(); + + const { + isLoading, + error, + request: readResourceList, + result: { resources, itemCount, relatedSearchableKeys, searchableKeys }, + } = useRequest( + useCallback(async () => { + const queryParams = parseQueryString( + QS_Config(sortColumns), + location.search + ); + + const [ + { + data: { count, results }, + }, + actionsResponse, + ] = await Promise.all([fetchItems(queryParams), fetchOptions()]); + return { + resources: results, + itemCount: count, + relatedSearchableKeys: ( + actionsResponse?.data?.related_search_fields || [] + ).map(val => val.slice(0, -8)), + searchableKeys: Object.keys( + actionsResponse.data.actions?.GET || {} + ).filter(key => actionsResponse.data.actions?.GET[key].filterable), + }; + }, [location, fetchItems, fetchOptions, sortColumns]), + { + resources: [], + itemCount: 0, + relatedSearchableKeys: [], + searchableKeys: [], + } + ); + + useEffect(() => { + readResourceList(); + }, [readResourceList]); + + return ( + +
+ {i18n._( + t`Choose the resources that will be receiving new roles. You'll be able to select the roles to apply in the next step. Note that the resources chosen here will receive all roles chosen in the next step.` + )} +
+ {selectedResourceRows.length > 0 && ( + + )} + ( + i.id === item.id)} + itemId={item.id} + key={item.id} + name={item[displayKey]} + label={item[displayKey]} + onSelect={() => onRowClick(item)} + onDeselect={() => onRowClick(item)} + /> + )} + renderToolbar={props => } + showPageSizeOptions={false} + /> +
+ ); +} + +SelectResourceStep.propTypes = { + searchColumns: SearchColumns, + sortColumns: SortColumns, + displayKey: PropTypes.string, + onRowClick: PropTypes.func, + fetchItems: PropTypes.func.isRequired, + selectedLabel: PropTypes.string, + selectedResourceRows: PropTypes.arrayOf(PropTypes.object), +}; + +SelectResourceStep.defaultProps = { + searchColumns: null, + sortColumns: null, + displayKey: 'name', + onRowClick: () => {}, + selectedLabel: null, + selectedResourceRows: [], +}; + +export { SelectResourceStep as _SelectResourceStep }; +export default withI18n()(withRouter(SelectResourceStep)); diff --git a/awx/ui_next/src/components/AddRole/SelectResourceStep.test.jsx b/awx/ui_next/src/components/AddRole/SelectResourceStep.test.jsx new file mode 100644 index 000000000000..4e307b7595bf --- /dev/null +++ b/awx/ui_next/src/components/AddRole/SelectResourceStep.test.jsx @@ -0,0 +1,126 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; + +import { shallow } from 'enzyme'; +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import { sleep } from '../../../testUtils/testUtils'; +import SelectResourceStep from './SelectResourceStep'; + +describe('', () => { + const searchColumns = [ + { + name: 'Username', + key: 'username__icontains', + isDefault: true, + }, + ]; + + const sortColumns = [ + { + name: 'Username', + key: 'username', + }, + ]; + afterEach(() => { + jest.restoreAllMocks(); + }); + test('initially renders without crashing', () => { + shallow( + {}} + fetchItems={() => {}} + fetchOptions={() => {}} + /> + ); + }); + + test('fetches resources on mount and adds items to list', async () => { + const handleSearch = jest.fn().mockResolvedValue({ + data: { + count: 2, + results: [ + { id: 1, username: 'foo', url: 'item/1' }, + { id: 2, username: 'bar', url: 'item/2' }, + ], + }, + }); + const options = jest.fn().mockResolvedValue({ + data: { + actions: { + GET: {}, + POST: {}, + }, + related_search_fields: [], + }, + }); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + {}} + fetchItems={handleSearch} + fetchOptions={options} + /> + ); + }); + expect(handleSearch).toHaveBeenCalledWith({ + order_by: 'username', + page: 1, + page_size: 5, + }); + waitForElement(wrapper, 'CheckBoxListItem', el => el.length === 2); + }); + + test('clicking on row fires callback with correct params', async () => { + const handleRowClick = jest.fn(); + const data = { + count: 2, + results: [ + { id: 1, username: 'foo', url: 'item/1' }, + { id: 2, username: 'bar', url: 'item/2' }, + ], + }; + const options = jest.fn().mockResolvedValue({ + data: { + actions: { + GET: {}, + POST: {}, + }, + related_search_fields: [], + }, + }); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + ({ data })} + fetchOptions={options} + selectedResourceRows={[]} + /> + ); + }); + await sleep(0); + wrapper.update(); + const checkboxListItemWrapper = wrapper.find('CheckboxListItem'); + expect(checkboxListItemWrapper.length).toBe(2); + + checkboxListItemWrapper + .first() + .find('input[type="checkbox"]') + .simulate('change', { target: { checked: true } }); + expect(handleRowClick).toHaveBeenCalledWith(data.results[0]); + }); +}); diff --git a/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx b/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx new file mode 100644 index 000000000000..32f0e6a96cb2 --- /dev/null +++ b/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx @@ -0,0 +1,78 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; + +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; + +import CheckboxCard from './CheckboxCard'; +import SelectedList from '../SelectedList'; + +function RolesStep({ + onRolesClick, + roles, + selectedListKey, + selectedListLabel, + selectedResourceRows, + selectedRoleRows, + i18n, +}) { + return ( + +
+ {i18n._( + t`Choose roles to apply to the selected resources. Note that all selected roles will be applied to all selected resources.` + )} +
+
+ {selectedResourceRows.length > 0 && ( + + )} +
+
+ {Object.keys(roles).map(role => ( + item.id === roles[role].id + )} + key={roles[role].id} + name={roles[role].name} + onSelect={() => onRolesClick(roles[role])} + /> + ))} +
+
+ ); +} + +RolesStep.propTypes = { + onRolesClick: PropTypes.func, + roles: PropTypes.objectOf(PropTypes.object).isRequired, + selectedListKey: PropTypes.string, + selectedListLabel: PropTypes.string, + selectedResourceRows: PropTypes.arrayOf(PropTypes.object), + selectedRoleRows: PropTypes.arrayOf(PropTypes.object), +}; + +RolesStep.defaultProps = { + onRolesClick: () => {}, + selectedListKey: 'name', + selectedListLabel: null, + selectedResourceRows: [], + selectedRoleRows: [], +}; + +export default withI18n()(RolesStep); diff --git a/awx/ui_next/src/components/AddRole/SelectRoleStep.test.jsx b/awx/ui_next/src/components/AddRole/SelectRoleStep.test.jsx new file mode 100644 index 000000000000..f2806043286e --- /dev/null +++ b/awx/ui_next/src/components/AddRole/SelectRoleStep.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import SelectRoleStep from './SelectRoleStep'; + +describe('', () => { + let wrapper; + const roles = { + project_admin_role: { + id: 1, + name: 'Project Admin', + description: 'Can manage all projects of the organization', + }, + execute_role: { + id: 2, + name: 'Execute', + description: 'May run any executable resources in the organization', + }, + }; + const selectedRoles = [ + { + id: 1, + name: 'Project Admin', + description: 'Can manage all projects of the organization', + }, + ]; + const selectedResourceRows = [ + { + id: 1, + name: 'foo', + }, + ]; + test('initially renders without crashing', () => { + wrapper = shallow( + + ); + expect(wrapper.length).toBe(1); + wrapper.unmount(); + }); + test('clicking role fires onRolesClick callback', () => { + const onRolesClick = jest.fn(); + wrapper = mountWithContexts( + + ); + const CheckboxCards = wrapper.find('CheckboxCard'); + expect(CheckboxCards.length).toBe(2); + CheckboxCards.first().prop('onSelect')(); + expect(onRolesClick).toBeCalledWith({ + id: 1, + name: 'Project Admin', + description: 'Can manage all projects of the organization', + }); + wrapper.unmount(); + }); +}); diff --git a/awx/ui_next/src/components/AddRole/index.js b/awx/ui_next/src/components/AddRole/index.js new file mode 100644 index 000000000000..52e9ec78d470 --- /dev/null +++ b/awx/ui_next/src/components/AddRole/index.js @@ -0,0 +1,4 @@ +export { default as AddResourceRole } from './AddResourceRole'; +export { default as CheckboxCard } from './CheckboxCard'; +export { default as SelectResourceStep } from './SelectResourceStep'; +export { default as SelectRoleStep } from './SelectRoleStep'; diff --git a/awx/ui_next/src/components/AlertModal/AlertModal.jsx b/awx/ui_next/src/components/AlertModal/AlertModal.jsx new file mode 100644 index 000000000000..0c443300bed1 --- /dev/null +++ b/awx/ui_next/src/components/AlertModal/AlertModal.jsx @@ -0,0 +1,89 @@ +import 'styled-components/macro'; +import React from 'react'; +import { Modal, Title } from '@patternfly/react-core'; +import { + CheckCircleIcon, + ExclamationCircleIcon, + ExclamationTriangleIcon, + InfoCircleIcon, + TimesCircleIcon, +} from '@patternfly/react-icons'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import styled from 'styled-components'; + +const Header = styled.div` + display: flex; + svg { + margin-right: 16px; + } +`; + +function AlertModal({ + i18n, + isOpen = null, + title, + label, + variant, + children, + i18nHash, + ...props +}) { + const variantIcons = { + danger: ( + + ), + error: ( + + ), + info: ( + + ), + success: ( + + ), + warning: ( + + ), + }; + + const customHeader = ( +
+ {variant ? variantIcons[variant] : null} + + {title} + +
+ ); + + return ( + + {children} + + ); +} + +export default withI18n()(AlertModal); diff --git a/awx/ui_next/src/components/AlertModal/AlertModal.test.jsx b/awx/ui_next/src/components/AlertModal/AlertModal.test.jsx new file mode 100644 index 000000000000..0173e5a378f9 --- /dev/null +++ b/awx/ui_next/src/components/AlertModal/AlertModal.test.jsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import AlertModal from './AlertModal'; + +describe('AlertModal', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts( + Are you sure? + ); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/AlertModal/index.js b/awx/ui_next/src/components/AlertModal/index.js new file mode 100644 index 000000000000..f40ad70d3d06 --- /dev/null +++ b/awx/ui_next/src/components/AlertModal/index.js @@ -0,0 +1 @@ +export { default } from './AlertModal'; diff --git a/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.jsx b/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.jsx new file mode 100644 index 000000000000..62b8983eb45e --- /dev/null +++ b/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { + arrayOf, + oneOfType, + func, + number, + string, + shape, + bool, +} from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { FormSelect, FormSelectOption } from '@patternfly/react-core'; + +function AnsibleSelect({ + id, + data, + i18n, + isValid, + onBlur, + value, + className, + isDisabled, + onChange, + name, +}) { + const onSelectChange = (val, event) => { + event.target.name = name; + onChange(event, val); + }; + + return ( + + {data.map(option => ( + + ))} + + ); +} + +const Option = shape({ + key: oneOfType([string, number]).isRequired, + value: oneOfType([string, number]).isRequired, + label: string.isRequired, + isDisabled: bool, +}); + +AnsibleSelect.defaultProps = { + data: [], + isValid: true, + onBlur: () => {}, + className: '', + isDisabled: false, +}; + +AnsibleSelect.propTypes = { + data: arrayOf(Option), + id: string.isRequired, + isValid: bool, + onBlur: func, + onChange: func.isRequired, + value: oneOfType([string, number]).isRequired, + className: string, + isDisabled: bool, +}; + +export { AnsibleSelect as _AnsibleSelect }; +export default withI18n()(AnsibleSelect); diff --git a/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.test.jsx b/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.test.jsx new file mode 100644 index 000000000000..bb671c8823a2 --- /dev/null +++ b/awx/ui_next/src/components/AnsibleSelect/AnsibleSelect.test.jsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import AnsibleSelect from './AnsibleSelect'; + +const mockData = [ + { + key: 'baz', + label: 'Baz', + value: '/var/lib/awx/venv/baz/', + }, + { + key: 'default', + label: 'Default', + value: '/var/lib/awx/venv/ansible/', + }, +]; + +describe('', () => { + const onChange = jest.fn(); + test('initially renders succesfully', async () => { + mountWithContexts( + {}} + data={mockData} + /> + ); + }); + + test('calls "onSelectChange" on dropdown select change', () => { + const wrapper = mountWithContexts( + + ); + expect(onChange).not.toHaveBeenCalled(); + wrapper.find('select').simulate('change'); + expect(onChange).toHaveBeenCalled(); + }); + + test('Returns correct select options', () => { + const wrapper = mountWithContexts( + {}} + data={mockData} + /> + ); + + expect(wrapper.find('FormSelect')).toHaveLength(1); + expect(wrapper.find('FormSelectOption')).toHaveLength(2); + }); +}); diff --git a/awx/ui_next/src/components/AnsibleSelect/index.js b/awx/ui_next/src/components/AnsibleSelect/index.js new file mode 100644 index 000000000000..647f195bbdb7 --- /dev/null +++ b/awx/ui_next/src/components/AnsibleSelect/index.js @@ -0,0 +1 @@ +export { default } from './AnsibleSelect'; diff --git a/awx/ui_next/src/components/AppContainer/AppContainer.jsx b/awx/ui_next/src/components/AppContainer/AppContainer.jsx new file mode 100644 index 000000000000..0abd198c07e5 --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/AppContainer.jsx @@ -0,0 +1,251 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import { useHistory, useLocation, withRouter } from 'react-router-dom'; +import { + Button, + Nav, + NavList, + Page, + PageHeader as PFPageHeader, + PageSidebar, +} from '@patternfly/react-core'; +import { t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import styled from 'styled-components'; + +import { ConfigAPI, MeAPI, RootAPI } from '../../api'; +import { ConfigProvider } from '../../contexts/Config'; +import { SESSION_TIMEOUT_KEY } from '../../constants'; +import { isAuthenticated } from '../../util/auth'; +import About from '../About'; +import AlertModal from '../AlertModal'; +import ErrorDetail from '../ErrorDetail'; +import BrandLogo from './BrandLogo'; +import NavExpandableGroup from './NavExpandableGroup'; +import PageHeaderToolbar from './PageHeaderToolbar'; + +// The maximum supported timeout for setTimeout(), in milliseconds, +// is the highest number you can represent as a signed 32bit +// integer (approximately 25 days) +const MAX_TIMEOUT = 2 ** (32 - 1) - 1; + +// The number of seconds the session timeout warning is displayed +// before the user is logged out. Increasing this number (up to +// the total session time, which is 1800s by default) will cause +// the session timeout warning to display sooner. +const SESSION_WARNING_DURATION = 10; + +const PageHeader = styled(PFPageHeader)` + & .pf-c-page__header-brand-link { + color: inherit; + + &:hover { + color: inherit; + } + } +`; + +/** + * The useStorage hook integrates with the browser's localStorage api. + * It accepts a storage key as its only argument and returns a state + * variable and setter function for that state variable. + * + * This utility behaves much like the standard useState hook with some + * key differences: + * 1. You don't pass it an initial value. Instead, the provided key + * is used to retrieve the initial value from local storage. If + * the key doesn't exist in local storage, null is returned. + * 2. Behind the scenes, this hook registers an event listener with + * the Web Storage api to establish a two-way binding between the + * state variable and its corresponding local storage value. This + * means that updates to the state variable with the setter + * function will produce a corresponding update to the local + * storage value and vice-versa. + * 3. When local storage is shared across browser tabs, the data + * binding is also shared across browser tabs. This means that + * updates to the state variable using the setter function on + * one tab will also update the state variable on any other tab + * using this hook with the same key and vice-versa. + */ +function useStorage(key) { + const [storageVal, setStorageVal] = useState( + window.localStorage.getItem(key) + ); + window.addEventListener('storage', () => { + const newVal = window.localStorage.getItem(key); + if (newVal !== storageVal) { + setStorageVal(newVal); + } + }); + const setValue = val => { + window.localStorage.setItem(key, val); + setStorageVal(val); + }; + return [storageVal, setValue]; +} + +function AppContainer({ i18n, navRouteConfig = [], children }) { + const history = useHistory(); + const { pathname } = useLocation(); + const [config, setConfig] = useState({}); + const [configError, setConfigError] = useState(null); + const [isAboutModalOpen, setIsAboutModalOpen] = useState(false); + const [isReady, setIsReady] = useState(false); + + const sessionTimeoutId = useRef(); + const sessionIntervalId = useRef(); + const [sessionTimeout, setSessionTimeout] = useStorage(SESSION_TIMEOUT_KEY); + const [timeoutWarning, setTimeoutWarning] = useState(false); + const [timeRemaining, setTimeRemaining] = useState(null); + + const handleAboutModalOpen = () => setIsAboutModalOpen(true); + const handleAboutModalClose = () => setIsAboutModalOpen(false); + const handleConfigErrorClose = () => setConfigError(null); + const handleSessionTimeout = () => setTimeoutWarning(true); + + const handleLogout = useCallback(async () => { + await RootAPI.logout(); + setSessionTimeout(null); + }, [setSessionTimeout]); + + const handleSessionContinue = () => { + MeAPI.read(); + setTimeoutWarning(false); + }; + + useEffect(() => { + if (!isAuthenticated(document.cookie)) history.replace('/login'); + const calcRemaining = () => + parseInt(sessionTimeout, 10) - new Date().getTime(); + const updateRemaining = () => setTimeRemaining(calcRemaining()); + setTimeoutWarning(false); + clearTimeout(sessionTimeoutId.current); + clearInterval(sessionIntervalId.current); + sessionTimeoutId.current = setTimeout( + handleSessionTimeout, + Math.min(calcRemaining() - SESSION_WARNING_DURATION * 1000, MAX_TIMEOUT) + ); + sessionIntervalId.current = setInterval(updateRemaining, 1000); + return () => { + clearTimeout(sessionTimeoutId.current); + clearInterval(sessionIntervalId.current); + }; + }, [history, sessionTimeout]); + + useEffect(() => { + if (timeRemaining !== null && timeRemaining <= 1) { + handleLogout(); + } + }, [handleLogout, timeRemaining]); + + useEffect(() => { + const loadConfig = async () => { + if (config?.version) return; + try { + const [ + { data }, + { + data: { + results: [me], + }, + }, + ] = await Promise.all([ConfigAPI.read(), MeAPI.read()]); + setConfig({ ...data, me }); + setIsReady(true); + } catch (err) { + if (err.response.status === 401) { + handleLogout(); + return; + } + setConfigError(err); + } + }; + loadConfig(); + }, [config, pathname, handleLogout]); + + const header = ( + } + logoProps={{ href: '/' }} + headerTools={ + + } + /> + ); + + const sidebar = ( + + + {navRouteConfig.map(({ groupId, groupTitle, routes }) => ( + + ))} + + + } + /> + ); + + return ( + <> + + {isReady && {children}} + + + + {i18n._(t`Failed to retrieve configuration.`)} + + + 0 && timeRemaining !== null} + onClose={handleLogout} + showClose={false} + variant="warning" + actions={[ + , + , + ]} + > + {i18n._( + t`You will be logged out in ${Number( + Math.max(Math.floor(timeRemaining / 1000), 0) + )} seconds due to inactivity.` + )} + + + ); +} + +export { AppContainer as _AppContainer }; +export default withI18n()(withRouter(AppContainer)); diff --git a/awx/ui_next/src/components/AppContainer/AppContainer.test.jsx b/awx/ui_next/src/components/AppContainer/AppContainer.test.jsx new file mode 100644 index 000000000000..bdb67db490e6 --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/AppContainer.test.jsx @@ -0,0 +1,124 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import { ConfigAPI, MeAPI, RootAPI } from '../../api'; +import AppContainer from './AppContainer'; + +jest.mock('../../api'); + +describe('', () => { + const ansible_version = '111'; + const custom_virtualenvs = []; + const version = '222'; + + beforeEach(() => { + ConfigAPI.read.mockResolvedValue({ + data: { + ansible_version, + custom_virtualenvs, + version, + }, + }); + MeAPI.read.mockResolvedValue({ data: { results: [{}] } }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('expected content is rendered', async () => { + const routeConfig = [ + { + groupTitle: 'Group One', + groupId: 'group_one', + routes: [ + { title: 'Foo', path: '/foo' }, + { title: 'Bar', path: '/bar' }, + ], + }, + { + groupTitle: 'Group Two', + groupId: 'group_two', + routes: [{ title: 'Fiz', path: '/fiz' }], + }, + ]; + + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + {routeConfig.map(({ groupId }) => ( +
+ ))} + + ); + }); + wrapper.update(); + + // page components + expect(wrapper.length).toBe(1); + expect(wrapper.find('PageHeader').length).toBe(1); + expect(wrapper.find('PageSidebar').length).toBe(1); + + // sidebar groups and route links + expect(wrapper.find('NavExpandableGroup').length).toBe(2); + expect(wrapper.find('a[href="/foo"]').length).toBe(1); + expect(wrapper.find('a[href="/bar"]').length).toBe(1); + expect(wrapper.find('a[href="/fiz"]').length).toBe(1); + + expect(wrapper.find('#group_one').length).toBe(1); + expect(wrapper.find('#group_two').length).toBe(1); + }); + + test('opening the about modal renders prefetched config data', async () => { + const aboutDropdown = 'Dropdown QuestionCircleIcon'; + const aboutButton = 'DropdownItem li button'; + const aboutModalContent = 'AboutModalBoxContent'; + const aboutModalClose = 'button[aria-label="Close Dialog"]'; + + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); + + // open about dropdown menu + await waitForElement(wrapper, aboutDropdown); + wrapper.find(aboutDropdown).simulate('click'); + + // open about modal + ( + await waitForElement(wrapper, aboutButton, el => !el.props().disabled) + ).simulate('click'); + + // check about modal content + const content = await waitForElement(wrapper, aboutModalContent); + expect(content.find('dd').text()).toContain(ansible_version); + expect(content.find('pre').text()).toContain(`< AWX ${version} >`); + + // close about modal + wrapper.find(aboutModalClose).simulate('click'); + expect(wrapper.find(aboutModalContent)).toHaveLength(0); + }); + + test('logout makes expected call to api client', async () => { + const userMenuButton = 'UserIcon'; + const logoutButton = '#logout-button button'; + + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); + + // open the user menu + expect(wrapper.find(logoutButton)).toHaveLength(0); + wrapper.find(userMenuButton).simulate('click'); + expect(wrapper.find(logoutButton)).toHaveLength(1); + + // logout + wrapper.find(logoutButton).simulate('click'); + expect(RootAPI.logout).toHaveBeenCalledTimes(1); + }); +}); diff --git a/awx/ui_next/src/components/AppContainer/BrandLogo.jsx b/awx/ui_next/src/components/AppContainer/BrandLogo.jsx new file mode 100644 index 000000000000..be15af67735a --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/BrandLogo.jsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import styled from 'styled-components'; + +const BrandImg = styled.img` + flex: initial; + height: 76px; + width: initial; + padding-left: 0px; + margin: 0px 0px 0px 0px; + max-width: 100px; + max-height: initial; + pointer-events: none; +`; + +const BrandLogo = () => ; + +export default BrandLogo; diff --git a/awx/ui_next/src/components/AppContainer/BrandLogo.test.jsx b/awx/ui_next/src/components/AppContainer/BrandLogo.test.jsx new file mode 100644 index 000000000000..641332be6663 --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/BrandLogo.test.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import BrandLogo from './BrandLogo'; + +let logoWrapper; +let brandLogoElem; +let imgElem; + +const findChildren = () => { + brandLogoElem = logoWrapper.find('BrandLogo'); + imgElem = logoWrapper.find('img'); +}; + +describe('', () => { + test('initially renders without crashing', () => { + logoWrapper = mountWithContexts(); + findChildren(); + expect(logoWrapper.length).toBe(1); + expect(brandLogoElem.length).toBe(1); + expect(imgElem.length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/components/AppContainer/NavExpandableGroup.jsx b/awx/ui_next/src/components/AppContainer/NavExpandableGroup.jsx new file mode 100644 index 000000000000..45c3b91faeac --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/NavExpandableGroup.jsx @@ -0,0 +1,66 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { matchPath, Link, withRouter } from 'react-router-dom'; +import { NavExpandable, NavItem } from '@patternfly/react-core'; + +class NavExpandableGroup extends Component { + constructor(props) { + super(props); + const { routes } = this.props; + + // Extract a list of paths from the route params and store them for later. This creates + // an array of url paths associated with any NavItem component rendered by this component. + this.navItemPaths = routes.map(({ path }) => path); + this.isActiveGroup = this.isActiveGroup.bind(this); + this.isActivePath = this.isActivePath.bind(this); + } + + isActiveGroup() { + return this.navItemPaths.some(this.isActivePath); + } + + isActivePath(path) { + const { history } = this.props; + return Boolean(matchPath(history.location.pathname, { path })); + } + + render() { + const { groupId, groupTitle, routes } = this.props; + + if (routes.length === 1) { + const [{ path }] = routes; + return ( + + {groupTitle} + + ); + } + + return ( + + {routes.map(({ path, title }) => ( + + {title} + + ))} + + ); + } +} + +NavExpandableGroup.propTypes = { + groupId: PropTypes.string.isRequired, + groupTitle: PropTypes.string.isRequired, + routes: PropTypes.arrayOf(PropTypes.object).isRequired, +}; + +export default withRouter(NavExpandableGroup); diff --git a/awx/ui_next/src/components/AppContainer/NavExpandableGroup.test.jsx b/awx/ui_next/src/components/AppContainer/NavExpandableGroup.test.jsx new file mode 100644 index 000000000000..486cda9e6da6 --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/NavExpandableGroup.test.jsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { mount } from 'enzyme'; + +import { Nav } from '@patternfly/react-core'; +import NavExpandableGroup from './NavExpandableGroup'; + +describe('NavExpandableGroup', () => { + test('initialization and render', () => { + const component = mount( + + + + ) + .find('NavExpandableGroup') + .instance(); + + expect(component.navItemPaths).toEqual(['/foo', '/bar', '/fiz']); + expect(component.isActiveGroup()).toEqual(true); + }); + + describe('isActivePath', () => { + const params = [ + ['/fo', '/foo', false], + ['/foo', '/foo', true], + ['/foo/1/bar/fiz', '/foo', true], + ['/foo/1/bar/fiz', 'foo', false], + ['/foo/1/bar/fiz', 'foo/', false], + ['/foo/1/bar/fiz', '/bar', false], + ['/foo/1/bar/fiz', '/fiz', false], + ]; + + params.forEach(([location, path, expected]) => { + test(`when location is ${location}, isActivePath('${path}') returns ${expected} `, () => { + const component = mount( + + + + ) + .find('NavExpandableGroup') + .instance(); + + expect(component.isActivePath(path)).toEqual(expected); + }); + }); + }); +}); diff --git a/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.jsx b/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.jsx new file mode 100644 index 000000000000..4d31af328e6c --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.jsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { + Dropdown, + DropdownItem, + DropdownToggle, + DropdownPosition, + PageHeaderTools, + PageHeaderToolsGroup, + PageHeaderToolsItem, + Tooltip, +} from '@patternfly/react-core'; +import { QuestionCircleIcon, UserIcon } from '@patternfly/react-icons'; + +const DOCLINK = + 'https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html'; + +function PageHeaderToolbar({ + isAboutDisabled, + onAboutClick, + onLogoutClick, + loggedInUser, + i18n, +}) { + const [isHelpOpen, setIsHelpOpen] = useState(false); + const [isUserOpen, setIsUserOpen] = useState(false); + + const handleHelpSelect = () => { + setIsHelpOpen(!isHelpOpen); + }; + + const handleUserSelect = () => { + setIsUserOpen(!isUserOpen); + }; + + return ( + + + {i18n._(t`Info`)}
}> + + + + + } + dropdownItems={[ + + {i18n._(t`Help`)} + , + + {i18n._(t`About`)} + , + ]} + /> + + + {i18n._(t`User`)}
}> + + + + {loggedInUser && ( + + {loggedInUser.username} + + )} + + } + dropdownItems={[ + + {i18n._(t`User Details`)} + , + + {i18n._(t`Logout`)} + , + ]} + /> + + + + + ); +} + +PageHeaderToolbar.propTypes = { + isAboutDisabled: PropTypes.bool, + onAboutClick: PropTypes.func.isRequired, + onLogoutClick: PropTypes.func.isRequired, +}; + +PageHeaderToolbar.defaultProps = { + isAboutDisabled: false, +}; + +export default withI18n()(PageHeaderToolbar); diff --git a/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.test.jsx b/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.test.jsx new file mode 100644 index 000000000000..7c151d3dc5e8 --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/PageHeaderToolbar.test.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import PageHeaderToolbar from './PageHeaderToolbar'; + +describe('PageHeaderToolbar', () => { + const pageHelpDropdownSelector = 'Dropdown QuestionCircleIcon'; + const pageUserDropdownSelector = 'Dropdown UserIcon'; + const onAboutClick = jest.fn(); + const onLogoutClick = jest.fn(); + + test('expected content is rendered on initialization', () => { + const wrapper = mountWithContexts( + + ); + + expect(wrapper.find(pageHelpDropdownSelector)).toHaveLength(1); + expect(wrapper.find(pageUserDropdownSelector)).toHaveLength(1); + }); + + test('dropdowns have expected items and callbacks', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('DropdownItem')).toHaveLength(0); + wrapper.find(pageHelpDropdownSelector).simulate('click'); + expect(wrapper.find('DropdownItem')).toHaveLength(2); + + const about = wrapper.find('DropdownItem li button'); + about.simulate('click'); + expect(onAboutClick).toHaveBeenCalled(); + + expect(wrapper.find('DropdownItem')).toHaveLength(0); + wrapper.find(pageUserDropdownSelector).simulate('click'); + expect(wrapper.find('DropdownItem')).toHaveLength(2); + + const logout = wrapper.find('DropdownItem li button'); + logout.simulate('click'); + expect(onLogoutClick).toHaveBeenCalled(); + }); +}); diff --git a/awx/ui_next/src/components/AppContainer/index.jsx b/awx/ui_next/src/components/AppContainer/index.jsx new file mode 100644 index 000000000000..4fa9f5e563fe --- /dev/null +++ b/awx/ui_next/src/components/AppContainer/index.jsx @@ -0,0 +1,3 @@ +import AppContainer from './AppContainer'; + +export default AppContainer; diff --git a/awx/ui_next/src/components/AppendBody/AppendBody.jsx b/awx/ui_next/src/components/AppendBody/AppendBody.jsx new file mode 100644 index 000000000000..62e25513721a --- /dev/null +++ b/awx/ui_next/src/components/AppendBody/AppendBody.jsx @@ -0,0 +1,24 @@ +import { Component } from 'react'; +import ReactDOM from 'react-dom'; + +class AppendBody extends Component { + constructor(props) { + super(props); + this.el = document.createElement('div'); + } + + componentDidMount() { + document.body.appendChild(this.el); + } + + componentWillUnmount() { + document.body.removeChild(this.el); + } + + render() { + const { children } = this.props; + return ReactDOM.createPortal(children, this.el); + } +} + +export default AppendBody; diff --git a/awx/ui_next/src/components/AppendBody/index.js b/awx/ui_next/src/components/AppendBody/index.js new file mode 100644 index 000000000000..d2c2b8ef93fa --- /dev/null +++ b/awx/ui_next/src/components/AppendBody/index.js @@ -0,0 +1 @@ +export { default } from './AppendBody'; diff --git a/awx/ui_next/src/components/AssociateModal/AssociateModal.jsx b/awx/ui_next/src/components/AssociateModal/AssociateModal.jsx new file mode 100644 index 000000000000..bddb53b949e3 --- /dev/null +++ b/awx/ui_next/src/components/AssociateModal/AssociateModal.jsx @@ -0,0 +1,164 @@ +import React, { Fragment, useEffect, useCallback } from 'react'; +import { useHistory } from 'react-router-dom'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Button, Modal } from '@patternfly/react-core'; +import OptionsList from '../OptionsList'; +import useRequest from '../../util/useRequest'; +import { getQSConfig, parseQueryString } from '../../util/qs'; +import useSelected from '../../util/useSelected'; + +const QS_CONFIG = (order_by = 'name') => { + return getQSConfig('associate', { + page: 1, + page_size: 5, + order_by, + }); +}; + +function AssociateModal({ + i18n, + header = i18n._(t`Items`), + title = i18n._(t`Select Items`), + onClose, + onAssociate, + fetchRequest, + optionsRequest, + isModalOpen = false, + displayKey = 'name', +}) { + const history = useHistory(); + const { selected, handleSelect } = useSelected([]); + + const { + request: fetchItems, + result: { items, itemCount, relatedSearchableKeys, searchableKeys }, + error: contentError, + isLoading, + } = useRequest( + useCallback(async () => { + const params = parseQueryString( + QS_CONFIG(displayKey), + history.location.search + ); + const [ + { + data: { count, results }, + }, + actionsResponse, + ] = await Promise.all([fetchRequest(params), optionsRequest()]); + + return { + items: results, + itemCount: count, + relatedSearchableKeys: ( + actionsResponse?.data?.related_search_fields || [] + ).map(val => val.slice(0, -8)), + searchableKeys: Object.keys( + actionsResponse.data.actions?.GET || {} + ).filter(key => actionsResponse.data.actions?.GET[key].filterable), + }; + }, [fetchRequest, optionsRequest, history.location.search, displayKey]), + { + items: [], + itemCount: 0, + relatedSearchableKeys: [], + searchableKeys: [], + } + ); + + useEffect(() => { + fetchItems(); + }, [fetchItems]); + + const clearQSParams = () => { + const parts = history.location.search.replace(/^\?/, '').split('&'); + const { namespace } = QS_CONFIG(displayKey); + const otherParts = parts.filter( + param => !param.startsWith(`${namespace}.`) + ); + history.replace(`${history.location.pathname}?${otherParts.join('&')}`); + }; + + const handleSave = async () => { + await onAssociate(selected); + clearQSParams(); + onClose(); + }; + + const handleClose = () => { + clearQSParams(); + onClose(); + }; + + return ( + + + {i18n._(t`Save`)} + , + , + ]} + > + + + + ); +} + +export default withI18n()(AssociateModal); diff --git a/awx/ui_next/src/components/AssociateModal/AssociateModal.test.jsx b/awx/ui_next/src/components/AssociateModal/AssociateModal.test.jsx new file mode 100644 index 000000000000..4b58e900e38d --- /dev/null +++ b/awx/ui_next/src/components/AssociateModal/AssociateModal.test.jsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; + +import { + mountWithContexts, + waitForElement, +} from '../../../testUtils/enzymeHelpers'; +import AssociateModal from './AssociateModal'; +import mockHosts from './data.hosts.json'; + +jest.mock('../../api'); + +describe('', () => { + let wrapper; + const onClose = jest.fn(); + const onAssociate = jest.fn().mockResolvedValue(); + const fetchRequest = jest.fn().mockReturnValue({ data: { ...mockHosts } }); + const optionsRequest = jest.fn().mockResolvedValue({ + data: { + actions: { + GET: {}, + POST: {}, + }, + related_search_fields: [], + }, + }); + + beforeEach(async () => { + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); + }); + + afterEach(() => { + wrapper.unmount(); + jest.clearAllMocks(); + }); + + test('should render successfully', () => { + expect(wrapper.find('AssociateModal').length).toBe(1); + }); + + test('should fetch and render list items', () => { + expect(fetchRequest).toHaveBeenCalledTimes(1); + expect(wrapper.find('CheckboxListItem').length).toBe(3); + }); + + test('should update selected list chips when items are selected', () => { + expect(wrapper.find('SelectedList Chip')).toHaveLength(0); + act(() => { + wrapper + .find('CheckboxListItem') + .first() + .invoke('onSelect')(); + }); + wrapper.update(); + expect(wrapper.find('SelectedList Chip')).toHaveLength(1); + wrapper.find('SelectedList Chip button').simulate('click'); + expect(wrapper.find('SelectedList Chip')).toHaveLength(0); + }); + + test('save button should call onAssociate', () => { + act(() => { + wrapper + .find('CheckboxListItem') + .first() + .invoke('onSelect')(); + }); + wrapper.find('button[aria-label="Save"]').simulate('click'); + expect(onAssociate).toHaveBeenCalledTimes(1); + }); + + test('cancel button should call onClose', () => { + wrapper.find('button[aria-label="Cancel"]').simulate('click'); + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/awx/ui_next/src/components/AssociateModal/data.hosts.json b/awx/ui_next/src/components/AssociateModal/data.hosts.json new file mode 100644 index 000000000000..07c6ef7d9f8d --- /dev/null +++ b/awx/ui_next/src/components/AssociateModal/data.hosts.json @@ -0,0 +1,393 @@ + +{ + "count": 3, + "results": [ + { + "id": 2, + "type": "host", + "url": "/api/v2/hosts/2/", + "related": { + "created_by": "/api/v2/users/10/", + "modified_by": "/api/v2/users/19/", + "variable_data": "/api/v2/hosts/2/variable_data/", + "groups": "/api/v2/hosts/2/groups/", + "all_groups": "/api/v2/hosts/2/all_groups/", + "job_events": "/api/v2/hosts/2/job_events/", + "job_host_summaries": "/api/v2/hosts/2/job_host_summaries/", + "activity_stream": "/api/v2/hosts/2/activity_stream/", + "inventory_sources": "/api/v2/hosts/2/inventory_sources/", + "smart_inventories": "/api/v2/hosts/2/smart_inventories/", + "ad_hoc_commands": "/api/v2/hosts/2/ad_hoc_commands/", + "ad_hoc_command_events": "/api/v2/hosts/2/ad_hoc_command_events/", + "insights": "/api/v2/hosts/2/insights/", + "ansible_facts": "/api/v2/hosts/2/ansible_facts/", + "inventory": "/api/v2/inventories/2/", + "last_job": "/api/v2/jobs/236/", + "last_job_host_summary": "/api/v2/job_host_summaries/2202/" + }, + "summary_fields": { + "inventory": { + "id": 2, + "name": " Inventory 1 Org 0", + "description": "", + "has_active_failures": false, + "total_hosts": 33, + "hosts_with_active_failures": 0, + "total_groups": 4, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 2, + "kind": "" + }, + "last_job": { + "id": 236, + "name": " Job Template 1 Project 0", + "description": "", + "finished": "2020-02-26T03:15:21.471439Z", + "status": "successful", + "failed": false, + "job_template_id": 18, + "job_template_name": " Job Template 1 Project 0" + }, + "last_job_host_summary": { + "id": 2202, + "failed": false + }, + "created_by": { + "id": 10, + "username": "user-3", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 19, + "username": "all", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "edit": true, + "delete": true + }, + "groups": { + "count": 2, + "results": [ + { + "id": 1, + "name": " Group 1 Inventory 0" + }, + { + "id": 2, + "name": " Group 2 Inventory 0" + } + ] + }, + "recent_jobs": [ + { + "id": 236, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-26T03:15:21.471439Z" + }, + { + "id": 232, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T21:20:33.593789Z" + }, + { + "id": 229, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:19:46.364134Z" + }, + { + "id": 228, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:18:54.138363Z" + }, + { + "id": 225, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T15:55:32.247652Z" + } + ] + }, + "created": "2020-02-24T15:10:58.922179Z", + "modified": "2020-02-26T21:52:43.428530Z", + "name": ".host-000001.group-00000.dummy", + "description": "", + "inventory": 2, + "enabled": false, + "instance_id": "", + "variables": "", + "has_active_failures": false, + "has_inventory_sources": false, + "last_job": 236, + "last_job_host_summary": 2202, + "insights_system_id": null, + "ansible_facts_modified": null + }, + { + "id": 3, + "type": "host", + "url": "/api/v2/hosts/3/", + "related": { + "created_by": "/api/v2/users/11/", + "modified_by": "/api/v2/users/1/", + "variable_data": "/api/v2/hosts/3/variable_data/", + "groups": "/api/v2/hosts/3/groups/", + "all_groups": "/api/v2/hosts/3/all_groups/", + "job_events": "/api/v2/hosts/3/job_events/", + "job_host_summaries": "/api/v2/hosts/3/job_host_summaries/", + "activity_stream": "/api/v2/hosts/3/activity_stream/", + "inventory_sources": "/api/v2/hosts/3/inventory_sources/", + "smart_inventories": "/api/v2/hosts/3/smart_inventories/", + "ad_hoc_commands": "/api/v2/hosts/3/ad_hoc_commands/", + "ad_hoc_command_events": "/api/v2/hosts/3/ad_hoc_command_events/", + "insights": "/api/v2/hosts/3/insights/", + "ansible_facts": "/api/v2/hosts/3/ansible_facts/", + "inventory": "/api/v2/inventories/2/", + "last_job": "/api/v2/jobs/236/", + "last_job_host_summary": "/api/v2/job_host_summaries/2195/" + }, + "summary_fields": { + "inventory": { + "id": 2, + "name": " Inventory 1 Org 0", + "description": "", + "has_active_failures": false, + "total_hosts": 33, + "hosts_with_active_failures": 0, + "total_groups": 4, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 2, + "kind": "" + }, + "last_job": { + "id": 236, + "name": " Job Template 1 Project 0", + "description": "", + "finished": "2020-02-26T03:15:21.471439Z", + "status": "successful", + "failed": false, + "job_template_id": 18, + "job_template_name": " Job Template 1 Project 0" + }, + "last_job_host_summary": { + "id": 2195, + "failed": false + }, + "created_by": { + "id": 11, + "username": "user-4", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "edit": true, + "delete": true + }, + "groups": { + "count": 2, + "results": [ + { + "id": 1, + "name": " Group 1 Inventory 0" + }, + { + "id": 2, + "name": " Group 2 Inventory 0" + } + ] + }, + "recent_jobs": [ + { + "id": 236, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-26T03:15:21.471439Z" + }, + { + "id": 232, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T21:20:33.593789Z" + }, + { + "id": 229, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:19:46.364134Z" + }, + { + "id": 228, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:18:54.138363Z" + }, + { + "id": 225, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T15:55:32.247652Z" + } + ] + }, + "created": "2020-02-24T15:10:58.945113Z", + "modified": "2020-02-27T03:43:43.635871Z", + "name": ".host-000002.group-00000.dummy", + "description": "", + "inventory": 2, + "enabled": false, + "instance_id": "", + "variables": "", + "has_active_failures": false, + "has_inventory_sources": false, + "last_job": 236, + "last_job_host_summary": 2195, + "insights_system_id": null, + "ansible_facts_modified": null + }, + { + "id": 4, + "type": "host", + "url": "/api/v2/hosts/4/", + "related": { + "created_by": "/api/v2/users/12/", + "modified_by": "/api/v2/users/1/", + "variable_data": "/api/v2/hosts/4/variable_data/", + "groups": "/api/v2/hosts/4/groups/", + "all_groups": "/api/v2/hosts/4/all_groups/", + "job_events": "/api/v2/hosts/4/job_events/", + "job_host_summaries": "/api/v2/hosts/4/job_host_summaries/", + "activity_stream": "/api/v2/hosts/4/activity_stream/", + "inventory_sources": "/api/v2/hosts/4/inventory_sources/", + "smart_inventories": "/api/v2/hosts/4/smart_inventories/", + "ad_hoc_commands": "/api/v2/hosts/4/ad_hoc_commands/", + "ad_hoc_command_events": "/api/v2/hosts/4/ad_hoc_command_events/", + "insights": "/api/v2/hosts/4/insights/", + "ansible_facts": "/api/v2/hosts/4/ansible_facts/", + "inventory": "/api/v2/inventories/2/", + "last_job": "/api/v2/jobs/236/", + "last_job_host_summary": "/api/v2/job_host_summaries/2192/" + }, + "summary_fields": { + "inventory": { + "id": 2, + "name": " Inventory 1 Org 0", + "description": "", + "has_active_failures": false, + "total_hosts": 33, + "hosts_with_active_failures": 0, + "total_groups": 4, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 2, + "kind": "" + }, + "last_job": { + "id": 236, + "name": " Job Template 1 Project 0", + "description": "", + "finished": "2020-02-26T03:15:21.471439Z", + "status": "successful", + "failed": false, + "job_template_id": 18, + "job_template_name": " Job Template 1 Project 0" + }, + "last_job_host_summary": { + "id": 2192, + "failed": false + }, + "created_by": { + "id": 12, + "username": "user-5", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "edit": true, + "delete": true + }, + "groups": { + "count": 2, + "results": [ + { + "id": 1, + "name": " Group 1 Inventory 0" + }, + { + "id": 2, + "name": " Group 2 Inventory 0" + } + ] + }, + "recent_jobs": [ + { + "id": 236, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-26T03:15:21.471439Z" + }, + { + "id": 232, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T21:20:33.593789Z" + }, + { + "id": 229, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:19:46.364134Z" + }, + { + "id": 228, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T16:18:54.138363Z" + }, + { + "id": 225, + "name": " Job Template 1 Project 0", + "status": "successful", + "finished": "2020-02-25T15:55:32.247652Z" + } + ] + }, + "created": "2020-02-24T15:10:58.962312Z", + "modified": "2020-02-27T03:43:45.528882Z", + "name": ".host-000003.group-00000.dummy", + "description": "", + "inventory": 2, + "enabled": false, + "instance_id": "", + "variables": "", + "has_active_failures": false, + "has_inventory_sources": false, + "last_job": 236, + "last_job_host_summary": 2192, + "insights_system_id": null, + "ansible_facts_modified": null + } + ] +} diff --git a/awx/ui_next/src/components/AssociateModal/index.js b/awx/ui_next/src/components/AssociateModal/index.js new file mode 100644 index 000000000000..1a9df3aa33c8 --- /dev/null +++ b/awx/ui_next/src/components/AssociateModal/index.js @@ -0,0 +1 @@ +export { default } from './AssociateModal'; diff --git a/awx/ui_next/src/components/Background/Background.jsx b/awx/ui_next/src/components/Background/Background.jsx new file mode 100644 index 000000000000..755393712c26 --- /dev/null +++ b/awx/ui_next/src/components/Background/Background.jsx @@ -0,0 +1,10 @@ +import React, { Fragment } from 'react'; + +import { BackgroundImage } from '@patternfly/react-core'; + +export default ({ children }) => ( + + + {children} + +); diff --git a/awx/ui_next/src/components/Background/Background.test.jsx b/awx/ui_next/src/components/Background/Background.test.jsx new file mode 100644 index 000000000000..4d306f79a5a1 --- /dev/null +++ b/awx/ui_next/src/components/Background/Background.test.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import Background from './Background'; + +describe('Background', () => { + test('renders the expected content', () => { + const wrapper = mount( + +
+ + ); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.pf-c-background-image')).toHaveLength(1); + expect(wrapper.find('#test')).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/Background/index.js b/awx/ui_next/src/components/Background/index.js new file mode 100644 index 000000000000..5f61d4bc31ce --- /dev/null +++ b/awx/ui_next/src/components/Background/index.js @@ -0,0 +1 @@ +export { default } from './Background'; diff --git a/awx/ui_next/src/components/Card/CardActionsRow.jsx b/awx/ui_next/src/components/Card/CardActionsRow.jsx new file mode 100644 index 000000000000..3652692a8150 --- /dev/null +++ b/awx/ui_next/src/components/Card/CardActionsRow.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { CardActions } from '@patternfly/react-core'; +import styled from 'styled-components'; + +const CardActionsWrapper = styled.div` + margin-top: 20px; + --pf-c-card__actions--PaddingLeft: 0; +`; + +function CardActionsRow({ children }) { + return ( + + {children} + + ); +} + +export default CardActionsRow; diff --git a/awx/ui_next/src/components/Card/CardBody.jsx b/awx/ui_next/src/components/Card/CardBody.jsx new file mode 100644 index 000000000000..095eece1429c --- /dev/null +++ b/awx/ui_next/src/components/Card/CardBody.jsx @@ -0,0 +1,9 @@ +import styled from 'styled-components'; +import { CardBody } from '@patternfly/react-core'; + +const TabbedCardBody = styled(CardBody)` + padding-top: var(--pf-c-card--first-child--PaddingTop); +`; +CardBody.displayName = 'PFCardBody'; + +export default TabbedCardBody; diff --git a/awx/ui_next/src/components/Card/index.js b/awx/ui_next/src/components/Card/index.js new file mode 100644 index 000000000000..93de96efcabf --- /dev/null +++ b/awx/ui_next/src/components/Card/index.js @@ -0,0 +1,2 @@ +export { default as CardBody } from './CardBody'; +export { default as CardActionsRow } from './CardActionsRow'; diff --git a/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.jsx b/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.jsx new file mode 100644 index 000000000000..befaa106745a --- /dev/null +++ b/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + DataListItem, + DataListItemRow, + DataListItemCells, + DataListCheck, + Radio, +} from '@patternfly/react-core'; +import DataListCell from '../DataListCell'; + +const CheckboxListItem = ({ + isDisabled = false, + isRadio = false, + isSelected = false, + itemId, + label, + name, + onDeselect, + onSelect, +}) => { + const CheckboxRadio = isRadio ? Radio : DataListCheck; + + return ( + + + + + + , + ]} + /> + + + ); +}; + +CheckboxListItem.propTypes = { + isSelected: PropTypes.bool.isRequired, + itemId: PropTypes.number.isRequired, + label: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + onDeselect: PropTypes.func.isRequired, + onSelect: PropTypes.func.isRequired, +}; + +export default CheckboxListItem; diff --git a/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.test.jsx b/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.test.jsx new file mode 100644 index 000000000000..3e61d9c98058 --- /dev/null +++ b/awx/ui_next/src/components/CheckboxListItem/CheckboxListItem.test.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import CheckboxListItem from './CheckboxListItem'; + +describe('CheckboxListItem', () => { + test('renders the expected content', () => { + const wrapper = mount( + {}} + onDeselect={() => {}} + /> + ); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/CheckboxListItem/index.js b/awx/ui_next/src/components/CheckboxListItem/index.js new file mode 100644 index 000000000000..f1c4287a66b5 --- /dev/null +++ b/awx/ui_next/src/components/CheckboxListItem/index.js @@ -0,0 +1 @@ +export { default } from './CheckboxListItem'; diff --git a/awx/ui_next/src/components/ChipGroup/ChipGroup.jsx b/awx/ui_next/src/components/ChipGroup/ChipGroup.jsx new file mode 100644 index 000000000000..c16ee052fee9 --- /dev/null +++ b/awx/ui_next/src/components/ChipGroup/ChipGroup.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { ChipGroup as PFChipGroup } from '@patternfly/react-core'; +import { number, shape } from 'prop-types'; + +function ChipGroup({ i18n, numChips, totalChips, i18nHash, ...props }) { + return ( + + ); +} + +ChipGroup.propTypes = { + numChips: number.isRequired, + totalChips: number.isRequired, + i18n: shape({}).isRequired, +}; + +export default withI18n()(ChipGroup); diff --git a/awx/ui_next/src/components/ChipGroup/ChipGroup.test.jsx b/awx/ui_next/src/components/ChipGroup/ChipGroup.test.jsx new file mode 100644 index 000000000000..9e3650370628 --- /dev/null +++ b/awx/ui_next/src/components/ChipGroup/ChipGroup.test.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import ChipGroup from './ChipGroup'; + +describe('ChipGroup', () => { + test('should mount properly', () => { + const wrapper = mountWithContexts( + + ); + expect( + wrapper + .find('ChipGroup') + .at(1) + .props().collapsedText + ).toEqual('5 more'); + }); +}); diff --git a/awx/ui_next/src/components/ChipGroup/index.js b/awx/ui_next/src/components/ChipGroup/index.js new file mode 100644 index 000000000000..e38952cc63bd --- /dev/null +++ b/awx/ui_next/src/components/ChipGroup/index.js @@ -0,0 +1 @@ +export { default } from './ChipGroup'; diff --git a/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.jsx b/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.jsx new file mode 100644 index 000000000000..f2f8b855d6fd --- /dev/null +++ b/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.jsx @@ -0,0 +1,88 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, Tooltip } from '@patternfly/react-core'; +import { CopyIcon } from '@patternfly/react-icons'; + +export const clipboardCopyFunc = (event, text) => { + const clipboard = event.currentTarget.parentElement; + const el = document.createElement('input'); + el.value = text; + clipboard.appendChild(el); + el.select(); + document.execCommand('copy'); + clipboard.removeChild(el); +}; + +class ClipboardCopyButton extends React.Component { + constructor(props) { + super(props); + + this.state = { + copied: false, + }; + + this.handleCopyClick = this.handleCopyClick.bind(this); + } + + handleCopyClick = event => { + const { stringToCopy, switchDelay } = this.props; + if (this.timer) { + window.clearTimeout(this.timer); + this.setState({ copied: false }); + } + clipboardCopyFunc(event, stringToCopy); + this.setState({ copied: true }, () => { + this.timer = window.setTimeout(() => { + this.setState({ copied: false }); + this.timer = null; + }, switchDelay); + }); + }; + + render() { + const { + copyTip, + entryDelay, + exitDelay, + copiedSuccessTip, + isDisabled, + } = this.props; + const { copied } = this.state; + + return ( + + + + ); + } +} + +ClipboardCopyButton.propTypes = { + copyTip: PropTypes.string.isRequired, + entryDelay: PropTypes.number, + exitDelay: PropTypes.number, + copiedSuccessTip: PropTypes.string.isRequired, + stringToCopy: PropTypes.string.isRequired, + switchDelay: PropTypes.number, + isDisabled: PropTypes.bool.isRequired, +}; + +ClipboardCopyButton.defaultProps = { + entryDelay: 100, + exitDelay: 1600, + switchDelay: 2000, +}; + +export default ClipboardCopyButton; diff --git a/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.test.jsx b/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.test.jsx new file mode 100644 index 000000000000..f777976135cd --- /dev/null +++ b/awx/ui_next/src/components/ClipboardCopyButton/ClipboardCopyButton.test.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import ClipboardCopyButton from './ClipboardCopyButton'; + +document.execCommand = jest.fn(); + +jest.useFakeTimers(); + +describe('ClipboardCopyButton', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper).toHaveLength(1); + }); + test('clicking button calls execCommand to copy to clipboard', () => { + const wrapper = mountWithContexts( + + ).find('ClipboardCopyButton'); + expect(wrapper.state('copied')).toBe(false); + wrapper.find('Button').simulate('click'); + expect(document.execCommand).toBeCalledWith('copy'); + expect(wrapper.state('copied')).toBe(true); + jest.runAllTimers(); + wrapper.update(); + expect(wrapper.state('copied')).toBe(false); + }); + test('should render disabled button', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('Button').prop('isDisabled')).toBe(true); + }); +}); diff --git a/awx/ui_next/src/components/ClipboardCopyButton/index.js b/awx/ui_next/src/components/ClipboardCopyButton/index.js new file mode 100644 index 000000000000..45adfe436ee3 --- /dev/null +++ b/awx/ui_next/src/components/ClipboardCopyButton/index.js @@ -0,0 +1 @@ +export { default } from './ClipboardCopyButton'; diff --git a/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorField.jsx b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorField.jsx new file mode 100644 index 000000000000..35ebf3272189 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorField.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { + string, + oneOfType, + object, + func, + bool, + node, + oneOf, + number, +} from 'prop-types'; +import { useField } from 'formik'; +import { FormGroup } from '@patternfly/react-core'; +import CodeMirrorInput from './CodeMirrorInput'; +import Popover from '../Popover'; + +function CodeMirrorField({ + id, + name, + label, + tooltip, + helperText, + validate, + isRequired, + mode, + ...rest +}) { + const [field, meta, helpers] = useField({ name, validate }); + const isValid = !(meta.touched && meta.error); + + return ( + } + > + { + helpers.setValue(value); + }} + mode={mode} + /> + + ); +} +CodeMirrorField.propTypes = { + helperText: string, + id: string.isRequired, + name: string.isRequired, + label: oneOfType([object, string]).isRequired, + validate: func, + isRequired: bool, + tooltip: node, + mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, + rows: number, +}; + +CodeMirrorField.defaultProps = { + helperText: '', + validate: () => {}, + isRequired: false, + tooltip: null, + rows: 5, +}; + +export default CodeMirrorField; diff --git a/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.jsx b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.jsx new file mode 100644 index 000000000000..a07b6feca57f --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.jsx @@ -0,0 +1,135 @@ +import React, { useState, useEffect } from 'react'; +import { oneOf, bool, number, string, func } from 'prop-types'; +import { Controlled as ReactCodeMirror } from 'react-codemirror2'; +import styled from 'styled-components'; +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/mode/yaml/yaml'; +import 'codemirror/mode/jinja2/jinja2'; +import 'codemirror/lib/codemirror.css'; +import 'codemirror/addon/display/placeholder'; + +const LINE_HEIGHT = 24; +const PADDING = 12; + +const CodeMirror = styled(ReactCodeMirror)` + && { + height: initial; + padding: 0; + } + + & > .CodeMirror { + height: ${props => + props.fullHeight ? 'auto' : `${props.rows * LINE_HEIGHT + PADDING}px`}; + font-family: var(--pf-global--FontFamily--monospace); + } + + ${props => + props.hasErrors && + ` + && { + --pf-c-form-control--PaddingRight: var(--pf-c-form-control--invalid--PaddingRight); + --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--invalid--BorderBottomColor); + padding-right: 24px; + padding-bottom: var(--pf-c-form-control--invalid--PaddingBottom); + background: var(--pf-c-form-control--invalid--Background); + border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth); + }`} + + ${props => + props.options && + props.options.readOnly && + ` + &, + &:hover { + --pf-c-form-control--BorderBottomColor: var(--pf-global--BorderColor--300); + } + + .CodeMirror-cursors { + display: none; + } + + .CodeMirror-lines { + cursor: default; + } + + .CodeMirror-scroll { + background-color: var(--pf-c-form-control--disabled--BackgroundColor); + } + `} + ${props => + props.options && + props.options.placeholder && + ` + .CodeMirror-empty { + pre.CodeMirror-placeholder { + color: var(--pf-c-form-control--placeholder--Color); + height: 100% !important; + } + } + `} +`; + +function CodeMirrorInput({ + value, + onChange, + mode, + readOnly, + hasErrors, + rows, + fullHeight, + className, + placeholder, +}) { + // Workaround for CodeMirror bug: If CodeMirror renders in a modal on the + // modal's initial render, it appears as an empty box due to mis-calculated + // element height. Forcing an initial render before mounting + // fixes this. + const [isInitialized, setIsInitialized] = useState(false); + useEffect(() => { + if (!isInitialized) { + setIsInitialized(true); + } + }, [isInitialized]); + if (!isInitialized) { + return
; + } + + return ( + onChange(val)} + mode={mode} + hasErrors={hasErrors} + options={{ + smartIndent: false, + lineNumbers: true, + lineWrapping: true, + placeholder, + readOnly, + }} + fullHeight={fullHeight} + rows={rows} + /> + ); +} +CodeMirrorInput.propTypes = { + value: string.isRequired, + onChange: func, + mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, + readOnly: bool, + hasErrors: bool, + fullHeight: bool, + rows: number, + className: string, +}; +CodeMirrorInput.defaultProps = { + readOnly: false, + onChange: () => {}, + rows: 6, + fullHeight: false, + hasErrors: false, + className: '', +}; + +export default CodeMirrorInput; diff --git a/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.test.jsx b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.test.jsx new file mode 100644 index 000000000000..aaf9d3311835 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/CodeMirrorInput.test.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import CodeMirrorInput from './CodeMirrorInput'; + +describe('CodeMirrorInput', () => { + beforeEach(() => { + document.body.createTextRange = jest.fn(); + }); + + it('should trigger onChange prop', () => { + const onChange = jest.fn(); + const wrapper = mount( + + ); + const codemirror = wrapper.find('Controlled'); + expect(codemirror.prop('mode')).toEqual('yaml'); + expect(codemirror.prop('options').readOnly).toEqual(false); + codemirror.prop('onBeforeChange')(null, null, 'newvalue'); + expect(onChange).toHaveBeenCalledWith('newvalue'); + }); + + it('should render in read only mode', () => { + const onChange = jest.fn(); + const wrapper = mount( + + ); + const codemirror = wrapper.find('Controlled'); + expect(codemirror.prop('options').readOnly).toEqual(true); + }); +}); diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx new file mode 100644 index 000000000000..feb3ebb0b789 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx @@ -0,0 +1,134 @@ +import 'styled-components/macro'; +import React, { useState, useEffect } from 'react'; +import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types'; +import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core'; +import { DetailName, DetailValue } from '../DetailList'; +import MultiButtonToggle from '../MultiButtonToggle'; +import Popover from '../Popover'; +import { + yamlToJson, + jsonToYaml, + isJsonObject, + isJsonString, +} from '../../util/yaml'; +import CodeMirrorInput from './CodeMirrorInput'; +import { JSON_MODE, YAML_MODE } from './constants'; + +function getValueAsMode(value, mode) { + if (!value) { + if (mode === JSON_MODE) { + return '{}'; + } + return '---'; + } + const modeMatches = isJsonString(value) === (mode === JSON_MODE); + if (modeMatches) { + return value; + } + return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value); +} + +function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) { + const [mode, setMode] = useState( + isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE + ); + const [currentValue, setCurrentValue] = useState( + isJsonObject(value) ? JSON.stringify(value, null, 2) : value || '---' + ); + const [error, setError] = useState(null); + + useEffect(() => { + setCurrentValue( + getValueAsMode( + isJsonObject(value) ? JSON.stringify(value, null, 2) : value, + mode + ) + ); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [value]); + + const labelCy = dataCy ? `${dataCy}-label` : null; + const valueCy = dataCy ? `${dataCy}-value` : null; + + return ( + <> + + + +
+ + {label} + + {helpText && ( + + )} +
+
+ + { + try { + setCurrentValue(getValueAsMode(currentValue, newMode)); + setMode(newMode); + } catch (err) { + setError(err); + } + }} + /> + +
+
+ + + {error && ( +
+ Error: {error.message} +
+ )} +
+ + ); +} +VariablesDetail.propTypes = { + value: oneOfType([shape({}), arrayOf(string), string]).isRequired, + label: node.isRequired, + rows: number, + dataCy: string, + helpText: string, +}; +VariablesDetail.defaultProps = { + rows: null, + dataCy: '', + helpText: '', +}; + +export default VariablesDetail; diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx new file mode 100644 index 000000000000..edb83d3515e6 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { shallow, mount } from 'enzyme'; +import VariablesDetail from './VariablesDetail'; + +jest.mock('../../api'); + +describe('', () => { + test('should render readonly CodeMirrorInput', () => { + const wrapper = shallow( + + ); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input).toHaveLength(1); + expect(input.prop('mode')).toEqual('yaml'); + expect(input.prop('value')).toEqual('---foo: bar'); + expect(input.prop('readOnly')).toEqual(true); + }); + + test('should detect JSON', () => { + const wrapper = shallow( + + ); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input).toHaveLength(1); + expect(input.prop('mode')).toEqual('javascript'); + expect(input.prop('value')).toEqual('{"foo": "bar"}'); + }); + + test('should convert between modes', () => { + const wrapper = shallow( + + ); + wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input.prop('mode')).toEqual('javascript'); + expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}'); + + wrapper.find('MultiButtonToggle').invoke('onChange')('yaml'); + const input2 = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input2.prop('mode')).toEqual('yaml'); + expect(input2.prop('value')).toEqual('foo: bar\n'); + }); + + test('should render label and value= --- when there are no values', () => { + const wrapper = shallow(); + expect(wrapper.find('VariablesDetail___StyledCodeMirrorInput').length).toBe( + 1 + ); + expect(wrapper.find('div.pf-c-form__label').text()).toBe('Variables'); + }); + + test('should update value if prop changes', () => { + const wrapper = mount( + + ); + act(() => { + wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); + }); + wrapper.setProps({ + value: '---bar: baz', + }); + wrapper.update(); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input.prop('mode')).toEqual('javascript'); + expect(input.prop('value')).toEqual('{\n "bar": "baz"\n}'); + }); + + test('should default yaml value to "---"', () => { + const wrapper = shallow(); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input.prop('value')).toEqual('---'); + }); + + test('should default empty json to "{}"', () => { + const wrapper = mount(); + act(() => { + wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); + }); + wrapper.setProps({ value: '' }); + const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); + expect(input.prop('value')).toEqual('{}'); + }); +}); diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx new file mode 100644 index 000000000000..1db21fdf0431 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx @@ -0,0 +1,108 @@ +import React, { useState } from 'react'; +import { string, bool } from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { useField } from 'formik'; +import styled from 'styled-components'; +import { Split, SplitItem } from '@patternfly/react-core'; +import { CheckboxField } from '../FormField'; +import MultiButtonToggle from '../MultiButtonToggle'; +import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml'; +import CodeMirrorInput from './CodeMirrorInput'; +import Popover from '../Popover'; +import { JSON_MODE, YAML_MODE } from './constants'; + +const FieldHeader = styled.div` + display: flex; + justify-content: space-between; + padding-bottom: var(--pf-c-form__group-label--PaddingBottom); +`; + +const StyledCheckboxField = styled(CheckboxField)` + --pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize); +`; + +function VariablesField({ + i18n, + id, + name, + label, + readOnly, + promptId, + tooltip, +}) { + const [field, meta, helpers] = useField(name); + const [mode, setMode] = useState( + isJsonString(field.value) ? JSON_MODE : YAML_MODE + ); + + return ( +
+ + + + + {tooltip && } + + + { + try { + const newVal = + newMode === YAML_MODE + ? jsonToYaml(field.value) + : yamlToJson(field.value); + helpers.setValue(newVal); + setMode(newMode); + } catch (err) { + helpers.setError(err.message); + } + }} + /> + + + {promptId && ( + + )} + + { + helpers.setValue(newVal); + }} + hasErrors={!!meta.error} + /> + {meta.error ? ( +
+ {meta.error} +
+ ) : null} +
+ ); +} +VariablesField.propTypes = { + id: string.isRequired, + name: string.isRequired, + label: string.isRequired, + readOnly: bool, + promptId: string, +}; +VariablesField.defaultProps = { + readOnly: false, + promptId: null, +}; + +export default withI18n()(VariablesField); diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.test.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.test.jsx new file mode 100644 index 000000000000..d2249b853d17 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.test.jsx @@ -0,0 +1,134 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { Formik } from 'formik'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import VariablesField from './VariablesField'; + +describe('VariablesField', () => { + beforeEach(() => { + document.body.createTextRange = jest.fn(); + }); + + it('should render code mirror input', () => { + const value = '---\n'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + const codemirror = wrapper.find('Controlled'); + expect(codemirror.prop('value')).toEqual(value); + }); + + it('should render yaml/json toggles', async () => { + const value = '---\n'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + const buttons = wrapper.find('Button'); + expect(buttons).toHaveLength(2); + expect(buttons.at(0).prop('variant')).toEqual('primary'); + expect(buttons.at(1).prop('variant')).toEqual('secondary'); + await act(async () => { + buttons.at(1).simulate('click'); + }); + wrapper.update(); + expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('javascript'); + const buttons2 = wrapper.find('Button'); + expect(buttons2.at(0).prop('variant')).toEqual('secondary'); + expect(buttons2.at(1).prop('variant')).toEqual('primary'); + await act(async () => { + buttons2.at(0).simulate('click'); + }); + wrapper.update(); + expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('yaml'); + }); + + it('should set Formik error if yaml is invalid', async () => { + const value = '---\nfoo bar\n'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + wrapper + .find('Button') + .at(1) + .simulate('click'); + wrapper.update(); + + const field = wrapper.find('CodeMirrorInput'); + expect(field.prop('hasErrors')).toEqual(true); + expect(wrapper.find('.pf-m-error')).toHaveLength(1); + }); + it('should render tooltip', () => { + const value = '---\n'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + expect(wrapper.find('Popover[data-cy="the-field"]').length).toBe(1); + }); + + it('should submit value through Formik', async () => { + const value = '---\nfoo: bar\n'; + const handleSubmit = jest.fn(); + const wrapper = mountWithContexts( + + {formik => ( +
+ + + + )} +
+ ); + await act(async () => { + wrapper.find('CodeMirrorInput').invoke('onChange')( + '---\nnewval: changed' + ); + wrapper.find('form').simulate('submit'); + }); + + expect(handleSubmit).toHaveBeenCalled(); + expect(handleSubmit.mock.calls[0][0]).toEqual({ + variables: '---\nnewval: changed', + }); + }); + + it('should initialize to JSON if value is JSON', async () => { + const value = '{"foo": "bar"}'; + const wrapper = mountWithContexts( + + {formik => ( +
+ + + + )} +
+ ); + + expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('javascript'); + }); +}); diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesInput.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesInput.jsx new file mode 100644 index 000000000000..a43962bd764b --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesInput.jsx @@ -0,0 +1,102 @@ +import React, { useState } from 'react'; +import { string, func, bool, number } from 'prop-types'; +import { Split, SplitItem } from '@patternfly/react-core'; +import styled from 'styled-components'; +import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml'; +import MultiButtonToggle from '../MultiButtonToggle'; +import CodeMirrorInput from './CodeMirrorInput'; +import { JSON_MODE, YAML_MODE } from './constants'; + +function formatJson(jsonString) { + return JSON.stringify(JSON.parse(jsonString), null, 2); +} + +const SplitItemRight = styled(SplitItem)` + margin-bottom: 5px; +`; + +function VariablesInput(props) { + const { id, label, readOnly, rows, error, onError, className } = props; + /* eslint-disable react/destructuring-assignment */ + const defaultValue = isJsonString(props.value) + ? formatJson(props.value) + : props.value; + const [value, setValue] = useState(defaultValue); + const [mode, setMode] = useState(isJsonString(value) ? JSON_MODE : YAML_MODE); + const isControlled = !!props.onChange; + /* eslint-enable react/destructuring-assignment */ + + const onChange = newValue => { + if (isControlled) { + props.onChange(newValue); + } + setValue(newValue); + }; + + return ( +
+ + + + + + { + try { + if (mode === JSON_MODE) { + onChange(jsonToYaml(value)); + } else { + onChange(yamlToJson(value)); + } + setMode(newMode); + } catch (err) { + onError(err.message); + } + }} + /> + + + + {error ? ( +
+ {error} +
+ ) : null} +
+ ); +} +VariablesInput.propTypes = { + id: string.isRequired, + label: string.isRequired, + value: string.isRequired, + readOnly: bool, + error: string, + rows: number, + onChange: func, + onError: func, +}; +VariablesInput.defaultProps = { + readOnly: false, + onChange: null, + rows: 6, + error: null, + onError: () => {}, +}; + +export default styled(VariablesInput)` + --pf-c-form__label--FontSize: var(--pf-global--FontSize--sm); +`; diff --git a/awx/ui_next/src/components/CodeMirrorInput/constants.js b/awx/ui_next/src/components/CodeMirrorInput/constants.js new file mode 100644 index 000000000000..79f71887e2bf --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/constants.js @@ -0,0 +1,2 @@ +export const YAML_MODE = 'yaml'; +export const JSON_MODE = 'javascript'; diff --git a/awx/ui_next/src/components/CodeMirrorInput/index.js b/awx/ui_next/src/components/CodeMirrorInput/index.js new file mode 100644 index 000000000000..2c60b806f5d8 --- /dev/null +++ b/awx/ui_next/src/components/CodeMirrorInput/index.js @@ -0,0 +1,7 @@ +import CodeMirrorInput from './CodeMirrorInput'; + +export default CodeMirrorInput; +export { default as CodeMirrorField } from './CodeMirrorField'; +export { default as VariablesDetail } from './VariablesDetail'; +export { default as VariablesInput } from './VariablesInput'; +export { default as VariablesField } from './VariablesField'; diff --git a/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.jsx b/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.jsx new file mode 100644 index 000000000000..b9e60385b8e2 --- /dev/null +++ b/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.jsx @@ -0,0 +1,58 @@ +import React, { useState } from 'react'; +import { bool, string } from 'prop-types'; +import styled from 'styled-components'; +import { Button } from '@patternfly/react-core'; +import { AngleRightIcon } from '@patternfly/react-icons'; +import omitProps from '../../util/omitProps'; +import ExpandingContainer from './ExpandingContainer'; + +// Make button findable by tests +Button.displayName = 'Button'; + +const Toggle = styled.div` + display: flex; + + hr { + margin-left: 20px; + flex: 1 1 auto; + align-self: center; + border: 0; + border-bottom: 1px solid var(--pf-global--BorderColor--300); + } +`; + +const Arrow = styled(omitProps(AngleRightIcon, 'isExpanded'))` + margin-right: -5px; + margin-left: 5px; + transition: transform 0.1s ease-out; + transform-origin: 50% 50%; + ${props => props.isExpanded && `transform: rotate(90deg);`} +`; + +function CollapsibleSection({ label, startExpanded, children }) { + const [isExpanded, setIsExpanded] = useState(startExpanded); + const toggle = () => setIsExpanded(!isExpanded); + + return ( +
+ + +
+
+ + {children} + +
+ ); +} +CollapsibleSection.propTypes = { + label: string.isRequired, + startExpanded: bool, +}; +CollapsibleSection.defaultProps = { + startExpanded: false, +}; + +export default CollapsibleSection; diff --git a/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.test.jsx b/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.test.jsx new file mode 100644 index 000000000000..d3b5d099307a --- /dev/null +++ b/awx/ui_next/src/components/CollapsibleSection/CollapsibleSection.test.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import CollapsibleSection from './CollapsibleSection'; + +describe('', () => { + it('should render contents', () => { + const wrapper = shallow( + foo + ); + expect(wrapper.find('Button > *').prop('isExpanded')).toEqual(false); + expect(wrapper.find('ExpandingContainer').prop('isExpanded')).toEqual( + false + ); + expect(wrapper.find('ExpandingContainer').prop('children')).toEqual('foo'); + }); + + it('should toggle when clicked', () => { + const wrapper = shallow( + foo + ); + expect(wrapper.find('Button > *').prop('isExpanded')).toEqual(false); + wrapper.find('Button').simulate('click'); + expect(wrapper.find('Button > *').prop('isExpanded')).toEqual(true); + expect(wrapper.find('ExpandingContainer').prop('isExpanded')).toEqual(true); + }); +}); diff --git a/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx b/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx new file mode 100644 index 000000000000..346297c94afe --- /dev/null +++ b/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx @@ -0,0 +1,44 @@ +import 'styled-components/macro'; +import React, { useState, useEffect, useRef } from 'react'; +import { bool } from 'prop-types'; +import styled from 'styled-components'; + +const Container = styled.div` + margin: 15px 0; + transition: height 0.2s ease-out; + ${props => props.hideOverflow && `overflow: hidden;`} +`; + +function ExpandingContainer({ isExpanded, children }) { + const [contentHeight, setContentHeight] = useState(0); + const [hideOverflow, setHideOverflow] = useState(!isExpanded); + const ref = useRef(null); + useEffect(() => { + ref.current.addEventListener('transitionend', () => { + setHideOverflow(!isExpanded); + }); + }); + useEffect(() => { + setContentHeight(ref.current.scrollHeight); + }, [setContentHeight, children]); + const height = isExpanded ? contentHeight : '0'; + return ( + + {children} + + ); +} +ExpandingContainer.propTypes = { + isExpanded: bool, +}; +ExpandingContainer.defaultProps = { + isExpanded: false, +}; + +export default ExpandingContainer; diff --git a/awx/ui_next/src/components/CollapsibleSection/index.js b/awx/ui_next/src/components/CollapsibleSection/index.js new file mode 100644 index 000000000000..a4623e90ed44 --- /dev/null +++ b/awx/ui_next/src/components/CollapsibleSection/index.js @@ -0,0 +1 @@ +export { default } from './CollapsibleSection'; diff --git a/awx/ui_next/src/components/ContentEmpty/ContentEmpty.jsx b/awx/ui_next/src/components/ContentEmpty/ContentEmpty.jsx new file mode 100644 index 000000000000..58b34e0dcdae --- /dev/null +++ b/awx/ui_next/src/components/ContentEmpty/ContentEmpty.jsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { + Title, + EmptyState, + EmptyStateIcon, + EmptyStateBody, +} from '@patternfly/react-core'; +import { CubesIcon } from '@patternfly/react-icons'; + +const ContentEmpty = ({ i18n, title = '', message = '' }) => ( + + + + {title || i18n._(t`No items found.`)} + + {message} + +); + +export { ContentEmpty as _ContentEmpty }; +export default withI18n()(ContentEmpty); diff --git a/awx/ui_next/src/components/ContentEmpty/ContentEmpty.test.jsx b/awx/ui_next/src/components/ContentEmpty/ContentEmpty.test.jsx new file mode 100644 index 000000000000..6498dc76cc78 --- /dev/null +++ b/awx/ui_next/src/components/ContentEmpty/ContentEmpty.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import ContentEmpty from './ContentEmpty'; + +describe('ContentEmpty', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts(); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/ContentEmpty/index.js b/awx/ui_next/src/components/ContentEmpty/index.js new file mode 100644 index 000000000000..cdf62bc88112 --- /dev/null +++ b/awx/ui_next/src/components/ContentEmpty/index.js @@ -0,0 +1 @@ +export { default } from './ContentEmpty'; diff --git a/awx/ui_next/src/components/ContentError/ContentError.jsx b/awx/ui_next/src/components/ContentError/ContentError.jsx new file mode 100644 index 000000000000..3c56a2630daf --- /dev/null +++ b/awx/ui_next/src/components/ContentError/ContentError.jsx @@ -0,0 +1,67 @@ +import React, { Fragment } from 'react'; +import { Link, Redirect } from 'react-router-dom'; +import { bool, instanceOf } from 'prop-types'; +import { t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { + Title, + EmptyState, + EmptyStateIcon, + EmptyStateBody, +} from '@patternfly/react-core'; +import { ExclamationTriangleIcon } from '@patternfly/react-icons'; +import { RootAPI } from '../../api'; +import ErrorDetail from '../ErrorDetail'; + +async function logout() { + await RootAPI.logout(); + window.location.replace('/#/login'); +} + +function ContentError({ error, children, isNotFound, i18n }) { + if (error && error.response && error.response.status === 401) { + if (!error.response.headers['session-timeout']) { + logout(); + return null; + } + } + const is404 = + isNotFound || (error && error.response && error.response.status === 404); + const is401 = error && error.response && error.response.status === 401; + return ( + + {is401 ? ( + + ) : ( + + + + {is404 ? i18n._(t`Not Found`) : i18n._(t`Something went wrong...`)} + + + {is404 + ? i18n._(t`The page you requested could not be found.`) + : i18n._( + t`There was an error loading this content. Please reload the page.` + )}{' '} + {children || ( + {i18n._(t`Back to Dashboard.`)} + )} + + {error && } + + )} + + ); +} +ContentError.propTypes = { + error: instanceOf(Error), + isNotFound: bool, +}; +ContentError.defaultProps = { + error: null, + isNotFound: false, +}; + +export { ContentError as _ContentError }; +export default withI18n()(ContentError); diff --git a/awx/ui_next/src/components/ContentError/ContentError.test.jsx b/awx/ui_next/src/components/ContentError/ContentError.test.jsx new file mode 100644 index 000000000000..518f0ae8c65d --- /dev/null +++ b/awx/ui_next/src/components/ContentError/ContentError.test.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import ContentError from './ContentError'; + +describe('ContentError', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/ContentError/index.js b/awx/ui_next/src/components/ContentError/index.js new file mode 100644 index 000000000000..14587f410d50 --- /dev/null +++ b/awx/ui_next/src/components/ContentError/index.js @@ -0,0 +1 @@ +export { default } from './ContentError'; diff --git a/awx/ui_next/src/components/ContentLoading/ContentLoading.jsx b/awx/ui_next/src/components/ContentLoading/ContentLoading.jsx new file mode 100644 index 000000000000..9808cc02af09 --- /dev/null +++ b/awx/ui_next/src/components/ContentLoading/ContentLoading.jsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import styled from 'styled-components'; +import { + EmptyState as PFEmptyState, + EmptyStateIcon, + Spinner, +} from '@patternfly/react-core'; + +const EmptyState = styled(PFEmptyState)` + --pf-c-empty-state--m-lg--MaxWidth: none; + min-height: 250px; +`; + +// TODO: Better loading state - skeleton lines / spinner, etc. +const ContentLoading = ({ className }) => { + return ( + + + + ); +}; + +export { ContentLoading as _ContentLoading }; +export default ContentLoading; diff --git a/awx/ui_next/src/components/ContentLoading/ContentLoading.test.jsx b/awx/ui_next/src/components/ContentLoading/ContentLoading.test.jsx new file mode 100644 index 000000000000..c2816e258272 --- /dev/null +++ b/awx/ui_next/src/components/ContentLoading/ContentLoading.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import ContentLoading from './ContentLoading'; + +describe('ContentLoading', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts(); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/ContentLoading/index.js b/awx/ui_next/src/components/ContentLoading/index.js new file mode 100644 index 000000000000..0e87a3fb97db --- /dev/null +++ b/awx/ui_next/src/components/ContentLoading/index.js @@ -0,0 +1 @@ +export { default } from './ContentLoading'; diff --git a/awx/ui_next/src/components/CopyButton/CopyButton.jsx b/awx/ui_next/src/components/CopyButton/CopyButton.jsx new file mode 100644 index 000000000000..fe4580f4bf0d --- /dev/null +++ b/awx/ui_next/src/components/CopyButton/CopyButton.jsx @@ -0,0 +1,74 @@ +import React, { useEffect } from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import PropTypes from 'prop-types'; + +import { Button, Tooltip } from '@patternfly/react-core'; +import { CopyIcon } from '@patternfly/react-icons'; +import useRequest, { useDismissableError } from '../../util/useRequest'; +import AlertModal from '../AlertModal'; +import ErrorDetail from '../ErrorDetail'; + +function CopyButton({ + i18n, + copyItem, + isDisabled, + onCopyStart, + onCopyFinish, + helperText, +}) { + const { isLoading, error: copyError, request: copyItemToAPI } = useRequest( + copyItem + ); + + useEffect(() => { + if (isLoading) { + return onCopyStart(); + } + return onCopyFinish(); + }, [isLoading, onCopyStart, onCopyFinish]); + + const { error, dismissError } = useDismissableError(copyError); + + return ( + <> + + + + + {helperText.errorMessage} + + + + ); +} + +CopyButton.propTypes = { + copyItem: PropTypes.func.isRequired, + onCopyStart: PropTypes.func.isRequired, + onCopyFinish: PropTypes.func.isRequired, + helperText: PropTypes.shape({ + tooltip: PropTypes.string.isRequired, + errorMessage: PropTypes.string.isRequired, + }).isRequired, + isDisabled: PropTypes.bool, +}; + +CopyButton.defaultProps = { + isDisabled: false, +}; + +export default withI18n()(CopyButton); diff --git a/awx/ui_next/src/components/CopyButton/CopyButton.test.jsx b/awx/ui_next/src/components/CopyButton/CopyButton.test.jsx new file mode 100644 index 000000000000..f81c0eab1d9c --- /dev/null +++ b/awx/ui_next/src/components/CopyButton/CopyButton.test.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import CopyButton from './CopyButton'; + +jest.mock('../../api'); + +describe('', () => { + test('shold mount properly', () => { + const wrapper = mountWithContexts( + {}} + onCopyFinish={() => {}} + copyItem={() => {}} + helperText={{ + tooltip: `Copy Template`, + errorMessage: `Failed to copy template.`, + }} + /> + ); + expect(wrapper.find('CopyButton').length).toBe(1); + }); + test('should render proper tooltip', () => { + const wrapper = mountWithContexts( + {}} + onCopyFinish={() => {}} + copyItem={() => {}} + helperText={{ + tooltip: `Copy Template`, + errorMessage: `Failed to copy template.`, + }} + /> + ); + expect(wrapper.find('Tooltip').prop('content')).toBe('Copy Template'); + }); +}); diff --git a/awx/ui_next/src/components/CopyButton/index.js b/awx/ui_next/src/components/CopyButton/index.js new file mode 100644 index 000000000000..90e9e6d2043d --- /dev/null +++ b/awx/ui_next/src/components/CopyButton/index.js @@ -0,0 +1 @@ +export { default } from './CopyButton'; diff --git a/awx/ui_next/src/components/CredentialChip/CredentialChip.jsx b/awx/ui_next/src/components/CredentialChip/CredentialChip.jsx new file mode 100644 index 000000000000..7dd5b055b50e --- /dev/null +++ b/awx/ui_next/src/components/CredentialChip/CredentialChip.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { shape } from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Chip } from '@patternfly/react-core'; +import { Credential } from '../../types'; +import { toTitleCase } from '../../util/strings'; + +function CredentialChip({ credential, i18n, i18nHash, ...props }) { + let type; + if (credential.cloud) { + type = i18n._(t`Cloud`); + } else if (credential.kind === 'aws' || credential.kind === 'ssh') { + type = credential.kind.toUpperCase(); + } else { + type = toTitleCase(credential.kind); + } + + const buildCredentialName = () => { + if (credential.kind === 'vault' && credential.inputs?.vault_id) { + return `${credential.name} | ${credential.inputs.vault_id}`; + } + return `${credential.name}`; + }; + + return ( + + {type}: + {buildCredentialName()} + + ); +} +CredentialChip.propTypes = { + credential: Credential.isRequired, + i18n: shape({}).isRequired, +}; + +export { CredentialChip as _CredentialChip }; +export default withI18n()(CredentialChip); diff --git a/awx/ui_next/src/components/CredentialChip/CredentialChip.test.jsx b/awx/ui_next/src/components/CredentialChip/CredentialChip.test.jsx new file mode 100644 index 000000000000..df678d5d23ce --- /dev/null +++ b/awx/ui_next/src/components/CredentialChip/CredentialChip.test.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import CredentialChip from './CredentialChip'; + +describe('CredentialChip', () => { + test('should render SSH kind', () => { + const credential = { + id: 1, + kind: 'ssh', + name: 'foo', + }; + + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('CredentialChip').text()).toEqual('SSH: foo'); + }); + + test('should render AWS kind', () => { + const credential = { + id: 1, + kind: 'aws', + name: 'foo', + }; + + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('CredentialChip').text()).toEqual('AWS: foo'); + }); + + test('should render with "Cloud"', () => { + const credential = { + id: 1, + cloud: true, + kind: 'other', + name: 'foo', + }; + + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('CredentialChip').text()).toEqual('Cloud: foo'); + }); + + test('should render with other kind', () => { + const credential = { + id: 1, + kind: 'other', + name: 'foo', + }; + + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('CredentialChip').text()).toEqual('Other: foo'); + }); +}); diff --git a/awx/ui_next/src/components/CredentialChip/index.js b/awx/ui_next/src/components/CredentialChip/index.js new file mode 100644 index 000000000000..c4cb5cc38a55 --- /dev/null +++ b/awx/ui_next/src/components/CredentialChip/index.js @@ -0,0 +1 @@ +export { default } from './CredentialChip'; diff --git a/awx/ui_next/src/components/DataListCell/DataListCell.jsx b/awx/ui_next/src/components/DataListCell/DataListCell.jsx new file mode 100644 index 000000000000..79aff02595e9 --- /dev/null +++ b/awx/ui_next/src/components/DataListCell/DataListCell.jsx @@ -0,0 +1,12 @@ +import { DataListCell as PFDataListCell } from '@patternfly/react-core'; +import styled from 'styled-components'; + +PFDataListCell.displayName = 'PFDataListCell'; +// Once https://github.com/patternfly/patternfly-react/issues/3938 +// has been resolved this component can be removed +const DataListCell = styled(PFDataListCell)` + word-break: break-word; +`; +DataListCell.displayName = 'DataListCell'; + +export default DataListCell; diff --git a/awx/ui_next/src/components/DataListCell/index.js b/awx/ui_next/src/components/DataListCell/index.js new file mode 100644 index 000000000000..d925b63c7d7e --- /dev/null +++ b/awx/ui_next/src/components/DataListCell/index.js @@ -0,0 +1 @@ +export { default } from './DataListCell'; diff --git a/awx/ui_next/src/components/DataListToolbar/DataListToolbar.jsx b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.jsx new file mode 100644 index 000000000000..e52ae1c2cb64 --- /dev/null +++ b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.jsx @@ -0,0 +1,193 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { + Checkbox, + Toolbar, + ToolbarContent, + ToolbarGroup, + ToolbarItem, + ToolbarToggleGroup, + Dropdown, + KebabToggle, +} from '@patternfly/react-core'; +import { SearchIcon } from '@patternfly/react-icons'; +import ExpandCollapse from '../ExpandCollapse'; +import Search from '../Search'; +import Sort from '../Sort'; +import { SearchColumns, SortColumns, QSConfig } from '../../types'; +import { KebabifiedProvider } from '../../contexts/Kebabified'; + +function DataListToolbar({ + itemCount, + clearAllFilters, + searchColumns, + searchableKeys, + relatedSearchableKeys, + sortColumns, + showSelectAll, + isAllSelected, + isCompact, + onSort, + onSearch, + onReplaceSearch, + onRemove, + onCompact, + onExpand, + onSelectAll, + additionalControls, + i18n, + qsConfig, + pagination, +}) { + const showExpandCollapse = onCompact && onExpand; + const [isKebabOpen, setIsKebabOpen] = useState(false); + const [isKebabModalOpen, setIsKebabModalOpen] = useState(false); + const [isAdvancedSearchShown, setIsAdvancedSearchShown] = useState(false); + + const onShowAdvancedSearch = shown => { + setIsAdvancedSearchShown(shown); + setIsKebabOpen(false); + }; + + useEffect(() => { + if (!isKebabModalOpen) { + setIsKebabOpen(false); + } + }, [isKebabModalOpen]); + + return ( + + + {showSelectAll && ( + + + + + + )} + } breakpoint="lg"> + + + + {sortColumns && ( + + + + )} + + {showExpandCollapse && ( + + <> + + + + + + )} + {isAdvancedSearchShown && additionalControls.length > 0 && ( + + + { + if (!isKebabModalOpen) { + setIsKebabOpen(isOpen); + } + }} + /> + } + isOpen={isKebabOpen} + isPlain + dropdownItems={additionalControls} + /> + + + )} + {!isAdvancedSearchShown && ( + + {additionalControls.map(control => ( + {control} + ))} + + )} + {!isAdvancedSearchShown && pagination && itemCount > 0 && ( + {pagination} + )} + + + ); +} + +DataListToolbar.propTypes = { + itemCount: PropTypes.number, + clearAllFilters: PropTypes.func, + qsConfig: QSConfig.isRequired, + searchColumns: SearchColumns.isRequired, + searchableKeys: PropTypes.arrayOf(PropTypes.string), + relatedSearchableKeys: PropTypes.arrayOf(PropTypes.string), + sortColumns: SortColumns, + showSelectAll: PropTypes.bool, + isAllSelected: PropTypes.bool, + isCompact: PropTypes.bool, + onCompact: PropTypes.func, + onExpand: PropTypes.func, + onSearch: PropTypes.func, + onReplaceSearch: PropTypes.func, + onSelectAll: PropTypes.func, + onSort: PropTypes.func, + additionalControls: PropTypes.arrayOf(PropTypes.node), +}; + +DataListToolbar.defaultProps = { + itemCount: 0, + searchableKeys: [], + relatedSearchableKeys: [], + sortColumns: null, + clearAllFilters: null, + showSelectAll: false, + isAllSelected: false, + isCompact: false, + onCompact: null, + onExpand: null, + onSearch: null, + onReplaceSearch: null, + onSelectAll: null, + onSort: null, + additionalControls: [], +}; + +export default withI18n()(DataListToolbar); diff --git a/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx new file mode 100644 index 000000000000..5dcd594d2240 --- /dev/null +++ b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx @@ -0,0 +1,356 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import DataListToolbar from './DataListToolbar'; +import AddDropDownButton from '../AddDropDownButton/AddDropDownButton'; + +describe('', () => { + let toolbar; + + const QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: 'name' }, + integerFields: ['page', 'page_size'], + }; + + afterEach(() => { + if (toolbar) { + toolbar.unmount(); + toolbar = null; + } + }); + + const onSearch = jest.fn(); + const onReplaceSearch = jest.fn(); + const onSort = jest.fn(); + const onSelectAll = jest.fn(); + + test('it triggers the expected callbacks', () => { + const searchColumns = [ + { name: 'Name', key: 'name__icontains', isDefault: true }, + ]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + const search = 'button[aria-label="Search submit button"]'; + const searchTextInput = 'input[aria-label="Search text input"]'; + const selectAll = 'input[aria-label="Select all"]'; + const sort = 'button[aria-label="Sort"]'; + + toolbar = mountWithContexts( + + ); + + toolbar.find(sort).simulate('click'); + toolbar.find(selectAll).simulate('change', { target: { checked: false } }); + + expect(onSelectAll).toHaveBeenCalledTimes(1); + expect(onSort).toHaveBeenCalledTimes(1); + expect(onSort).toBeCalledWith('name', 'descending'); + + expect(onSelectAll).toHaveBeenCalledTimes(1); + expect(onSelectAll.mock.calls[0][0]).toBe(false); + + toolbar.find(searchTextInput).instance().value = 'test-321'; + toolbar.find(searchTextInput).simulate('change'); + toolbar.find(search).simulate('click'); + + expect(onSearch).toHaveBeenCalledTimes(1); + expect(onSearch).toBeCalledWith('name__icontains', 'test-321'); + }); + + test('dropdown items sortable/searchable columns work', () => { + const sortDropdownToggleSelector = 'button[id="awx-sort"]'; + const searchDropdownToggleSelector = + 'Select[aria-label="Simple key select"] SelectToggle'; + const sortDropdownMenuItems = + 'DropdownMenu > ul[aria-labelledby="awx-sort"]'; + const searchDropdownMenuItems = + 'Select[aria-label="Simple key select"] SelectOption'; + + const NEW_QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: 'foo' }, + integerFields: ['page', 'page_size'], + }; + + const searchColumns = [ + { name: 'Foo', key: 'foo', isDefault: true }, + { name: 'Bar', key: 'bar' }, + ]; + const sortColumns = [ + { name: 'Foo', key: 'foo' }, + { name: 'Bar', key: 'bar' }, + { name: 'Bakery', key: 'Bakery' }, + ]; + + toolbar = mountWithContexts( + + ); + const sortDropdownToggle = toolbar.find(sortDropdownToggleSelector); + expect(sortDropdownToggle.length).toBe(1); + sortDropdownToggle.simulate('click'); + toolbar.update(); + const sortDropdownItems = toolbar.find(sortDropdownMenuItems).children(); + expect(sortDropdownItems.length).toBe(2); + let searchDropdownToggle = toolbar.find(searchDropdownToggleSelector); + expect(searchDropdownToggle.length).toBe(1); + searchDropdownToggle.simulate('click'); + toolbar.update(); + let searchDropdownItems = toolbar.find(searchDropdownMenuItems).children(); + expect(searchDropdownItems.length).toBe(2); + const mockedSortEvent = { target: { innerText: 'Bar' } }; + searchDropdownItems.at(0).simulate('click', mockedSortEvent); + toolbar = mountWithContexts( + + ); + toolbar.update(); + + const sortDropdownToggleDescending = toolbar.find( + sortDropdownToggleSelector + ); + expect(sortDropdownToggleDescending.length).toBe(1); + sortDropdownToggleDescending.simulate('click'); + toolbar.update(); + + const sortDropdownItemsDescending = toolbar + .find(sortDropdownMenuItems) + .children(); + expect(sortDropdownItemsDescending.length).toBe(2); + sortDropdownToggleDescending.simulate('click'); // toggle close the sort dropdown + + const mockedSortEventDescending = { target: { innerText: 'Bar' } }; + sortDropdownItems.at(0).simulate('click', mockedSortEventDescending); + toolbar.update(); + + searchDropdownToggle = toolbar.find(searchDropdownToggleSelector); + expect(searchDropdownToggle.length).toBe(1); + searchDropdownToggle.simulate('click'); + toolbar.update(); + + searchDropdownItems = toolbar.find(searchDropdownMenuItems).children(); + expect(searchDropdownItems.length).toBe(2); + + const mockedSearchEvent = { target: { innerText: 'Bar' } }; + searchDropdownItems.at(0).simulate('click', mockedSearchEvent); + }); + + test('it displays correct sort icon', () => { + const NUM_QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: 'id' }, + integerFields: ['page', 'page_size', 'id'], + }; + + const NUM_DESC_QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: '-id' }, + integerFields: ['page', 'page_size', 'id'], + }; + + const ALPH_QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: 'name' }, + integerFields: ['page', 'page_size', 'id'], + }; + + const ALPH_DESC_QS_CONFIG = { + namespace: 'organization', + dateFields: ['modified', 'created'], + defaultParams: { page: 1, page_size: 5, order_by: '-name' }, + integerFields: ['page', 'page_size', 'id'], + }; + + const forwardNumericIconSelector = 'SortNumericDownIcon'; + const reverseNumericIconSelector = 'SortNumericDownAltIcon'; + const forwardAlphaIconSelector = 'SortAlphaDownIcon'; + const reverseAlphaIconSelector = 'SortAlphaDownAltIcon'; + + const numericColumns = [{ name: 'ID', key: 'id' }]; + + const alphaColumns = [{ name: 'Name', key: 'name' }]; + + const searchColumns = [ + { name: 'Name', key: 'name', isDefault: true }, + { name: 'ID', key: 'id' }, + ]; + + toolbar = mountWithContexts( + + ); + + const reverseNumericIcon = toolbar.find(reverseNumericIconSelector); + expect(reverseNumericIcon.length).toBe(1); + + toolbar = mountWithContexts( + + ); + + const forwardNumericIcon = toolbar.find(forwardNumericIconSelector); + expect(forwardNumericIcon.length).toBe(1); + + toolbar = mountWithContexts( + + ); + + const reverseAlphaIcon = toolbar.find(reverseAlphaIconSelector); + expect(reverseAlphaIcon.length).toBe(1); + + toolbar = mountWithContexts( + + ); + + const forwardAlphaIcon = toolbar.find(forwardAlphaIconSelector); + expect(forwardAlphaIcon.length).toBe(1); + }); + + test('should render additionalControls', () => { + const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + + toolbar = mountWithContexts( + + click + , + ]} + /> + ); + + const button = toolbar.find('#test'); + expect(button).toHaveLength(1); + expect(button.text()).toEqual('click'); + }); + + test('it triggers the expected callbacks', () => { + const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + toolbar = mountWithContexts( + + ); + const checkbox = toolbar.find('Checkbox'); + expect(checkbox.prop('isChecked')).toBe(true); + }); + + test('always adds advanced item to search column array', () => { + const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + + toolbar = mountWithContexts( + + click + , + ]} + /> + ); + + const search = toolbar.find('Search'); + expect( + search.prop('columns').filter(col => col.key === 'advanced').length + ).toBe(1); + }); + + test('should properly render toolbar buttons when in advanced search mode', async () => { + const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + + const newToolbar = mountWithContexts( + + Add Contaner +
, +
+ Add Instance Group +
, + ]} + />, + ]} + /> + ); + act(() => newToolbar.find('Search').prop('onShowAdvancedSearch')(true)); + newToolbar.update(); + expect(newToolbar.find('KebabToggle').length).toBe(1); + act(() => newToolbar.find('KebabToggle').prop('onToggle')(true)); + newToolbar.update(); + expect(newToolbar.find('div[aria-label="add container"]').length).toBe(1); + expect(newToolbar.find('div[aria-label="add instance group"]').length).toBe( + 1 + ); + }); +}); diff --git a/awx/ui_next/src/components/DataListToolbar/index.js b/awx/ui_next/src/components/DataListToolbar/index.js new file mode 100644 index 000000000000..038f0690174c --- /dev/null +++ b/awx/ui_next/src/components/DataListToolbar/index.js @@ -0,0 +1 @@ +export { default } from './DataListToolbar'; diff --git a/awx/ui_next/src/components/DeleteButton/DeleteButton.jsx b/awx/ui_next/src/components/DeleteButton/DeleteButton.jsx new file mode 100644 index 000000000000..19e499952d85 --- /dev/null +++ b/awx/ui_next/src/components/DeleteButton/DeleteButton.jsx @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Button } from '@patternfly/react-core'; +import AlertModal from '../AlertModal'; + +function DeleteButton({ + onConfirm, + modalTitle, + name, + i18n, + variant, + children, + isDisabled, +}) { + const [isOpen, setIsOpen] = useState(false); + + return ( + <> + + setIsOpen(false)} + actions={[ + , + , + ]} + > + {i18n._(t`Are you sure you want to delete:`)} +
+ {name} +
+ + ); +} + +export default withI18n()(DeleteButton); diff --git a/awx/ui_next/src/components/DeleteButton/index.js b/awx/ui_next/src/components/DeleteButton/index.js new file mode 100644 index 000000000000..991ad79b298d --- /dev/null +++ b/awx/ui_next/src/components/DeleteButton/index.js @@ -0,0 +1 @@ +export { default } from './DeleteButton'; diff --git a/awx/ui_next/src/components/DetailList/ArrayDetail.jsx b/awx/ui_next/src/components/DetailList/ArrayDetail.jsx new file mode 100644 index 000000000000..a946a5976fec --- /dev/null +++ b/awx/ui_next/src/components/DetailList/ArrayDetail.jsx @@ -0,0 +1,35 @@ +import 'styled-components/macro'; +import React from 'react'; +import styled from 'styled-components'; +import { TextListItemVariants } from '@patternfly/react-core'; +import { DetailName, DetailValue } from './Detail'; + +const Value = styled(DetailValue)` + margin-top: var(--pf-global--spacer--xs); + padding: var(--pf-global--spacer--xs); + border: 1px solid var(--pf-global--BorderColor--100); + max-height: 5.5em; + overflow: auto; +`; + +function ArrayDetail({ label, value, dataCy }) { + const labelCy = dataCy ? `${dataCy}-label` : null; + const valueCy = dataCy ? `${dataCy}-value` : null; + + const vals = Array.isArray(value) ? value : [value]; + + return ( +
+ + {label} + + + {vals.map(v => ( +
{v}
+ ))} +
+
+ ); +} + +export default ArrayDetail; diff --git a/awx/ui_next/src/components/DetailList/CodeDetail.jsx b/awx/ui_next/src/components/DetailList/CodeDetail.jsx new file mode 100644 index 000000000000..6d78ef043a65 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/CodeDetail.jsx @@ -0,0 +1,81 @@ +import 'styled-components/macro'; +import React from 'react'; +import { + arrayOf, + oneOf, + oneOfType, + node, + number, + shape, + string, +} from 'prop-types'; +import { TextListItemVariants } from '@patternfly/react-core'; +import { DetailName, DetailValue } from './Detail'; +import CodeMirrorInput from '../CodeMirrorInput'; +import Popover from '../Popover'; + +function CodeDetail({ + value, + label, + mode, + rows, + fullHeight, + helpText, + dataCy, +}) { + const labelCy = dataCy ? `${dataCy}-label` : null; + const valueCy = dataCy ? `${dataCy}-value` : null; + + return ( + <> + +
+ + {label} + + {helpText && ( + + )} +
+
+ + + + + ); +} +CodeDetail.propTypes = { + value: oneOfType([shape({}), arrayOf(string), string]).isRequired, + label: node.isRequired, + dataCy: string, + helpText: string, + rows: number, + mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, +}; +CodeDetail.defaultProps = { + rows: null, + helpText: '', + dataCy: '', +}; + +export default CodeDetail; diff --git a/awx/ui_next/src/components/DetailList/DeletedDetail.jsx b/awx/ui_next/src/components/DetailList/DeletedDetail.jsx new file mode 100644 index 000000000000..e71fc183bd40 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/DeletedDetail.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { node } from 'prop-types'; +import styled from 'styled-components'; +import _Detail from './Detail'; + +const Detail = styled(_Detail)` + dd& { + color: red; + } +`; + +function DeletedDetail({ i18n, label }) { + return ; +} + +DeletedDetail.propTypes = { + label: node.isRequired, +}; + +export default withI18n()(DeletedDetail); diff --git a/awx/ui_next/src/components/DetailList/Detail.jsx b/awx/ui_next/src/components/DetailList/Detail.jsx new file mode 100644 index 000000000000..b58f09a8dc22 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/Detail.jsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { node, bool, string } from 'prop-types'; +import { TextListItem, TextListItemVariants } from '@patternfly/react-core'; +import styled from 'styled-components'; +import Popover from '../Popover'; + +const DetailName = styled(({ fullWidth, ...props }) => ( + +))` + font-weight: var(--pf-global--FontWeight--bold); + ${props => + props.fullWidth && + ` + grid-column: 1; + `} +`; + +const DetailValue = styled( + ({ fullWidth, isEncrypted, isNotConfigured, ...props }) => ( + + ) +)` + word-break: break-all; + ${props => + props.fullWidth && + ` + grid-column: 2 / -1; + `} + ${props => + (props.isEncrypted || props.isNotConfigured) && + ` + color: var(--pf-global--Color--400); + `} +`; + +const Detail = ({ + label, + value, + fullWidth, + className, + dataCy, + alwaysVisible, + helpText, + isEncrypted, + isNotConfigured, +}) => { + if (!value && typeof value !== 'number' && !alwaysVisible) { + return null; + } + + const labelCy = dataCy ? `${dataCy}-label` : null; + const valueCy = dataCy ? `${dataCy}-value` : null; + + return ( + <> + + {label} + {helpText && } + + + {value} + + + ); +}; +Detail.propTypes = { + label: node.isRequired, + value: node, + fullWidth: bool, + alwaysVisible: bool, + helpText: string, +}; +Detail.defaultProps = { + value: null, + fullWidth: false, + alwaysVisible: false, + helpText: null, +}; + +export default Detail; +export { DetailName }; +export { DetailValue }; diff --git a/awx/ui_next/src/components/DetailList/Detail.test.jsx b/awx/ui_next/src/components/DetailList/Detail.test.jsx new file mode 100644 index 000000000000..d78cf285668e --- /dev/null +++ b/awx/ui_next/src/components/DetailList/Detail.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import Detail from './Detail'; + +describe('Detail', () => { + test('renders the expected content', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/DetailList/DetailBadge.jsx b/awx/ui_next/src/components/DetailList/DetailBadge.jsx new file mode 100644 index 000000000000..7447a896f8a9 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/DetailBadge.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { node } from 'prop-types'; +import styled from 'styled-components'; +import { Badge } from '@patternfly/react-core'; + +import _Detail from './Detail'; + +const Detail = styled(_Detail)` + word-break: break-word; +`; + +function DetailBadge({ label, content, dataCy = null }) { + return ( + {content}} + /> + ); +} +DetailBadge.propTypes = { + label: node.isRequired, + content: node.isRequired, +}; + +export default DetailBadge; diff --git a/awx/ui_next/src/components/DetailList/DetailList.jsx b/awx/ui_next/src/components/DetailList/DetailList.jsx new file mode 100644 index 000000000000..85bde3494a7d --- /dev/null +++ b/awx/ui_next/src/components/DetailList/DetailList.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { TextList, TextListVariants } from '@patternfly/react-core'; +import styled from 'styled-components'; + +const DetailList = ({ children, stacked, ...props }) => ( + + {children} + +); + +export default styled(DetailList)` + display: grid; + grid-gap: 20px; + align-items: start; + ${props => + props.stacked + ? ` + grid-template-columns: auto 1fr; + ` + : ` + --column-count: 1; + grid-template-columns: repeat(var(--column-count), auto minmax(10em, 1fr)); + + @media (min-width: 920px) { + --column-count: 2; + } + + @media (min-width: 1210px) { + --column-count: 3; + } + `} +`; diff --git a/awx/ui_next/src/components/DetailList/DetailList.test.jsx b/awx/ui_next/src/components/DetailList/DetailList.test.jsx new file mode 100644 index 000000000000..5e41f75de6ec --- /dev/null +++ b/awx/ui_next/src/components/DetailList/DetailList.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import DetailList from './DetailList'; + +describe('DetailList', () => { + test('renders the expected content', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/DetailList/UserDateDetail.jsx b/awx/ui_next/src/components/DetailList/UserDateDetail.jsx new file mode 100644 index 000000000000..29826175c5e4 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/UserDateDetail.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { node, string } from 'prop-types'; +import { Trans } from '@lingui/macro'; +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import { formatDateString } from '../../util/dates'; +import _Detail from './Detail'; +import { SummaryFieldUser } from '../../types'; + +const Detail = styled(_Detail)` + word-break: break-word; +`; + +function UserDateDetail({ label, date, user, dataCy = null }) { + const dateStr = formatDateString(date); + const username = user ? user.username : ''; + return ( + + {dateStr} by {username} + + ) : ( + dateStr + ) + } + /> + ); +} +UserDateDetail.propTypes = { + label: node.isRequired, + date: string.isRequired, + user: SummaryFieldUser, +}; +UserDateDetail.defaultProps = { + user: null, +}; + +export default UserDateDetail; diff --git a/awx/ui_next/src/components/DetailList/index.js b/awx/ui_next/src/components/DetailList/index.js new file mode 100644 index 000000000000..d5e2ccd8a468 --- /dev/null +++ b/awx/ui_next/src/components/DetailList/index.js @@ -0,0 +1,11 @@ +export { default as DetailList } from './DetailList'; +export { default as Detail, DetailName, DetailValue } from './Detail'; +export { default as DeletedDetail } from './DeletedDetail'; +export { default as UserDateDetail } from './UserDateDetail'; +export { default as DetailBadge } from './DetailBadge'; +export { default as ArrayDetail } from './ArrayDetail'; +/* + NOTE: CodeDetail cannot be imported here, as it causes circular + dependencies in testing environment. Import it directly from + DetailList/ObjectDetail +*/ diff --git a/awx/ui_next/src/components/DisassociateButton/DisassociateButton.jsx b/awx/ui_next/src/components/DisassociateButton/DisassociateButton.jsx new file mode 100644 index 000000000000..39943f88b46b --- /dev/null +++ b/awx/ui_next/src/components/DisassociateButton/DisassociateButton.jsx @@ -0,0 +1,171 @@ +import React, { useState, useEffect, useContext } from 'react'; +import { arrayOf, func, shape, string, oneOfType, number } from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Button, Tooltip, DropdownItem } from '@patternfly/react-core'; +import styled from 'styled-components'; +import { KebabifiedContext } from '../../contexts/Kebabified'; + +import AlertModal from '../AlertModal'; + +const ModalNote = styled.div` + margin-bottom: var(--pf-global--spacer--xl); +`; + +function DisassociateButton({ + i18n, + itemsToDisassociate = [], + modalNote = '', + modalTitle = i18n._(t`Disassociate?`), + onDisassociate, + verifyCannotDisassociate = true, +}) { + const [isOpen, setIsOpen] = useState(false); + const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext); + + function handleDisassociate() { + onDisassociate(); + setIsOpen(false); + } + + useEffect(() => { + if (isKebabified) { + onKebabModalChange(isOpen); + } + }, [isKebabified, isOpen, onKebabModalChange]); + + function cannotDisassociate(item) { + return !item.summary_fields?.user_capabilities?.delete; + } + + function renderTooltip() { + if (verifyCannotDisassociate) { + const itemsUnableToDisassociate = itemsToDisassociate + .filter(cannotDisassociate) + .map(item => item.name) + .join(', '); + + if (itemsToDisassociate.some(cannotDisassociate)) { + return ( +
+ {i18n._( + t`You do not have permission to disassociate the following: ${itemsUnableToDisassociate}` + )} +
+ ); + } + } + + if (itemsToDisassociate.length) { + return i18n._(t`Disassociate`); + } + return i18n._(t`Select a row to disassociate`); + } + + let isDisabled = false; + if (verifyCannotDisassociate) { + isDisabled = + itemsToDisassociate.length === 0 || + itemsToDisassociate.some(cannotDisassociate); + } else { + isDisabled = itemsToDisassociate.length === 0; + } + + // NOTE: Once PF supports tooltips on disabled elements, + // we can delete the extra
around the below. + // See: https://github.com/patternfly/patternfly-react/issues/1894 + return ( + <> + {isKebabified ? ( + setIsOpen(true)} + > + {i18n._(t`Disassociate`)} + + ) : ( + +
+ +
+
+ )} + + {isOpen && ( + setIsOpen(false)} + actions={[ + , + , + ]} + > + {modalNote && {modalNote}} + +
{i18n._(t`This action will disassociate the following:`)}
+ + {itemsToDisassociate.map(item => ( + + {item.hostname ? item.hostname : item.name} +
+
+ ))} +
+ )} + + ); +} + +DisassociateButton.defaultProps = { + itemsToDisassociate: [], + modalNote: '', + modalTitle: '', +}; + +DisassociateButton.propTypes = { + itemsToDisassociate: oneOfType([ + arrayOf( + shape({ + id: number.isRequired, + name: string.isRequired, + }) + ), + arrayOf( + shape({ + id: number.isRequired, + hostname: string.isRequired, + }) + ), + ]), + modalNote: string, + modalTitle: string, + onDisassociate: func.isRequired, +}; + +export default withI18n()(DisassociateButton); diff --git a/awx/ui_next/src/components/DisassociateButton/DisassociateButton.test.jsx b/awx/ui_next/src/components/DisassociateButton/DisassociateButton.test.jsx new file mode 100644 index 000000000000..5f0b76d330e4 --- /dev/null +++ b/awx/ui_next/src/components/DisassociateButton/DisassociateButton.test.jsx @@ -0,0 +1,113 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import DisassociateButton from './DisassociateButton'; + +describe('', () => { + describe('User has disassociate permissions', () => { + let wrapper; + const handleDisassociate = jest.fn(); + const mockHosts = [ + { + id: 1, + name: 'foo', + summary_fields: { + user_capabilities: { + delete: true, + }, + }, + }, + { + id: 2, + name: 'bar', + summary_fields: { + user_capabilities: { + delete: true, + }, + }, + }, + ]; + + beforeAll(() => { + wrapper = mountWithContexts( + + ); + }); + + afterAll(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('should render button', () => { + expect(wrapper.find('button')).toHaveLength(1); + expect(wrapper.find('button').text()).toEqual('Disassociate'); + }); + + test('should open confirmation modal', () => { + wrapper.find('button').simulate('click'); + expect(wrapper.find('AlertModal')).toHaveLength(1); + }); + + test('cancel button should close confirmation modal', () => { + expect(wrapper.find('AlertModal')).toHaveLength(1); + wrapper.find('button[aria-label="Cancel"]').simulate('click'); + expect(wrapper.find('AlertModal')).toHaveLength(0); + }); + + test('should render expected modal content', () => { + wrapper.find('button').simulate('click'); + expect( + wrapper + .find('AlertModal') + .containsMatchingElement(
custom note
) + ).toEqual(true); + expect( + wrapper + .find('AlertModal') + .containsMatchingElement( +
This action will disassociate the following:
+ ) + ).toEqual(true); + expect(wrapper.find('Title').text()).toEqual('custom title'); + wrapper.find('button[aria-label="Close"]').simulate('click'); + }); + + test('disassociate button should call handleDisassociate on click', () => { + wrapper.find('button').simulate('click'); + expect(handleDisassociate).toHaveBeenCalledTimes(0); + wrapper + .find('button[aria-label="confirm disassociate"]') + .simulate('click'); + expect(handleDisassociate).toHaveBeenCalledTimes(1); + }); + }); + + describe('User does not have disassociate permissions', () => { + const readOnlyHost = [ + { + id: 1, + name: 'foo', + summary_fields: { + user_capabilities: { + delete: false, + }, + }, + }, + ]; + + test('should disable button when no delete permissions', () => { + const wrapper = mountWithContexts( + {}} + itemsToDelete={readOnlyHost} + /> + ); + expect(wrapper.find('button[disabled]')).toHaveLength(1); + }); + }); +}); diff --git a/awx/ui_next/src/components/DisassociateButton/index.js b/awx/ui_next/src/components/DisassociateButton/index.js new file mode 100644 index 000000000000..c64669bc235a --- /dev/null +++ b/awx/ui_next/src/components/DisassociateButton/index.js @@ -0,0 +1 @@ +export { default } from './DisassociateButton'; diff --git a/awx/ui_next/src/components/ErrorDetail/ErrorDetail.jsx b/awx/ui_next/src/components/ErrorDetail/ErrorDetail.jsx new file mode 100644 index 000000000000..3b05ba47d5e4 --- /dev/null +++ b/awx/ui_next/src/components/ErrorDetail/ErrorDetail.jsx @@ -0,0 +1,90 @@ +import React, { useState, Fragment } from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; + +import { + Card as PFCard, + CardBody as PFCardBody, + ExpandableSection as PFExpandable, +} from '@patternfly/react-core'; +import getErrorMessage from './getErrorMessage'; + +const Card = styled(PFCard)` + background-color: var(--pf-global--BackgroundColor--200); + overflow-wrap: break-word; +`; + +const CardBody = styled(PFCardBody)` + max-height: 200px; + overflow: scroll; +`; + +const Expandable = styled(PFExpandable)` + text-align: left; + + & .pf-c-expandable__toggle { + padding-left: 10px; + margin-left: 5px; + margin-top: 10px; + margin-bottom: 10px; + } +`; + +function ErrorDetail({ error, i18n }) { + const { response } = error; + const [isExpanded, setIsExpanded] = useState(false); + + const handleToggle = () => { + setIsExpanded(!isExpanded); + }; + + const renderNetworkError = () => { + const message = getErrorMessage(response); + + return ( + + + {response?.config?.method.toUpperCase()} {response?.config?.url}{' '} + {response?.status} + + + {Array.isArray(message) ? ( +
    + {message.map(m => + typeof m === 'string' ?
  • {m}
  • : null + )} +
+ ) : ( + message + )} +
+
+ ); + }; + + const renderStack = () => { + return {error.stack}; + }; + + return ( + + + {Object.prototype.hasOwnProperty.call(error, 'response') + ? renderNetworkError() + : renderStack()} + + + ); +} + +ErrorDetail.propTypes = { + error: PropTypes.instanceOf(Error).isRequired, +}; + +export default withI18n()(ErrorDetail); diff --git a/awx/ui_next/src/components/ErrorDetail/ErrorDetail.test.jsx b/awx/ui_next/src/components/ErrorDetail/ErrorDetail.test.jsx new file mode 100644 index 000000000000..1816f4a2dd78 --- /dev/null +++ b/awx/ui_next/src/components/ErrorDetail/ErrorDetail.test.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import ErrorDetail from './ErrorDetail'; + +describe('ErrorDetail', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper).toHaveLength(1); + }); + test('testing errors', () => { + const wrapper = mountWithContexts( + + ); + act(() => wrapper.find('ExpandableSection').prop('onToggle')()); + wrapper.update(); + }); +}); diff --git a/awx/ui_next/src/components/ErrorDetail/getErrorMessage.js b/awx/ui_next/src/components/ErrorDetail/getErrorMessage.js new file mode 100644 index 000000000000..1c2450a64d75 --- /dev/null +++ b/awx/ui_next/src/components/ErrorDetail/getErrorMessage.js @@ -0,0 +1,15 @@ +export default function getErrorMessage(response) { + if (!response?.data) { + return null; + } + if (typeof response.data === 'string') { + return response.data; + } + if (response.data.detail) { + return response.data.detail; + } + return Object.values(response.data).reduce( + (acc, currentValue) => acc.concat(currentValue), + [] + ); +} diff --git a/awx/ui_next/src/components/ErrorDetail/getErrorMessage.test.js b/awx/ui_next/src/components/ErrorDetail/getErrorMessage.test.js new file mode 100644 index 000000000000..c67728f00bc8 --- /dev/null +++ b/awx/ui_next/src/components/ErrorDetail/getErrorMessage.test.js @@ -0,0 +1,60 @@ +import getErrorMessage from './getErrorMessage'; + +describe('getErrorMessage', () => { + test('should return data string', () => { + const response = { + data: 'error response', + }; + expect(getErrorMessage(response)).toEqual('error response'); + }); + test('should return detail string', () => { + const response = { + data: { + detail: 'detail string', + }, + }; + expect(getErrorMessage(response)).toEqual('detail string'); + }); + test('should return an array of strings', () => { + const response = { + data: { + project: ['project error response'], + }, + }; + expect(getErrorMessage(response)).toEqual(['project error response']); + }); + test('should consolidate error messages from multiple keys into an array', () => { + const response = { + data: { + project: ['project error response'], + inventory: ['inventory error response'], + organization: ['org error response'], + }, + }; + expect(getErrorMessage(response)).toEqual([ + 'project error response', + 'inventory error response', + 'org error response', + ]); + }); + test('should handle no response.data', () => { + const response = {}; + expect(getErrorMessage(response)).toEqual(null); + }); + test('should consolidate multiple error messages from multiple keys into an array', () => { + const response = { + data: { + project: ['project error response'], + inventory: [ + 'inventory error response', + 'another inventory error response', + ], + }, + }; + expect(getErrorMessage(response)).toEqual([ + 'project error response', + 'inventory error response', + 'another inventory error response', + ]); + }); +}); diff --git a/awx/ui_next/src/components/ErrorDetail/index.js b/awx/ui_next/src/components/ErrorDetail/index.js new file mode 100644 index 000000000000..0f380db7abaa --- /dev/null +++ b/awx/ui_next/src/components/ErrorDetail/index.js @@ -0,0 +1 @@ +export { default } from './ErrorDetail'; diff --git a/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.jsx b/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.jsx new file mode 100644 index 000000000000..00a33b68c2e1 --- /dev/null +++ b/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.jsx @@ -0,0 +1,71 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { + Button as PFButton, + ToolbarItem as PFToolbarItem, +} from '@patternfly/react-core'; +import { BarsIcon, EqualsIcon } from '@patternfly/react-icons'; +import styled from 'styled-components'; + +const Button = styled(PFButton)` + padding: 0; + margin: 0; + height: 30px; + width: 30px; + ${props => + props.isActive + ? ` + background-color: #007bba; + --pf-c-button--m-plain--active--Color: white; + --pf-c-button--m-plain--focus--Color: white;` + : null}; +`; + +const ToolbarItem = styled(PFToolbarItem)` + & :not(:last-child) { + margin-right: 20px; + } +`; + +// TODO: Recommend renaming this component to avoid confusion +// with ExpandingContainer +function ExpandCollapse({ isCompact, onCompact, onExpand, i18n }) { + return ( + + + + + + + + + ); +} + +ExpandCollapse.propTypes = { + onCompact: PropTypes.func.isRequired, + onExpand: PropTypes.func.isRequired, + isCompact: PropTypes.bool, +}; + +ExpandCollapse.defaultProps = { + isCompact: true, +}; + +export default withI18n()(ExpandCollapse); diff --git a/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.test.jsx b/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.test.jsx new file mode 100644 index 000000000000..74b37d623590 --- /dev/null +++ b/awx/ui_next/src/components/ExpandCollapse/ExpandCollapse.test.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import ExpandCollapse from './ExpandCollapse'; + +describe('', () => { + const onCompact = jest.fn(); + const onExpand = jest.fn(); + const isCompact = false; + test('initially renders without crashing', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.length).toBe(1); + wrapper.unmount(); + }); +}); diff --git a/awx/ui_next/src/components/ExpandCollapse/index.js b/awx/ui_next/src/components/ExpandCollapse/index.js new file mode 100644 index 000000000000..997c5b618120 --- /dev/null +++ b/awx/ui_next/src/components/ExpandCollapse/index.js @@ -0,0 +1 @@ +export { default } from './ExpandCollapse'; diff --git a/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.jsx b/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.jsx new file mode 100644 index 000000000000..8c9051e67e6c --- /dev/null +++ b/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { bool, node, string } from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import styled from 'styled-components'; +import { CheckboxField } from '../FormField'; +import Popover from '../Popover'; + +const FieldHeader = styled.div` + display: flex; + padding-bottom: var(--pf-c-form__group-label--PaddingBottom); +`; + +const StyledCheckboxField = styled(CheckboxField)` + --pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize); + margin-left: auto; +`; + +function FieldWithPrompt({ + children, + fieldId, + i18n, + isRequired, + label, + promptId, + promptName, + tooltip, + isDisabled, +}) { + return ( +
+ +
+ + {tooltip && } +
+ +
+ {children} +
+ ); +} + +FieldWithPrompt.propTypes = { + fieldId: string.isRequired, + isRequired: bool, + label: string.isRequired, + promptId: string.isRequired, + promptName: string.isRequired, + tooltip: node, +}; + +FieldWithPrompt.defaultProps = { + isRequired: false, + tooltip: null, +}; + +export default withI18n()(FieldWithPrompt); diff --git a/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.test.jsx b/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.test.jsx new file mode 100644 index 000000000000..fcc079875fbe --- /dev/null +++ b/awx/ui_next/src/components/FieldWithPrompt/FieldWithPrompt.test.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { Field, Formik } from 'formik'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import FieldWithPrompt from './FieldWithPrompt'; + +describe('FieldWithPrompt', () => { + let wrapper; + + afterEach(() => { + wrapper.unmount(); + }); + + test('Required asterisk and Popover hidden when not required and tooltip not provided', () => { + wrapper = mountWithContexts( + + {() => ( + + + {() => } + + + )} + + ); + expect(wrapper.find('.pf-c-form__label-required')).toHaveLength(0); + expect(wrapper.find('Popover')).toHaveLength(0); + }); + + test('Required asterisk and Popover shown when required and tooltip provided', () => { + wrapper = mountWithContexts( + + {() => ( + + + {() => } + + + )} + + ); + expect(wrapper.find('.pf-c-form__label-required')).toHaveLength(1); + expect(wrapper.find('Popover[data-cy="job-template-limit"]').length).toBe( + 1 + ); + }); +}); diff --git a/awx/ui_next/src/components/FieldWithPrompt/index.js b/awx/ui_next/src/components/FieldWithPrompt/index.js new file mode 100644 index 000000000000..77c1d5bda6c3 --- /dev/null +++ b/awx/ui_next/src/components/FieldWithPrompt/index.js @@ -0,0 +1 @@ +export { default } from './FieldWithPrompt'; diff --git a/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx new file mode 100644 index 000000000000..70a5c95f7d2b --- /dev/null +++ b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { ActionGroup, Button } from '@patternfly/react-core'; +import { FormFullWidthLayout } from '../FormLayout'; + +const FormActionGroup = ({ onCancel, onSubmit, submitDisabled, i18n }) => { + return ( + + + + + + + ); +}; + +FormActionGroup.propTypes = { + onCancel: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + submitDisabled: PropTypes.bool, +}; + +FormActionGroup.defaultProps = { + submitDisabled: false, +}; + +export default withI18n()(FormActionGroup); diff --git a/awx/ui_next/src/components/FormActionGroup/FormActionGroup.test.jsx b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.test.jsx new file mode 100644 index 000000000000..5068a85226dc --- /dev/null +++ b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.test.jsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; + +import FormActionGroup from './FormActionGroup'; + +describe('FormActionGroup', () => { + test('should render the expected content', () => { + const wrapper = mountWithContexts( + {}} onCancel={() => {}} /> + ); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/FormActionGroup/index.js b/awx/ui_next/src/components/FormActionGroup/index.js new file mode 100644 index 000000000000..30c9e11f1a6b --- /dev/null +++ b/awx/ui_next/src/components/FormActionGroup/index.js @@ -0,0 +1 @@ +export { default } from './FormActionGroup'; diff --git a/awx/ui_next/src/components/FormField/ArrayTextField.jsx b/awx/ui_next/src/components/FormField/ArrayTextField.jsx new file mode 100644 index 000000000000..d32493b41ba0 --- /dev/null +++ b/awx/ui_next/src/components/FormField/ArrayTextField.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useField } from 'formik'; +import { FormGroup, TextArea } from '@patternfly/react-core'; +import Popover from '../Popover'; + +function ArrayTextField(props) { + const { + id, + helperText, + name, + label, + tooltip, + tooltipMaxWidth, + validate, + isRequired, + type, + ...rest + } = props; + + const [field, meta, helpers] = useField({ name, validate }); + const isValid = !(meta.touched && meta.error); + const value = field.value || []; + + return ( + } + > +