]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Update bootstrap
authorTiago Melo <tmelo@suse.com>
Mon, 12 Nov 2018 14:37:40 +0000 (14:37 +0000)
committerTiago Melo <tmelo@suse.com>
Wed, 10 Jul 2019 15:35:49 +0000 (15:35 +0000)
Fixes: http://tracker.ceph.com/issues/39326
Signed-off-by: Tiago Melo <tmelo@suse.com>
146 files changed:
src/pybind/mgr/dashboard/frontend/angular.json
src/pybind/mgr/dashboard/frontend/package-lock.json
src/pybind/mgr/dashboard/frontend/package.json
src/pybind/mgr/dashboard/frontend/src/app/app.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-tabs/iscsi-tabs.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-details/iscsi-target-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-details/iscsi-target-details.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-details/iscsi-target-details.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-image-settings-modal/iscsi-target-image-settings-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-iqn-settings-modal/iscsi-target-iqn-settings-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/image-list/image-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirror-health-color.pipe.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirror-health-color.pipe.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/pool-edit-mode-modal/pool-edit-mode-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/pool-edit-peer-modal/pool-edit-peer-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-details/rbd-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-move-modal/rbd-trash-move-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-restore-modal/rbd-trash-restore-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/crushmap/crushmap.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/crushmap/crushmap.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/logs/logs.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/logs/logs.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-form/mgr-module-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-pg-scrub-modal/osd-pg-scrub-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-reweight-modal/osd-reweight-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/alert-list/alert-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/prometheus-tabs/prometheus-tabs.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-list/silence-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-matcher-modal/silence-matcher-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-card/info-card-popover.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-card/info-card.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-card/info-card.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-card/info-card.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-group/info-group.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/info-group/info-group.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form-client/nfs-form-client.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-details/rgw-bucket-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-capability-modal/rgw-user-capability-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-s3-key-modal/rgw-user-s3-key-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-subuser-modal/rgw-user-subuser-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-swift-key-modal/rgw-user-swift-key-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-swift-key-modal/rgw-user-swift-key-modal.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/login/login.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/login/login.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/sso/sso-not-found/sso-not-found.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-tabs/user-tabs.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/about/about.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.ts
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/identity/identity.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.ts
src/pybind/mgr/dashboard/frontend/src/app/core/not-found/not-found.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/back-button/back-button.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/config-option/config-option.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/config-option/config-option.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/confirmation-modal/confirmation-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/error-panel/error-panel.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/language-selector/language-selector.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/loading-panel/loading-panel.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/modal/modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/modal/modal.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/select-badges/select-badges.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/select-badges/select-badges.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/select/select.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/select/select.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/directives/password-button.directive.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/icons.enum.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-notification.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.ts
src/pybind/mgr/dashboard/frontend/src/defaults.scss [deleted file]
src/pybind/mgr/dashboard/frontend/src/index.html
src/pybind/mgr/dashboard/frontend/src/styles.scss
src/pybind/mgr/dashboard/frontend/src/styles/chart-tooltip.scss
src/pybind/mgr/dashboard/frontend/src/styles/defaults.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/styles/popover.scss
src/pybind/mgr/dashboard/frontend/src/styles/vendor.overrides.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/styles/vendor.variables.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/vendor.overrides.scss [deleted file]
src/pybind/mgr/dashboard/frontend/src/vendor.variables.scss [deleted file]

index 068aa101dfcccd7a6bec698d56997845607b6801..d91a71d89994e1dd50313db7908d5a6fd28e457e 100644 (file)
               "src/favicon.ico"
             ],
             "styles": [
-              "node_modules/bootstrap/dist/css/bootstrap.css",
-              "node_modules/ng2-toastr/bundles/ng2-toastr.min.css",
-              "node_modules/fork-awesome/css/fork-awesome.css",
-              "node_modules/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css",
+              "node_modules/ngx-toastr/toastr.css",
               "node_modules/ngx-bootstrap/datepicker/bs-datepicker.css",
               "src/styles.scss",
-              "src/vendor.overrides.scss",
+              "src/styles/vendor.overrides.scss",
               "node_modules/ng2-tree/styles.css"
             ],
             "scripts": [
               "node_modules/chart.js/dist/Chart.bundle.js"
-            ]
+            ],
+            "stylePreprocessorOptions": {
+              "includePaths": [
+                "src/styles",
+                "src"
+              ]
+            }
           },
           "configurations": {
             "production": {
index 94e89fc4e44c14d298c9d8633134bbe825d67b4a..12275eaec2597141dba4c5892e1c55093d1465e7 100644 (file)
           "requires": {
             "tslib": "^1.9.0"
           }
-        },
-        "semver": {
-          "version": "5.6.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
-          "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
-          "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
-        },
-        "source-map-support": {
-          "version": "0.5.10",
-          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
-          "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
-          "dev": true,
-          "requires": {
-            "buffer-from": "^1.0.0",
-            "source-map": "^0.6.0"
-          }
         }
       }
     },
           "requires": {
             "tslib": "^1.9.0"
           }
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
         }
       }
     },
           "requires": {
             "tslib": "^1.9.0"
           }
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
         }
       }
     },
         "yargs": "9.0.1"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
         "camelcase": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
           "dev": true
         },
         "chokidar": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz",
-          "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==",
+          "version": "2.1.5",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz",
+          "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",
           "dev": true,
           "requires": {
             "anymatch": "^2.0.0",
             "normalize-path": "^3.0.0",
             "path-is-absolute": "^1.0.0",
             "readdirp": "^2.2.1",
-            "upath": "^1.1.0"
+            "upath": "^1.1.1"
           }
         },
         "cliui": {
         },
         "load-json-file": {
           "version": "2.0.0",
-          "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
           "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
           "dev": true,
           "requires": {
             "strip-bom": "^3.0.0"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "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
         },
-        "os-locale": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
-          "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
-          "dev": true,
-          "requires": {
-            "execa": "^0.7.0",
-            "lcid": "^1.0.0",
-            "mem": "^1.1.0"
-          }
-        },
         "path-type": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
             "read-pkg": "^2.0.0"
           }
         },
-        "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"
-          }
-        },
         "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
         },
-        "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": {
-            "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
-            },
-            "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-bom": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
           "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
           "dev": true
         },
-        "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
-        },
-        "y18n": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
-          "dev": true
-        },
         "yargs": {
           "version": "9.0.1",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz",
             "minimist": "^1.2.0"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "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.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
         }
       }
     },
           "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
           "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
           "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
         }
       }
     },
         "uuid": "^3.3.2"
       },
       "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
         "chokidar": {
           "version": "2.1.6",
           "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
             "minimist": "^1.2.0"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "normalize-path": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
           "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
           "dev": true
         },
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "string-length": "^2.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "write-file-atomic": "2.4.1"
       },
       "dependencies": {
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "yargs": "10.0.3"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
-        },
-        "camelcase": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
-        },
-        "cliui": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-          "requires": {
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1",
-            "wrap-ansi": "^2.0.0"
-          },
-          "dependencies": {
-            "string-width": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-              "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-              "requires": {
-                "code-point-at": "^1.0.0",
-                "is-fullwidth-code-point": "^1.0.0",
-                "strip-ansi": "^3.0.0"
-              }
-            }
-          }
-        },
-        "os-locale": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
-          "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
-          "requires": {
-            "execa": "^0.7.0",
-            "lcid": "^1.0.0",
-            "mem": "^1.1.0"
-          }
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.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="
-            },
-            "strip-ansi": {
-              "version": "4.0.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-              "requires": {
-                "ansi-regex": "^3.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="
-        },
-        "y18n": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
-        },
         "yargs": {
           "version": "10.0.3",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz",
             "y18n": "^3.2.1",
             "yargs-parser": "^8.0.0"
           }
-        },
-        "yargs-parser": {
-          "version": "8.1.0",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz",
-          "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==",
-          "requires": {
-            "camelcase": "^4.1.0"
-          }
         }
       }
     },
           "requires": {
             "tslib": "^1.9.0"
           }
-        },
-        "semver": {
-          "version": "5.6.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
-          "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
         }
       }
     },
       "dev": true
     },
     "@types/selenium-webdriver": {
-      "version": "3.0.14",
-      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz",
-      "integrity": "sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ==",
+      "version": "3.0.16",
+      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz",
+      "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==",
       "dev": true
     },
     "@types/source-list-map": {
         "fast-json-stable-stringify": "^2.0.0",
         "json-schema-traverse": "^0.4.1",
         "uri-js": "^4.2.2"
-      },
-      "dependencies": {
-        "fast-deep-equal": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
-          "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
-          "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
-        }
       }
     },
     "ajv-errors": {
       },
       "dependencies": {
         "color-convert": {
-          "version": "1.9.2",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
-          "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
           "dev": true,
           "requires": {
-            "color-name": "1.1.1"
+            "color-name": "1.1.3"
           }
         },
         "color-name": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
-          "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
           "dev": true
         }
       }
       "dev": true
     },
     "app-root-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz",
-      "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz",
+      "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==",
       "dev": true
     },
     "aproba": {
       "optional": true
     },
     "asn1": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
-      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
-      "dev": true
+      "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": "4.10.1",
       }
     },
     "async-each": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
-      "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
+      "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-foreach": {
       "dev": true
     },
     "atob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
-      "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
+      "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
     },
     "autoprefixer": {
       }
     },
     "awesome-bootstrap-checkbox": {
-      "version": "0.3.7",
-      "resolved": "https://registry.npmjs.org/awesome-bootstrap-checkbox/-/awesome-bootstrap-checkbox-0.3.7.tgz",
-      "integrity": "sha1-sRKXPubVv/QKshfEIBhcRwJR0OI="
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/awesome-bootstrap-checkbox/-/awesome-bootstrap-checkbox-1.0.1.tgz",
+      "integrity": "sha1-2rEBRrYAESmrCg7B5Uu3fGwwRXo="
     },
     "aws-sign2": {
       "version": "0.7.0",
       "dev": true
     },
     "aws4": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
-      "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
       "dev": true
     },
     "babel-code-frame": {
         "lodash": "^4.17.4",
         "source-map": "^0.5.7",
         "trim-right": "^1.0.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
       }
     },
     "babel-helper-builder-binary-assignment-operator-visitor": {
         "slash": "^2.0.0"
       },
       "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
         "slash": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
         "browserslist": "^3.2.6",
         "invariant": "^2.2.2",
         "semver": "^5.3.0"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "3.2.8",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
+          "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30000844",
+            "electron-to-chromium": "^1.3.47"
+          }
+        }
       }
     },
     "babel-preset-jest": {
       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
       "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
       "dev": true,
-      "optional": true,
       "requires": {
         "tweetnacl": "^0.14.3"
       }
       "dev": true
     },
     "binary-extensions": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
-      "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
       "dev": true
     },
     "block-stream": {
       "dev": true,
       "requires": {
         "minimist": "^1.2.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
       }
     },
     "bluebird": {
           "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
           "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==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
+        },
         "qs": {
           "version": "6.7.0",
           "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
       "dev": true
     },
     "bootstrap": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
-      "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA=="
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
+      "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
     },
     "brace-expansion": {
       "version": "1.1.11",
         "pako": "~1.0.5"
       }
     },
-    "browserslist": {
-      "version": "3.2.8",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
-      "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
-      "dev": true,
-      "requires": {
-        "caniuse-lite": "^1.0.30000844",
-        "electron-to-chromium": "^1.3.47"
-      }
-    },
     "browserstack": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.1.tgz",
-      "integrity": "sha512-O8VMT64P9NOLhuIoD4YngyxBURefaSdR4QdhG8l6HZ9VxtU7jc3m6jLufFwKA5gaf7fetfB2TnRJnMxyob+heg==",
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.2.tgz",
+      "integrity": "sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg==",
       "dev": true,
       "requires": {
         "https-proxy-agent": "^2.2.1"
       "dev": true
     },
     "buffer-from": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
-      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
+      "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": {
         "ssri": "^5.2.4",
         "unique-filename": "^1.1.0",
         "y18n": "^4.0.0"
+      },
+      "dependencies": {
+        "y18n": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+          "dev": true
+        }
       }
     },
     "cache-base": {
       "dev": true,
       "requires": {
         "callsites": "^2.0.0"
-      },
-      "dependencies": {
-        "callsites": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
-          "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
-          "dev": true
-        }
       }
     },
     "caller-path": {
       }
     },
     "callsites": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz",
-      "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+      "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
       "dev": true
     },
     "camelcase": {
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30000865",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz",
-      "integrity": "sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw==",
+      "version": "1.0.30000960",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000960.tgz",
+      "integrity": "sha512-7nK5qs17icQaX6V3/RYrJkOsZyRNnroA4+ZwxaKJzIKy+crIy0Mz5CBlLySd2SNV+4nbUZeqeNfiaEieUBu3aA==",
       "dev": true
     },
     "canonical-path": {
       "dev": true
     },
     "chalk": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz",
-      "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==",
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
       "dev": true,
       "requires": {
-        "ansi-styles": "^3.1.0",
+        "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
-        "supports-color": "^4.0.0"
+        "supports-color": "^5.3.0"
       },
       "dependencies": {
-        "has-flag": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
-          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
-          "dev": true
-        },
         "supports-color": {
-          "version": "4.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
-          "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
           "dev": true,
           "requires": {
-            "has-flag": "^2.0.0"
+            "has-flag": "^3.0.0"
           }
         }
       }
       }
     },
     "chartjs-color": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
-      "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz",
+      "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==",
       "requires": {
-        "chartjs-color-string": "^0.5.0",
+        "chartjs-color-string": "^0.6.0",
         "color-convert": "^0.5.3"
       }
     },
     "chartjs-color-string": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
-      "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
+      "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
       "requires": {
         "color-name": "^1.0.0"
       }
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
       "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-      "dev": true,
-      "optional": true,
       "requires": {
         "string-width": "^1.0.1",
         "strip-ansi": "^3.0.1",
         "wrap-ansi": "^2.0.0"
+      },
+      "dependencies": {
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        }
       }
     },
     "clone": {
         "sprintf-js": "^1.1.1"
       },
       "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
         "sprintf-js": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
-          "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=",
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+          "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
           "dev": true
         }
       }
       "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
       "dev": true
     },
-    "colors": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
-      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
-      "dev": true
-    },
     "combined-stream": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
-      "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
+      "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
       "dev": true,
       "requires": {
         "delayed-stream": "~1.0.0"
       }
     },
     "commander": {
-      "version": "2.16.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz",
-      "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==",
+      "version": "2.20.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+      "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
       "dev": true
     },
     "commondir": {
       "dev": true
     },
     "component-emitter": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+      "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
     },
     "compressible": {
       "dev": true
     },
     "convert-source-map": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
-      "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
-      "dev": true
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+      "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.1"
+      }
     },
     "cookie": {
       "version": "0.4.0",
       }
     },
     "cross-spawn": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
-      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
-      "dev": true,
-      "optional": true,
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+      "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
       "requires": {
         "lru-cache": "^4.0.1",
+        "shebang-command": "^1.2.0",
         "which": "^1.2.9"
       }
     },
       }
     },
     "css-selector-tokenizer": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
-      "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=",
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
+      "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
       "dev": true,
       "requires": {
         "cssesc": "^0.1.0",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
       "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
       "dev": true,
-      "optional": true,
       "requires": {
         "jsbn": "~0.1.0",
         "safer-buffer": "^2.1.0"
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.52",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz",
-      "integrity": "sha1-0tnxJwuko7lnuDHEDvcftNmrXOA=",
+      "version": "1.3.124",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz",
+      "integrity": "sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w==",
       "dev": true
     },
     "elliptic": {
       }
     },
     "es6-promise": {
-      "version": "4.2.5",
-      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz",
-      "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==",
+      "version": "4.2.6",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
+      "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==",
       "dev": true
     },
     "es6-promisify": {
         "p-finally": "^1.0.0",
         "signal-exit": "^3.0.0",
         "strip-eof": "^1.0.0"
-      },
-      "dependencies": {
-        "cross-spawn": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
-          "requires": {
-            "lru-cache": "^4.0.1",
-            "shebang-command": "^1.2.0",
-            "which": "^1.2.9"
-          }
-        }
       }
     },
     "exit": {
         "tmp": "^0.0.33"
       },
       "dependencies": {
-        "tmp": {
-          "version": "0.0.33",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-          "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+        "iconv-lite": {
+          "version": "0.4.24",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
           "dev": true,
           "requires": {
-            "os-tmpdir": "~1.0.2"
+            "safer-buffer": ">= 2.1.2 < 3"
           }
         }
       }
       }
     },
     "fast-deep-equal": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
-      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
       "dev": true
     },
     "fast-glob": {
       "dev": true
     },
     "fastparse": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
-      "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
       "dev": true
     },
     "faye-websocket": {
       "integrity": "sha512-fFWz7LqRGMbyewY0Vxclw4712Cy+6Vd+1RAIJb7XY5qHpZi8BAA+Ue5sr4jAlDSI1+AD4b5WYl99NrGMtSaPzw=="
     },
     "form-data": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
-      "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+      "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",
+        "combined-stream": "^1.0.6",
         "mime-types": "^2.1.12"
       }
     },
       }
     },
     "fs-extra": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
-      "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
+      "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",
         "string-width": "^1.0.1",
         "strip-ansi": "^3.0.1",
         "wide-align": "^1.1.0"
+      },
+      "dependencies": {
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        }
       }
     },
     "gaze": {
       }
     },
     "graceful-fs": {
-      "version": "4.1.11",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "version": "4.1.15",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+      "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
       "dev": true
     },
     "growly": {
       "dev": true
     },
     "har-validator": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
-      "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
       "dev": true,
       "requires": {
-        "ajv": "^5.1.0",
+        "ajv": "^6.5.5",
         "har-schema": "^2.0.0"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "5.5.2",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
-          "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
-          "dev": true,
-          "requires": {
-            "co": "^4.6.0",
-            "fast-deep-equal": "^1.0.0",
-            "fast-json-stable-stringify": "^2.0.0",
-            "json-schema-traverse": "^0.3.0"
-          }
-        }
       }
     },
     "has": {
         "chalk": "^2.4.1",
         "commander": "^2.12.2",
         "glob": "^7.1.2"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "2.4.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
-          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        }
       }
     },
     "htmlparser2": {
       }
     },
     "iconv-lite": {
-      "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+      "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
       "dev": true,
       "requires": {
         "safer-buffer": ">= 2.1.2 < 3"
       },
       "dependencies": {
         "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "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": "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"
-              }
-            }
-          }
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
         },
         "strip-ansi": {
           "version": "5.2.0",
       "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
       "dev": true
     },
-    "is-builtin-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
-      "dev": true,
-      "requires": {
-        "builtin-modules": "^1.0.0"
-      }
-    },
     "is-callable": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
       "dev": true
     },
     "is-glob": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
-      "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+      "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"
             "json-schema-traverse": "^0.3.0"
           }
         },
+        "fast-deep-equal": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+          "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+          "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+          "dev": true
+        },
         "schema-utils": {
           "version": "0.3.0",
           "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
       "dev": true,
       "requires": {
         "colors": "1.1.2"
+      },
+      "dependencies": {
+        "colors": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+          "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+          "dev": true
+        }
       }
     },
     "jasminewd2": {
           "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
           "dev": true
         },
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "camelcase": {
           "version": "5.3.1",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
         "realpath-native": "^1.1.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "pretty-format": "^24.8.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "jsdom": "^11.5.1"
       },
       "dependencies": {
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "jest-util": "^24.8.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "walker": "^1.0.7"
       },
       "dependencies": {
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "throat": "^4.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
         "pretty-format": "^24.8.0"
       }
     },
-    "jest-message-util": {
-      "version": "24.0.0",
-      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.0.0.tgz",
-      "integrity": "sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "chalk": "^2.0.1",
-        "micromatch": "^3.1.10",
-        "slash": "^2.0.0",
-        "stack-utils": "^1.0.1"
-      },
-      "dependencies": {
-        "slash": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
-          "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
-          "dev": true
-        }
-      }
-    },
     "jest-mock": {
       "version": "24.8.0",
       "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.8.0.tgz",
         "throat": "^4.0.0"
       },
       "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "graceful-fs": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
-          "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==",
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
           "dev": true
         },
         "jest-message-util": {
           "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
           "dev": true
         },
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        },
         "camelcase": {
           "version": "5.3.1",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
       "requires": {
         "chalk": "^2.3.1",
         "jest-util": "^24.0.0"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        }
       }
     },
     "jest-snapshot": {
       }
     },
     "jest-util": {
-      "version": "24.0.0",
-      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.0.0.tgz",
-      "integrity": "sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ==",
+      "version": "24.7.1",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.7.1.tgz",
+      "integrity": "sha512-/KilOue2n2rZ5AnEBYoxOXkeTu6vi7cjgQ8MXEkih0oeAXT6JkS3fr7/j8+engCjciOU1Nq5loMSKe0A1oeX0A==",
       "dev": true,
       "requires": {
+        "@jest/console": "^24.7.1",
+        "@jest/fake-timers": "^24.7.1",
+        "@jest/source-map": "^24.3.0",
+        "@jest/test-result": "^24.7.1",
+        "@jest/types": "^24.7.0",
         "callsites": "^3.0.0",
         "chalk": "^2.0.1",
         "graceful-fs": "^4.1.15",
         "is-ci": "^2.0.0",
-        "jest-message-util": "^24.0.0",
         "mkdirp": "^0.5.1",
         "slash": "^2.0.0",
         "source-map": "^0.6.0"
       },
       "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.15",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
-          "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
           "dev": true
         },
         "slash": {
         "string-length": "^2.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
+        },
         "graceful-fs": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
       "requires": {
         "merge-stream": "^1.0.1",
         "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"
-          }
-        }
       }
     },
     "jest-zone-patch": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "jsdom": {
       "version": "11.12.0",
       "dev": true
     },
     "json-schema-traverse": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
-      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "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-stringify-safe": {
       "dev": true
     },
     "json5": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
-      "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
-      "dev": true
+      "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"
+      }
     },
     "jsonfile": {
       "version": "4.0.0",
       }
     },
     "jszip": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz",
-      "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==",
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.1.tgz",
+      "integrity": "sha512-iCMBbo4eE5rb1VCpm5qXOAaUiRKRUKiItn8ah2YQQx9qymmSAY98eyQfioChEYcVQLh0zxJ3wS4A0mh90AVPvw==",
       "dev": true,
       "requires": {
-        "core-js": "~2.3.0",
-        "es6-promise": "~3.0.2",
-        "lie": "~3.1.0",
+        "lie": "~3.3.0",
         "pako": "~1.0.2",
-        "readable-stream": "~2.0.6"
-      },
-      "dependencies": {
-        "core-js": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz",
-          "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=",
-          "dev": true
-        },
-        "es6-promise": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
-          "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=",
-          "dev": true
-        },
-        "process-nextick-args": {
-          "version": "1.0.7",
-          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
-          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.0.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
-          "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.1",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~1.0.6",
-            "string_decoder": "~0.10.x",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "0.10.31",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
-          "dev": true
-        }
+        "readable-stream": "~2.3.6",
+        "set-immediate-shim": "~1.0.1"
       }
     },
     "karma-source-map-support": {
       }
     },
     "lie": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
-      "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
       "dev": true,
       "requires": {
         "immediate": "~3.0.5"
         "big.js": "^5.2.2",
         "emojis-list": "^2.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"
-          }
-        },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
       }
     },
     "locate-path": {
       }
     },
     "lru-cache": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
-      "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
       "requires": {
         "pseudomap": "^1.0.2",
         "yallist": "^2.1.2"
             "figgy-pudding": "^3.5.1"
           }
         },
+        "y18n": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+          "dev": true
+        },
         "yallist": {
           "version": "3.0.3",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
         "read-pkg-up": "^1.0.1",
         "redent": "^1.0.0",
         "trim-newlines": "^1.0.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true,
-          "optional": true
-        }
       }
     },
     "merge-descriptors": {
       "dev": true,
       "requires": {
         "source-map": "^0.5.6"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
       }
     },
     "merge-stream": {
       "dev": true
     },
     "mime-db": {
-      "version": "1.35.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
-      "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==",
+      "version": "1.38.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
+      "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==",
       "dev": true
     },
     "mime-types": {
-      "version": "2.1.19",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
-      "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
+      "version": "2.1.22",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
+      "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
       "dev": true,
       "requires": {
-        "mime-db": "~1.35.0"
+        "mime-db": "~1.38.0"
       }
     },
     "mimic-fn": {
       }
     },
     "minimist": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
       "dev": true
     },
     "minipass": {
       "dev": true,
       "requires": {
         "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "dev": true
+        }
       }
     },
     "moment": {
       "dev": true
     },
     "nan": {
-      "version": "2.10.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
-      "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+      "version": "2.13.2",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
+      "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==",
       "dev": true,
       "optional": true
     },
       "integrity": "sha512-COGMatd+YrwJb3LSobagDC+t2PlSh4GkgG75Akh9QbXOSdFFPkbGmZvILg2xO4Hc+xicacvHp+6GINvjIeJwkA=="
     },
     "ngx-bootstrap": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-3.2.0.tgz",
-      "integrity": "sha512-oLSLIWZgRiIfcuxyXLMZUOhX3wZtg6lpuMbdo/0UzMDg2bSOe1XPskcKZ/iuOa3FOlU9rjuYMzswHYYV5f/QCA=="
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-4.3.0.tgz",
+      "integrity": "sha512-ZPS6V2yLEeqB/7KIlVohS8qUdtFa1bgUB/sSPWRcXqOWU3EKhORetZoXG6m2F5ILYDe5hwQvBEjdHPlEz2piOg=="
     },
     "nice-try": {
       "version": "1.0.5",
           "dev": true,
           "optional": true
         },
-        "aws4": {
-          "version": "1.8.0",
-          "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-          "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
-          "dev": true,
-          "optional": true
-        },
         "chalk": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
             "supports-color": "^2.0.0"
           }
         },
-        "har-validator": {
-          "version": "5.1.3",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
-          "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+        "cross-spawn": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+          "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
           "dev": true,
           "optional": true,
           "requires": {
-            "ajv": "^6.5.5",
-            "har-schema": "^2.0.0"
+            "lru-cache": "^4.0.1",
+            "which": "^1.2.9"
           }
         },
         "nan": {
         "punycode": {
           "version": "1.4.1",
           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true,
-          "optional": true
+          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
         },
         "request": {
           "version": "2.88.0",
           "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
           "dev": true,
           "optional": true
-        },
-        "tough-cookie": {
-          "version": "2.4.3",
-          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-          "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "psl": "^1.1.24",
-            "punycode": "^1.4.1"
-          }
         }
       }
     },
       }
     },
     "normalize-package-data": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
-      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+      "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",
-        "is-builtin-module": "^1.0.0",
+        "resolve": "^1.10.0",
         "semver": "2 || 3 || 4 || 5",
         "validate-npm-package-license": "^3.0.1"
       }
       "dev": true
     },
     "oauth-sign": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
-      "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+      "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": {
           "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
           "dev": true
         },
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
         "ansi-styles": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
             "through": "^2.3.6"
           }
         },
-        "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
-        },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "opn": {
           "version": "4.0.2",
           "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
             "pinkie-promise": "^2.0.0"
           }
         },
-        "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"
-              }
-            }
-          }
-        },
         "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
-        },
-        "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"
-          }
         }
       }
     },
         "wordwrap": "~0.0.2"
       },
       "dependencies": {
-        "wordwrap": {
-          "version": "0.0.3",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+        "minimist": {
+          "version": "0.0.10",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
           "dev": true
         }
       }
         "prelude-ls": "~1.1.2",
         "type-check": "~0.3.2",
         "wordwrap": "~1.0.0"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+          "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+          "dev": true
+        }
       }
     },
     "original": {
       "dev": true
     },
     "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
-      "dev": true,
-      "optional": true,
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+      "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
       "requires": {
-        "lcid": "^1.0.0"
+        "execa": "^0.7.0",
+        "lcid": "^1.0.0",
+        "mem": "^1.1.0"
       }
     },
     "os-name": {
       "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
     },
     "p-is-promise": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz",
-      "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+      "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
       "dev": true
     },
     "p-limit": {
             "yallist": "^3.0.3"
           }
         },
+        "y18n": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+          "dev": true
+        },
         "yallist": {
           "version": "3.0.3",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
       }
     },
     "pako": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
-      "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+      "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
       "dev": true
     },
     "parallel-transform": {
       "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
     },
     "path-parse": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
-      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+      "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": {
         "iconv-lite": "^0.4.24",
         "linebreak": "^0.3.0",
         "pdfkit": "^0.10.0"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.4.24",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
+        }
       }
     },
     "performance-now": {
         "supports-color": "^6.1.0"
       },
       "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          },
-          "dependencies": {
-            "supports-color": {
-              "version": "5.5.0",
-              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-              "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-              "dev": true,
-              "requires": {
-                "has-flag": "^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
-        },
-        "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"
-          }
         }
       }
     },
             "arrify": "^1.0.1",
             "minimatch": "^3.0.4"
           }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
             "pinkie-promise": "^2.0.0"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
           "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
           "dev": true
         },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
         "source-map-support": {
           "version": "0.4.18",
           "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
         "uuid": "^3.1.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"
-          }
-        },
         "q": {
           "version": "1.5.1",
           "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz",
       "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "public-encrypt": {
       "version": "4.0.3",
       }
     },
     "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
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+      "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
     },
     "q": {
       "version": "1.4.1",
         "buffer-equal": "0.0.1",
         "minimist": "^1.1.3",
         "through2": "^2.0.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
       }
     },
     "randombytes": {
           "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
           "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
           "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==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
         }
       }
     },
       "dev": true
     },
     "repeat-element": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
-      "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
+      "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": {
           "dev": true
         },
         "camelcase": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
-          "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
           "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==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
         "cliui": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
           "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
           "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
-        },
         "lcid": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
           }
         },
         "mem": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz",
-          "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==",
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
+          "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
           "dev": true,
           "requires": {
             "map-age-cleaner": "^0.1.1",
-            "mimic-fn": "^1.0.0",
+            "mimic-fn": "^2.0.0",
             "p-is-promise": "^2.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
+        },
         "os-locale": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
           }
         },
         "p-limit": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
-          "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
+          "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
           "dev": true,
           "requires": {
             "p-try": "^2.0.0"
           }
         },
         "p-try": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
-          "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
+          "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
         },
         "pump": {
             "once": "^1.3.1"
           }
         },
-        "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"
-          }
-        },
         "strip-ansi": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
             "ansi-regex": "^3.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
-        },
         "yargs": {
           "version": "12.0.5",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
       }
     },
     "request": {
-      "version": "2.87.0",
-      "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
-      "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
+      "version": "2.88.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
       "dev": true,
       "requires": {
         "aws-sign2": "~0.7.0",
-        "aws4": "^1.6.0",
+        "aws4": "^1.8.0",
         "caseless": "~0.12.0",
-        "combined-stream": "~1.0.5",
-        "extend": "~3.0.1",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
         "forever-agent": "~0.6.1",
-        "form-data": "~2.3.1",
-        "har-validator": "~5.0.3",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.0",
         "http-signature": "~1.2.0",
         "is-typedarray": "~1.0.0",
         "isstream": "~0.1.2",
         "json-stringify-safe": "~5.0.1",
-        "mime-types": "~2.1.17",
-        "oauth-sign": "~0.8.2",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
         "performance-now": "^2.1.0",
-        "qs": "~6.5.1",
-        "safe-buffer": "^5.1.1",
-        "tough-cookie": "~2.3.3",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.4.3",
         "tunnel-agent": "^0.6.0",
-        "uuid": "^3.1.0"
+        "uuid": "^3.3.2"
       }
     },
     "request-promise-core": {
       "dev": true
     },
     "resolve": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
-      "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
+      "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
       "dev": true,
       "requires": {
-        "path-parse": "^1.0.5"
+        "path-parse": "^1.0.6"
       }
     },
     "resolve-cwd": {
       "dev": true
     },
     "rimraf": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
-      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "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.0.5"
+        "glob": "^7.1.3"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+          "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"
+          }
+        }
       }
     },
     "ripemd160": {
             "pump": "^3.0.0"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "pump": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
         "rimraf": "^2.5.4",
         "tmp": "0.0.30",
         "xml2js": "^0.4.17"
+      },
+      "dependencies": {
+        "tmp": {
+          "version": "0.0.30",
+          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
+          "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
+          "dev": true,
+          "requires": {
+            "os-tmpdir": "~1.0.1"
+          }
+        }
       }
     },
     "selfsigned": {
       }
     },
     "semver": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
-      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
       "dev": true
     },
     "semver-dsl": {
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
     },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
+      "dev": true
+    },
     "set-value": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
         }
       }
     },
       "dev": true
     },
     "source-map": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
       "dev": true
     },
     "source-map-loader": {
       }
     },
     "source-map-support": {
-      "version": "0.5.6",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz",
-      "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==",
+      "version": "0.5.10",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
+      "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
       "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
       "dev": true
     },
     "spdx-correct": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
-      "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
       "dev": true,
       "requires": {
         "spdx-expression-parse": "^3.0.0",
       }
     },
     "spdx-exceptions": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
-      "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
       "dev": true
     },
     "spdx-expression-parse": {
       }
     },
     "spdx-license-ids": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
-      "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
+      "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==",
       "dev": true
     },
     "spdy": {
       "dev": true
     },
     "sshpk": {
-      "version": "1.14.2",
-      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
-      "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+      "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",
       }
     },
     "stack-utils": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz",
-      "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
+      "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==",
       "dev": true
     },
     "static-eval": {
       }
     },
     "string-width": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
       "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "strip-ansi": "^3.0.0"
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "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="
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
       }
     },
     "string_decoder": {
       }
     },
     "supports-color": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
-      "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+      "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"
             "figgy-pudding": "^3.5.1"
           }
         },
+        "y18n": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+          "dev": true
+        },
         "yallist": {
           "version": "3.0.3",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
       "dev": true
     },
     "tmp": {
-      "version": "0.0.30",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
-      "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
+      "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.1"
+        "os-tmpdir": "~1.0.2"
       }
     },
     "tmpl": {
       "dev": true
     },
     "tough-cookie": {
-      "version": "2.3.4",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
-      "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
       "dev": true,
       "requires": {
+        "psl": "^1.1.24",
         "punycode": "^1.4.1"
       },
       "dependencies": {
       "dev": true,
       "requires": {
         "punycode": "^2.1.0"
+      },
+      "dependencies": {
+        "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
+        }
       }
     },
     "traverse": {
         "fs-extra": "6.0.1",
         "json5": "^0.5.0",
         "lodash": "^4.17.10"
+      },
+      "dependencies": {
+        "fs-extra": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
+          "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "jsonfile": "^4.0.0",
+            "universalify": "^0.1.0"
+          }
+        },
+        "json5": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+          "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+          "dev": true
+        }
       }
     },
     "ts-node": {
             "path-type": "^3.0.0"
           }
         },
+        "fs-extra": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
+          "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "jsonfile": "^4.0.0",
+            "universalify": "^0.1.0"
+          }
+        },
         "globby": {
           "version": "8.0.2",
           "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz",
             "escape-string-regexp": "^1.0.5",
             "supports-color": "^5.3.0"
           }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
       "version": "0.14.5",
       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "type-check": {
       "version": "0.3.2",
       }
     },
     "upath": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
-      "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
+      "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
       "dev": true
     },
     "uri-js": {
       "dev": true,
       "requires": {
         "punycode": "^2.1.0"
+      },
+      "dependencies": {
+        "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
+        }
       }
     },
     "urix": {
       "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="
-        }
       }
     },
     "url-parse": {
       "dev": true
     },
     "validate-npm-package-license": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
-      "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
+      "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",
           "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
           "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
-        },
         "lcid": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
           "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
           "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"
-              }
-            }
+            "has-flag": "^3.0.0"
           }
         },
         "webpack-dev-middleware": {
             "webpack-log": "^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
-        },
         "yargs": {
           "version": "12.0.2",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz",
       "dev": true,
       "requires": {
         "iconv-lite": "0.4.24"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.4.24",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
+        }
       }
     },
     "whatwg-mimetype": {
       }
     },
     "which-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
-      "dev": true,
-      "optional": true
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
     },
     "wide-align": {
       "version": "1.1.3",
       }
     },
     "wordwrap": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
       "dev": true
     },
     "worker-farm": {
       "requires": {
         "string-width": "^1.0.1",
         "strip-ansi": "^3.0.1"
+      },
+      "dependencies": {
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        }
       }
     },
     "wrappy": {
       "dev": true
     },
     "y18n": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-      "dev": true
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
     },
     "yallist": {
       "version": "2.1.2",
           "dev": true,
           "optional": true
         },
+        "os-locale": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+          "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "lcid": "^1.0.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        },
+        "which-module": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+          "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+          "dev": true,
+          "optional": true
+        },
         "y18n": {
           "version": "3.2.1",
           "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
           "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
           "dev": true,
           "optional": true
+        },
+        "yargs-parser": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
+          "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "camelcase": "^3.0.0"
+          }
         }
       }
     },
     "yargs-parser": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
-      "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
-      "dev": true,
-      "optional": true,
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz",
+      "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==",
       "requires": {
-        "camelcase": "^3.0.0"
+        "camelcase": "^4.1.0"
       },
       "dependencies": {
         "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true,
-          "optional": true
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
         }
       }
     },
     "yn": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz",
-      "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz",
+      "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==",
       "dev": true
     },
     "zone.js": {
index 49d32d297603ca8d8b8d950b1cf44a8e3c2481fc..3af9d680392de391971c5ee3682d077ec29cd41a 100644 (file)
@@ -67,8 +67,8 @@
     "@auth0/angular-jwt": "2.1.0",
     "@ngx-translate/i18n-polyfill": "1.0.0",
     "@swimlane/ngx-datatable": "14.0.0",
-    "awesome-bootstrap-checkbox": "0.3.7",
-    "bootstrap": "3.4.1",
+    "awesome-bootstrap-checkbox": "1.0.1",
+    "bootstrap": "4.3.1",
     "chart.js": "2.7.3",
     "core-js": "2.6.5",
     "detect-browser": "4.1.0",
@@ -79,7 +79,7 @@
     "ng2-charts": "1.6.0",
     "ng2-toastr": "zzakir/ng2-toastr#0eafd72",
     "ng2-tree": "2.0.0-rc.11",
-    "ngx-bootstrap": "3.2.0",
+    "ngx-bootstrap": "4.3.0",
     "rxjs": "6.4.0",
     "rxjs-compat": "6.4.0",
     "tslib": "1.9.3",
index 936627290189c25816fd03a0a2144040987f8d1c..238524b866d23301e9fdd8b0fd3d2b293d76ae41 100644 (file)
@@ -1,4 +1,4 @@
-@import '../defaults';
+@import 'defaults';
 
 .dashboard {
   background-color: $color-whitesmoke-gray;
@@ -13,7 +13,7 @@
     margin-top: 2.5vw;
   }
 
-  @media (max-width: $screen-sm-max) {
+  @media (max-width: $screen-md-max) {
     margin-top: 9vw;
   }
 
index ac4bcf1a51a51722816d802670591f8cd8b8e9fb..e1e43c291a5c6e897d160aeb8561fcc380f5a726 100644 (file)
@@ -2,11 +2,11 @@
   <tab heading="Overview"
        i18n-heading
        [active]="url === '/block/iscsi/overview'"
-       (select)="navigateTo('/block/iscsi/overview')">
+       (selectTab)="navigateTo('/block/iscsi/overview')">
   </tab>
   <tab heading="Targets"
        i18n-heading
        [active]="url === '/block/iscsi/targets'"
-       (select)="navigateTo('/block/iscsi/targets')">
+       (selectTab)="navigateTo('/block/iscsi/targets')">
   </tab>
 </tabset>
index 080f458b73bc95dfc540e0e2c6552a826d303e1f..ed5ecec46c3a6d39257a35c5c867f9f6d770e613 100644 (file)
@@ -1,30 +1,32 @@
-<div class="col-sm-6 col-lg-6">
-  <legend i18n>iSCSI Topology</legend>
-  <tree [tree]="tree"
-        (nodeSelected)="onNodeSelected($event)">
-    <ng-template let-node>
-      <span class="node-name"
-            [innerHTML]="node.value"></span>
-      <span>&nbsp;</span>
+<div class="row">
+  <div class="col-6">
+    <legend i18n>iSCSI Topology</legend>
+    <tree [tree]="tree"
+          (nodeSelected)="onNodeSelected($event)">
+      <ng-template let-node>
+        <span class="node-name"
+              [innerHTML]="node.value"></span>
+        <span>&nbsp;</span>
 
-      <span class="label"
-            [ngClass]="{'label-success': ['logged_in'].includes(node.status), 'label-danger': ['logged_out'].includes(node.status)}">
-        {{ node.status }}
-      </span>
-    </ng-template>
-  </tree>
-</div>
+        <span class="badge"
+              [ngClass]="{'badge-success': ['logged_in'].includes(node.status), 'badge-danger': ['logged_out'].includes(node.status)}">
+          {{ node.status }}
+        </span>
+      </ng-template>
+    </tree>
+  </div>
 
-<div class="col-sm-6 col-lg-6 metadata"
-     *ngIf="data">
-  <legend>{{ title }}</legend>
+  <div class="col-6 metadata"
+       *ngIf="data">
+    <legend>{{ title }}</legend>
 
-  <cd-table #detailTable
-            [data]="data"
-            columnMode="flex"
-            [columns]="columns"
-            [limit]="0">
-  </cd-table>
+    <cd-table #detailTable
+              [data]="data"
+              columnMode="flex"
+              [columns]="columns"
+              [limit]="0">
+    </cd-table>
+  </div>
 </div>
 
 <ng-template #highlightTpl
index 7894005bc05f26492c7c48dcf885f4bf78511faf..852c7619926784739bee049f223f170d56a3c713 100644 (file)
@@ -111,8 +111,8 @@ describe('IscsiTargetDetailsComponent', () => {
           children: [{ id: 'disk_rbd_disk_1', value: 'rbd/disk_1' }],
           settings: {
             cssClasses: {
-              expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
-              leaf: _.join([Icons.width, Icons.disk], ' ')
+              expanded: _.join([Icons.large, Icons.disk], ' '),
+              leaf: _.join([Icons.disk], ' ')
             },
             selectionAllowed: false
           },
@@ -122,8 +122,8 @@ describe('IscsiTargetDetailsComponent', () => {
           children: [{ value: 'node1:192.168.100.201' }],
           settings: {
             cssClasses: {
-              expanded: _.join([Icons.width, Icons.large, Icons.server], ' '),
-              leaf: _.join([Icons.width, Icons.large, Icons.server], ' ')
+              expanded: _.join([Icons.large, Icons.server], ' '),
+              leaf: _.join([Icons.large, Icons.server], ' ')
             },
             selectionAllowed: false
           },
@@ -137,8 +137,8 @@ describe('IscsiTargetDetailsComponent', () => {
                   id: 'disk_rbd_disk_1',
                   settings: {
                     cssClasses: {
-                      expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
-                      leaf: _.join([Icons.width, Icons.disk], ' ')
+                      expanded: _.join([Icons.large, Icons.disk], ' '),
+                      leaf: _.join([Icons.disk], ' ')
                     }
                   },
                   value: 'rbd/disk_1'
@@ -151,8 +151,8 @@ describe('IscsiTargetDetailsComponent', () => {
           ],
           settings: {
             cssClasses: {
-              expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
-              leaf: _.join([Icons.width, Icons.user], ' ')
+              expanded: _.join([Icons.large, Icons.user], ' '),
+              leaf: _.join([Icons.user], ' ')
             },
             selectionAllowed: false
           },
@@ -162,8 +162,8 @@ describe('IscsiTargetDetailsComponent', () => {
           children: [],
           settings: {
             cssClasses: {
-              expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
-              leaf: _.join([Icons.width, Icons.user], ' ')
+              expanded: _.join([Icons.large, Icons.user], ' '),
+              leaf: _.join([Icons.user], ' ')
             },
             selectionAllowed: false
           },
@@ -172,7 +172,7 @@ describe('IscsiTargetDetailsComponent', () => {
       ],
       id: 'root',
       settings: {
-        cssClasses: { expanded: _.join([Icons.width, Icons.large, Icons.bullseye], ' ') },
+        cssClasses: { expanded: _.join([Icons.large, Icons.bullseye], ' ') },
         static: true
       },
       value: 'iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw'
index 985434b834c7701d56d710b4206ef3d3e85cbbef..07499f34848994158383fc41c1abd4c27f97cfdd 100644 (file)
@@ -78,23 +78,23 @@ export class IscsiTargetDetailsComponent implements OnChanges, OnInit {
     this.metadata = { root: this.selectedItem.target_controls };
     const cssClasses = {
       target: {
-        expanded: _.join([Icons.width, Icons.large, Icons.bullseye], ' ')
+        expanded: _.join([Icons.large, Icons.bullseye], ' ')
       },
       initiators: {
-        expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
-        leaf: _.join([Icons.width, Icons.user], ' ')
+        expanded: _.join([Icons.large, Icons.user], ' '),
+        leaf: _.join([Icons.user], ' ')
       },
       groups: {
-        expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
-        leaf: _.join([Icons.width, Icons.user], ' ')
+        expanded: _.join([Icons.large, Icons.user], ' '),
+        leaf: _.join([Icons.user], ' ')
       },
       disks: {
-        expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
-        leaf: _.join([Icons.width, Icons.disk], ' ')
+        expanded: _.join([Icons.large, Icons.disk], ' '),
+        leaf: _.join([Icons.disk], ' ')
       },
       portals: {
-        expanded: _.join([Icons.width, Icons.large, Icons.server], ' '),
-        leaf: _.join([Icons.width, Icons.large, Icons.server], ' ')
+        expanded: _.join([Icons.large, Icons.server], ' '),
+        leaf: _.join([Icons.large, Icons.server], ' ')
       }
     };
 
index 9fe64e8317158a0e409091079d93f67d45743e14..4e3679c3721487f8c1e1959bac8eee9df3730969 100644 (file)
@@ -4,15 +4,14 @@
 
   <ng-container class="modal-content">
     <form name="discoveryForm"
-          class="form-horizontal"
           #formDir="ngForm"
           [formGroup]="discoveryForm"
           novalidate>
       <div class="modal-body">
         <!-- User -->
-        <div class="form-group"
-             [ngClass]="{'has-error': discoveryForm.showError('user', formDir)}">
-          <label class="control-label col-sm-4"
+        <div class="form-group row"
+             [ngClass]="{':invalid': discoveryForm.showError('user', formDir)}">
+          <label class="col-form-label col-sm-4"
                  for="user"
                  i18n>User</label>
           <div class="col-sm-8">
                    class="form-control"
                    formControlName="user"
                    type="text">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('user', formDir, 'required')"
                   i18n>This field is required.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('user', formDir, 'pattern')"
                   i18n>Usernames must have a length of 8 to 64 characters and
               can only contain letters, '.', '@', '-', '_' or ':'.</span>
@@ -32,9 +31,9 @@
         </div>
 
         <!-- Password -->
-        <div class="form-group"
-             [ngClass]="{'has-error': discoveryForm.showError('password', formDir)}">
-          <label class="control-label col-sm-4"
+        <div class="form-group row"
+             [ngClass]="{':invalid': discoveryForm.showError('password', formDir)}">
+          <label class="col-form-label col-sm-4"
                  for="password"
                  i18n>Password</label>
           <div class="col-sm-8">
                      formControlName="password"
                      type="password">
 
-              <span class="input-group-btn">
+              <span class="input-group-append">
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdPasswordButton="password">
                 </button>
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdCopy2ClipboardButton="password">
                 </button>
               </span>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('password', formDir, 'required')"
                   i18n>This field is required.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('password', formDir, 'pattern')"
                   i18n>Passwords must have a length of 12 to 16 characters
               and can only contain letters, '@', '-', '_' or '/'.</span>
@@ -67,9 +66,9 @@
         </div>
 
         <!-- mutual_user -->
-        <div class="form-group"
-             [ngClass]="{'has-error': discoveryForm.showError('mutual_user', formDir)}">
-          <label class="control-label col-sm-4"
+        <div class="form-group row"
+             [ngClass]="{':invalid': discoveryForm.showError('mutual_user', formDir)}">
+          <label class="col-form-label col-sm-4"
                  for="mutual_user">
             <ng-container i18n>Mutual User</ng-container>
           </label>
                    formControlName="mutual_user"
                    type="text">
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('mutual_user', formDir, 'required')"
                   i18n>This field is required.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('mutual_user', formDir, 'pattern')"
                   i18n>Usernames must have a length of 8 to 64 characters and
               can only contain letters, '.', '@', '-', '_' or ':'.</span>
@@ -91,9 +90,9 @@
         </div>
 
         <!-- mutual_password -->
-        <div class="form-group"
-             [ngClass]="{'has-error': discoveryForm.showError('mutual_password', formDir)}">
-          <label class="control-label col-sm-4"
+        <div class="form-group row"
+             [ngClass]="{':invalid': discoveryForm.showError('mutual_password', formDir)}">
+          <label class="col-form-label col-sm-4"
                  for="mutual_password"
                  i18n>Mutual Password</label>
           <div class="col-sm-8">
                      formControlName="mutual_password"
                      type="password">
 
-              <span class="input-group-btn">
+              <span class="input-group-append">
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdPasswordButton="mutual_password">
                 </button>
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdCopy2ClipboardButton="mutual_password">
                 </button>
               </span>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('mutual_password', formDir, 'required')"
                   i18n>This field is required.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="discoveryForm.showError('mutual_password', formDir, 'pattern')"
                   i18n>Passwords must have a length of 12 to 16 characters and
               can only contain letters, '@', '-', '_' or '/'.</span>
index e3d56d301a60c65555454af1814c6b8d544c6882..9d425899e64d414990c16d011c228216c6e592de 100644 (file)
@@ -1,21 +1,18 @@
 <div class="col-sm-12 col-lg-6">
   <form name="targetForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="targetForm"
         novalidate
         *ngIf="targetForm">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
 
-      <div class="panel-body">
+      <div class="card-body">
         <!-- Target IQN -->
-        <div class="form-group"
-             [ngClass]="{'has-error': targetForm.showError('target_iqn', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': targetForm.showError('target_iqn', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="target_iqn">
             <ng-container i18n>Target IQN</ng-container>
             <span class="required"></span>
                      id="target_iqn"
                      name="target_iqn"
                      formControlName="target_iqn" />
-              <span class="input-group-btn">
-                <button class="btn btn-default"
+              <span class="input-group-append">
+                <button class="btn btn-light"
                         id="ecp-info-button"
                         type="button"
                         (click)="targetSettingsModal()">
-                  <i [ngClass]="[icons.deepCheck, icons.width]"
+                  <i [ngClass]="[icons.deepCheck]"
                      aria-hidden="true"></i>
                 </button>
               </span>
             </div>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="targetForm.showError('target_iqn', formDir, 'required')"
                   i18n>This field is required.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="targetForm.showError('target_iqn', formDir, 'pattern')"
                   i18n>IQN has wrong pattern.</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="targetForm.showError('target_iqn', formDir, 'iqn')">
-              <ng-container i18n>An IQN has the following notation 'iqn.$year-$month.$reversedAddress:$definedName'</ng-container>
+              <ng-container i18n>An IQN has the following notation
+                'iqn.$year-$month.$reversedAddress:$definedName'</ng-container>
               <br>
               <ng-container i18n>For example: iqn.2016-06.org.dashboard:storage:disk.sn-a8675309</ng-container>
               <br>
@@ -57,7 +55,7 @@
                  i18n>More information</a>
             </span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))"
                   i18n>This target has modified advanced settings.</span>
             <hr />
@@ -65,9 +63,9 @@
         </div>
 
         <!-- Portals -->
-        <div class="form-group"
-             [ngClass]="{'has-error': targetForm.showError('portals', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': targetForm.showError('portals', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="portals">
             <ng-container i18n>Portals</ng-container>
             <span class="required"></span>
 
             <ng-container *ngFor="let portal of portals.value; let i = index">
               <div class="input-group cd-mb">
-                <input class="form-control"
+                <input class="cd-form-control"
                        type="text"
                        [value]="portal"
                        disabled />
-                <span class="input-group-btn">
-                  <button class="btn btn-default"
+                <span class="input-group-append">
+                  <button class="btn btn-light"
                           type="button"
                           (click)="removePortal(i, portal)">
-                    <i [ngClass]="[icons.destroy, icons.width]"
+                    <i [ngClass]="[icons.destroy]"
                        aria-hidden="true"></i>
                   </button>
                 </span>
               </div>
             </ng-container>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="targetForm.showError('portals', formDir, 'minGateways')"
                   i18n>At least {{ minimum_gateways }} gateways are required.</span>
 
                            [options]="portalsSelections"
                            [messages]="messages.portals"
                            (selection)="onPortalSelection($event)"
-                           elemClass="btn btn-default pull-right">
-                  <i [ngClass]="[icons.add, icons.width]"></i>
+                           elemClass="btn btn-light float-right">
+                  <i [ngClass]="[icons.add]"></i>
                   <ng-container i18n>Add portal</ng-container>
                 </cd-select>
               </div>
         </div>
 
         <!-- Images -->
-        <div class="form-group"
-             [ngClass]="{'has-error': targetForm.showError('disks', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': targetForm.showError('disks', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="disks"
                  i18n>Images</label>
           <div class="col-sm-9">
             <ng-container *ngFor="let image of targetForm.getValue('disks'); let i = index">
               <div class="input-group cd-mb">
-                <input class="form-control"
+                <input class="cd-form-control"
                        type="text"
                        [value]="image"
                        disabled />
-                <span class="input-group-btn">
-                  <button class="btn btn-default"
+                <span class="input-group-append">
+                  <button class="btn btn-light"
                           type="button"
                           (click)="imageSettingsModal(image)">
-                    <i [ngClass]="[icons.deepCheck, icons.width]"
+                    <i [ngClass]="[icons.deepCheck]"
                        aria-hidden="true"></i>
                   </button>
-                  <button class="btn btn-default"
+                  <button class="btn btn-light"
                           type="button"
                           (click)="removeImage(i, image)">
-                    <i [ngClass]="[icons.destroy, icons.width]"
+                    <i [ngClass]="[icons.destroy]"
                        aria-hidden="true"></i>
                   </button>
                 </span>
 
               </div>
 
-              <span class="help-block">
+              <span class="form-text text-muted">
                 <ng-container *ngIf="backstores.length > 1"
                               i18n>Backstore: {{ imagesSettings[image].backstore | iscsiBackstore }}.&nbsp;</ng-container>
 
               </span>
             </ng-container>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="targetForm.showError('disks', formDir, 'required')"
                   i18n>At least 1 image is required.</span>
 
                            [options]="imagesSelections"
                            [messages]="messages.images"
                            (selection)="onImageSelection($event)"
-                           elemClass="btn btn-default pull-right">
-                  <i [ngClass]="[icons.add, icons.width]"></i>
+                           elemClass="btn btn-light float-right">
+                  <i [ngClass]="[icons.add]"></i>
                   <ng-container i18n>Add image</ng-container>
                 </cd-select>
               </div>
         </div>
 
         <!-- acl_enabled -->
-        <div class="form-group">
-          <div class="col-sm-offset-3 col-sm-9">
+        <div class="form-group row">
+          <div class="offset-sm-3 col-sm-9">
             <div class="checkbox checkbox-primary">
               <input type="checkbox"
                      formControlName="acl_enabled"
         </div>
 
         <!-- Initiators -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="targetForm.getValue('acl_enabled')">
-          <label class="control-label col-sm-3"
+          <label class="col-form-label col-sm-3"
                  for="initiators"
                  i18n>Initiators</label>
           <div class="col-sm-9"
                formArrayName="initiators">
-            <div class="panel panel-default"
+            <div class="card mb-2"
                  *ngFor="let initiator of initiators.controls; let ii = index"
                  [formGroupName]="ii">
-              <div class="panel-heading">
+              <div class="card-header">
                 <ng-container i18n>Initiator</ng-container>: {{ initiator.getValue('client_iqn') }}
                 <button type="button"
                         class="close"
                         (click)="removeInitiator(ii)">
-                  <i [ngClass]="[icons.deepCheck, icons.width]"></i>
+                  <i [ngClass]="[icons.deepCheck]"></i>
                 </button>
               </div>
-              <div class="panel-body">
+              <div class="card-body">
                 <!-- Initiator: Name -->
-                <div class="form-group"
-                     [ngClass]="{'has-error': initiator.showError('client_iqn', formDir)}">
-                  <label class="control-label col-sm-3"
+                <div class="form-group row"
+                     [ngClass]="{':invalid': initiator.showError('client_iqn', formDir)}">
+                  <label class="col-form-label col-sm-3"
                          for="client_iqn">
                     <ng-container i18n>Client IQN</ng-container>
                     <span class="required"></span>
                            formControlName="client_iqn"
                            (blur)="updatedInitiatorSelector()">
 
-                    <span class="help-block"
+                    <span class="form-text text-muted"
                           *ngIf="initiator.showError('client_iqn', formDir, 'notUnique')"
                           i18n>Initiator IQN needs to be unique.</span>
 
-                    <span class="help-block"
+                    <span class="form-text text-muted"
                           *ngIf="initiator.showError('client_iqn', formDir, 'required')"
                           i18n>This field is required.</span>
 
-                    <span class="help-block"
+                    <span class="form-text text-muted"
                           *ngIf="initiator.showError('client_iqn', formDir, 'pattern')"
                           i18n>IQN has wrong pattern.</span>
                   </div>
 
                 <ng-container formGroupName="auth">
                   <!-- Initiator: User -->
-                  <div class="form-group"
-                       [ngClass]="{'has-error': initiator.showError('user', formDir)}">
-                    <label class="control-label col-sm-3"
+                  <div class="form-group row"
+                       [ngClass]="{':invalid': initiator.showError('user', formDir)}">
+                    <label class="col-form-label col-sm-3"
                            for="user"
                            i18n>User</label>
                     <div class="col-sm-9">
                              class="form-control"
                              formControlName="user"
                              type="text">
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('user', formDir, 'required')"
                             i18n>This field is required.</span>
 
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('user', formDir, 'pattern')"
                             i18n>Usernames must have a length of 8 to 64 characters and
                         can only contain letters, '.', '@', '-', '_' or ':'.</span>
                   </div>
 
                   <!-- Initiator: Password -->
-                  <div class="form-group"
-                       [ngClass]="{'has-error': initiator.showError('password', formDir)}">
-                    <label class="control-label col-sm-3"
+                  <div class="form-group row"
+                       [ngClass]="{':invalid': initiator.showError('password', formDir)}">
+                    <label class="col-form-label col-sm-3"
                            for="password"
                            i18n>Password</label>
                     <div class="col-sm-9">
                                formControlName="password"
                                type="password">
 
-                        <span class="input-group-btn">
+                        <span class="input-group-append">
                           <button type="button"
-                                  class="btn btn-default"
+                                  class="btn btn-light"
                                   [cdPasswordButton]="'password' + ii">
                           </button>
                           <button type="button"
-                                  class="btn btn-default"
+                                  class="btn btn-light"
                                   [cdCopy2ClipboardButton]="'password' + ii">
                           </button>
                         </span>
                       </div>
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('password', formDir, 'required')"
                             i18n>This field is required.</span>
 
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('password', formDir, 'pattern')"
                             i18n>Passwords must have a length of 12 to 16 characters
                         and can only contain letters, '@', '-', '_' or '/'.</span>
 
 
                   <!-- Initiator: mutual_user -->
-                  <div class="form-group"
-                       [ngClass]="{'has-error': initiator.showError('mutual_user', formDir)}">
-                    <label class="control-label col-sm-3"
+                  <div class="form-group row"
+                       [ngClass]="{':invalid': initiator.showError('mutual_user', formDir)}">
+                    <label class="col-form-label col-sm-3"
                            for="mutual_user">
                       <ng-container i18n>Mutual User</ng-container>
                     </label>
                              formControlName="mutual_user"
                              type="text">
 
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('mutual_user', formDir, 'required')"
                             i18n>This field is required.</span>
 
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('mutual_user', formDir, 'pattern')"
                             i18n>Usernames must have a length of 8 to 64 characters and
                         can only contain letters, '.', '@', '-', '_' or ':'.</span>
                   </div>
 
                   <!-- Initiator: mutual_password -->
-                  <div class="form-group"
-                       [ngClass]="{'has-error': initiator.showError('mutual_password', formDir)}">
-                    <label class="control-label col-sm-3"
+                  <div class="form-group row"
+                       [ngClass]="{':invalid': initiator.showError('mutual_password', formDir)}">
+                    <label class="col-form-label col-sm-3"
                            for="mutual_password"
                            i18n>Mutual Password</label>
                     <div class="col-sm-9">
                                formControlName="mutual_password"
                                type="password">
 
-                        <span class="input-group-btn">
+                        <span class="input-group-append">
                           <button type="button"
-                                  class="btn btn-default"
+                                  class="btn btn-light"
                                   [cdPasswordButton]="'mutual_password' + ii">
                           </button>
                           <button type="button"
-                                  class="btn btn-default"
+                                  class="btn btn-light"
                                   [cdCopy2ClipboardButton]="'mutual_password' + ii">
                           </button>
                         </span>
                       </div>
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('mutual_password', formDir, 'required')"
                             i18n>This field is required.</span>
 
-                      <span class="help-block"
+                      <span class="form-text text-muted"
                             *ngIf="initiator.showError('mutual_password', formDir, 'pattern')"
                             i18n>Passwords must have a length of 12 to 16 characters and
                         can only contain letters, '@', '-', '_' or '/'.</span>
                 </ng-container>
 
                 <!-- Initiator: Images -->
-                <div class="form-group"
-                     [ngClass]="{'has-error': initiator.showError('luns', formDir)}">
-                  <label class="control-label col-sm-3"
+                <div class="form-group row"
+                     [ngClass]="{':invalid': initiator.showError('luns', formDir)}">
+                  <label class="col-form-label col-sm-3"
                          for="luns"
                          i18n>Images</label>
                   <div class="col-sm-9">
                     <ng-container *ngFor="let image of initiator.getValue('luns'); let li = index">
                       <div class="input-group cd-mb">
-                        <input class="form-control"
+                        <input class="cd-form-control"
                                type="text"
                                [value]="image"
                                disabled />
-                        <span class="input-group-btn">
-                          <button class="btn btn-default"
+                        <span class="input-group-append">
+                          <button class="btn btn-light"
                                   type="button"
                                   (click)="removeInitiatorImage(initiator, li, ii, image)">
-                            <i [ngClass]="[icons.destroy, icons.width]"
+                            <i [ngClass]="[icons.destroy]"
                                aria-hidden="true"></i>
                           </button>
                         </span>
                         <cd-select [data]="initiator.getValue('luns')"
                                    [options]="imagesInitiatorSelections[ii]"
                                    [messages]="messages.initiatorImage"
-                                   elemClass="btn btn-default pull-right">
-                          <i [ngClass]="[icons.add, icons.width]"></i>
+                                   elemClass="btn btn-light float-right">
+                          <i [ngClass]="[icons.add]"></i>
                           <ng-container i18n>Add image</ng-container>
                         </cd-select>
                       </div>
 
             <div class="row">
               <div class="col-md-12">
-                <span class="text-muted"
+                <span class="form-text text-muted"
                       *ngIf="initiators.controls.length === 0"
                       i18n>No items added.</span>
 
                 <button (click)="addInitiator(); false"
-                        class="btn btn-default pull-right">
-                  <i [ngClass]="[icons.add, icons.width]"></i>
+                        class="btn btn-light float-right">
+                  <i [ngClass]="[icons.add]"></i>
                   <ng-container i18n>Add initiator</ng-container>
                 </button>
               </div>
         </div>
 
         <!-- Groups -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="targetForm.getValue('acl_enabled')"
-             [ngClass]="{'has-error': targetForm.showError('groups', formDir)}">
-          <label class="control-label col-sm-3"
+             [ngClass]="{':invalid': targetForm.showError('groups', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="initiators"
                  i18n>Groups</label>
           <div class="col-sm-9"
                formArrayName="groups">
-            <div class="panel panel-default"
+            <div class="card mb-2"
                  *ngFor="let group of groups.controls; let gi = index"
                  [formGroupName]="gi">
-              <div class="panel-heading">
+              <div class="card-header">
                 <ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }}
                 <button type="button"
                         class="close"
                         (click)="groups.removeAt(gi)">
-                  <i [ngClass]="[icons.destroy, icons.width]"></i>
+                  <i [ngClass]="[icons.destroy]"></i>
                 </button>
               </div>
-              <div class="panel-body">
+              <div class="card-body">
                 <!-- Group: group_id -->
-                <div class="form-group">
-                  <label class="control-label col-sm-3"
+                <div class="form-group row">
+                  <label class="col-form-label col-sm-3"
                          for="group_id">
                     <ng-container i18n>Name</ng-container>
                     <span class="required"></span>
                 </div>
 
                 <!-- Group: members -->
-                <div class="form-group"
-                     [ngClass]="{'has-error': group.showError('members', formDir)}">
-                  <label class="control-label col-sm-3"
+                <div class="form-group row"
+                     [ngClass]="{':invalid': group.showError('members', formDir)}">
+                  <label class="col-form-label col-sm-3"
                          for="members">
                     <ng-container i18n>Initiators</ng-container>
                   </label>
                   <div class="col-sm-9">
                     <ng-container *ngFor="let member of group.getValue('members'); let i = index">
                       <div class="input-group cd-mb">
-                        <input class="form-control"
+                        <input class="cd-form-control"
                                type="text"
                                [value]="member"
                                disabled />
-                        <span class="input-group-btn">
-                          <button class="btn btn-default"
+                        <span class="input-group-append">
+                          <button class="btn btn-light"
                                   type="button"
                                   (click)="removeGroupInitiator(group, i, gi)">
-                            <i [ngClass]="[icons.destroy, icons.width]"
+                            <i [ngClass]="[icons.destroy]"
                                aria-hidden="true"></i>
                           </button>
                         </span>
                                    [options]="groupMembersSelections[gi]"
                                    [messages]="messages.groupInitiator"
                                    (selection)="onGroupMemberSelection($event)"
-                                   elemClass="btn btn-default pull-right">
-                          <i [ngClass]="[icons.add, icons.width]"></i>
+                                   elemClass="btn btn-light float-right">
+                          <i [ngClass]="[icons.add]"></i>
                           <ng-container i18n>Add initiator</ng-container>
                         </cd-select>
                       </div>
                 </div>
 
                 <!-- Group: disks -->
-                <div class="form-group"
-                     [ngClass]="{'has-error': group.showError('disks', formDir)}">
-                  <label class="control-label col-sm-3"
+                <div class="form-group row"
+                     [ngClass]="{':invalid': group.showError('disks', formDir)}">
+                  <label class="col-form-label col-sm-3"
                          for="disks">
                     <ng-container i18n>Images</ng-container>
                   </label>
                   <div class="col-sm-9">
                     <ng-container *ngFor="let disk of group.getValue('disks'); let i = index">
                       <div class="input-group cd-mb">
-                        <input class="form-control"
+                        <input class="cd-form-control"
                                type="text"
                                [value]="disk"
                                disabled />
-                        <span class="input-group-btn">
-                          <button class="btn btn-default"
+                        <span class="input-group-append">
+                          <button class="btn btn-light"
                                   type="button"
                                   (click)="removeGroupDisk(group, i, gi)">
-                            <i [ngClass]="[icons.destroy, icons.width]"
+                            <i [ngClass]="[icons.destroy]"
                                aria-hidden="true"></i>
                           </button>
                         </span>
                         <cd-select [data]="group.getValue('disks')"
                                    [options]="groupDiskSelections[gi]"
                                    [messages]="messages.initiatorImage"
-                                   elemClass="btn btn-default pull-right">
-                          <i [ngClass]="[icons.add, icons.width]"></i>
+                                   elemClass="btn btn-light float-right">
+                          <i [ngClass]="[icons.add]"></i>
                           <ng-container i18n>Add image</ng-container>
                         </cd-select>
                       </div>
 
             <div class="row">
               <div class="col-md-12">
-                <span class="text-muted"
+                <span class="form-text text-muted"
                       *ngIf="groups.controls.length === 0"
                       i18n>No items added.</span>
 
                 <button (click)="addGroup(); false"
-                        class="btn btn-default pull-right">
-                  <i [ngClass]="[icons.add, icons.width]"></i>
+                        class="btn btn-light float-right">
+                  <i [ngClass]="[icons.add]"></i>
                   <ng-container i18n>Add group</ng-container>
                 </button>
               </div>
         </div>
 
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            [form]="formDir"
-            (submitAction)="submit()"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="submit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index c0dd35b5fee947df980a743eefea342f02983a62..df7823661a611f107f758168aae8a388331a157b 100644 (file)
@@ -12,7 +12,7 @@
       <!-- BACKSTORE -->
       <div class="form-group row">
         <div class="col-sm-12">
-          <label class="control-label"
+          <label class="col-form-label"
                  i18n>Backstore</label>
           <select id="backstore"
                   name="backstore"
           <div class="form-group row"
                *ngFor="let setting of disk_default_controls[bs] | keyvalue">
             <div class="col-sm-12">
-              <label class="control-label"
+              <label class="col-form-label"
                      for="{{ setting.key }}">{{ setting.key }}</label>
               <input type="number"
                      class="form-control"
                      [(ngModel)]="model[bs][setting.key]">
-              <span class="help-block">{{ helpText[setting.key]?.help }}</span>
+              <span class="form-text text-muted">{{ helpText[setting.key]?.help }}</span>
             </div>
           </div>
         </ng-container>
@@ -45,7 +45,7 @@
 
     <div class="modal-footer">
       <div class="button-group text-right">
-        <button class="btn btn-sm btn-primary"
+        <button class="btn btn-secondary"
                 (click)="save()"
                 i18n>Confirm</button>
         <cd-back-button [back]="modalRef.hide"
index 4707dafe8d2b1761b1bcbe3657cb1d7a5fcccb28..310a1ec2747d9bc26cf0f38290e6523397982082 100644 (file)
@@ -4,7 +4,6 @@
 
   <ng-container class="modal-content">
     <form name="settingsForm"
-          class="form"
           #formDir="ngForm"
           [formGroup]="settingsForm"
           novalidate>
@@ -14,9 +13,9 @@
 
         <div class="form-group row"
              *ngFor="let setting of settingsForm.controls | keyvalue"
-             [ngClass]="{'has-error': settingsForm.showError(setting.key, formDir)}">
+             [ngClass]="{':invalid': settingsForm.showError(setting.key, formDir)}">
           <div class="col-sm-12">
-            <label class="control-label"
+            <label class="col-form-label"
                    for="{{ setting.key }}">{{ setting.key }}</label>
             <input class="form-control"
                    *ngIf="!isRadio(setting.key)"
 
             <ng-container *ngIf="isRadio(setting.key)">
               <br>
-              <div class="radio radio-inline">
+              <div class="custom-control custom-radio custom-control-inline">
                 <input type="radio"
                        [id]="setting.key + 'Yes'"
                        value="Yes"
-                       [formControlName]="setting.key">
-                <label [for]="setting.key + 'Yes'">Yes</label>
+                       [formControlName]="setting.key"
+                       class="custom-control-input">
+                <label class="custom-col-form-label"
+                       [for]="setting.key + 'Yes'">Yes</label>
               </div>
-              <div class="radio radio-inline">
+              <div class="custom-control custom-radio custom-control-inline">
                 <input type="radio"
                        [id]="setting.key + 'No'"
                        value="No"
+                       class="custom-control-input"
                        [formControlName]="setting.key">
-                <label [for]="setting.key + 'No'">No</label>
+                <label class="custom-col-form-label"
+                       [for]="setting.key + 'No'">No</label>
               </div>
             </ng-container>
 
-            <span class="help-block">{{ helpText[setting.key]?.help }}</span>
+            <span class="form-text text-muted">{{ helpText[setting.key]?.help }}</span>
           </div>
         </div>
       </div>
index a99424c6408a74c24df59006732772a0df04ea8f..985bd476e3f4f74bc485028c4da06394a9cf658a 100644 (file)
                       [tableActions]="tableActions">
     </cd-table-actions>
 
-    <button class="btn btn-sm btn-default btn-label"
+    <button class="btn btn-light"
             type="button"
             (click)="configureDiscoveryAuth()">
-      <i [ngClass]="[icons.key, icons.width]"
+      <i [ngClass]="[icons.key]"
          aria-hidden="true">
       </i>
       <ng-container i18n>Discovery authentication</ng-container>
index 59604a2438302c3f3c40ad4f9eb5db663a374ee8..4f65b3f2c54d01ea26a75a8b034bf552e55e20d0 100644 (file)
@@ -13,8 +13,8 @@
 
 <ng-template #statusColorTpl
              let-value="value">
-  <span class="label"
-        [ngClass]="{'label-success': 'up' == value, 'label-danger': 'down' == value}">{{ value }}</span>
+  <span class="badge"
+        [ngClass]="{'badge-success': 'up' == value, 'badge-danger': 'down' == value}">{{ value }}</span>
 </ng-template>
 
 <ng-template #iscsiSparklineTpl
index 419217b2ec7ce5a3dd767bed1e15c6d2b43babd4..41be217998cae83e7877bf1ff26470a4967931e0 100644 (file)
@@ -35,7 +35,7 @@
 </ng-template>
 
 <ng-template #syncTmpl>
-  <span class="label label-info" i18n>Syncing</span>
+  <span class="badge badge-info" i18n>Syncing</span>
 </ng-template>
 
 <ng-template #progressTmpl
index 2b1738c8b4cb97f01d6a52d06515bf5fec9dc668..52ff84be1043ac9a583ced02cfec342503bb75d7 100644 (file)
@@ -8,18 +8,18 @@ describe('MirrorHealthColorPipe', () => {
   });
 
   it('transforms "warning"', () => {
-    expect(pipe.transform('warning')).toBe('label label-warning');
+    expect(pipe.transform('warning')).toBe('badge badge-warning');
   });
 
   it('transforms "error"', () => {
-    expect(pipe.transform('error')).toBe('label label-danger');
+    expect(pipe.transform('error')).toBe('badge badge-danger');
   });
 
   it('transforms "success"', () => {
-    expect(pipe.transform('success')).toBe('label label-success');
+    expect(pipe.transform('success')).toBe('badge badge-success');
   });
 
   it('transforms others', () => {
-    expect(pipe.transform('abc')).toBe('label label-info');
+    expect(pipe.transform('abc')).toBe('badge badge-info');
   });
 });
index 33e0204c69e9a4258febe2ac11119e0f94a6b2c2..3c25d715e5e309de195691a3947b84296dfaa503 100644 (file)
@@ -6,12 +6,12 @@ import { Pipe, PipeTransform } from '@angular/core';
 export class MirrorHealthColorPipe implements PipeTransform {
   transform(value: any): any {
     if (value === 'warning') {
-      return 'label label-warning';
+      return 'badge badge-warning';
     } else if (value === 'error') {
-      return 'label label-danger';
+      return 'badge badge-danger';
     } else if (value === 'success') {
-      return 'label label-success';
+      return 'badge badge-success';
     }
-    return 'label label-info';
+    return 'badge badge-info';
   }
 }
index bc5bb0f6a44ebe26ed388884813ee4e2cca7bd2e..6a919d7b5281237e85b5975bd17ec3272d1d3c0f 100644 (file)
@@ -16,8 +16,8 @@
         </p>
 
         <div class="form-group"
-             [ngClass]="{'has-error': editModeForm.showError('mirrorMode', formDir)}">
-          <label class="control-label"
+             [ngClass]="{':invalid': editModeForm.showError('mirrorMode', formDir)}">
+          <label class="col-form-label"
                  for="mirrorMode">
             <span i18n>Mode</span>
           </label>
@@ -28,7 +28,7 @@
             <option *ngFor="let mirrorMode of mirrorModes"
                     [value]="mirrorMode.id">{{ mirrorMode.name }}</option>
           </select>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editModeForm.showError('mirrorMode', formDir, 'cannotDisable')"
                 i18n>Peer clusters must be removed prior to disabling mirror.</span>
         </div>
index 66291d9418664054a7238cfc233601e7f38e1e1f..6dffc7d5cf6d268e5cce447d0b52c950c2f94e00 100644 (file)
       <div class="modal-body">
         <p>
           <ng-container i18n>{mode, select, edit {Edit} other {Add}} the pool
-          mirror peer attributes for pool <kbd>{{ poolName }}</kbd> and click 
+          mirror peer attributes for pool <kbd>{{ poolName }}</kbd> and click
           <kbd>Submit</kbd>.</ng-container>
         </p>
 
         <div class="form-group"
-             [ngClass]="{'has-error': editPeerForm.showError('clusterName', formDir)}">
-          <label class="control-label"
+             [ngClass]="{':invalid': editPeerForm.showError('clusterName', formDir)}">
+          <label class="col-form-label"
                  for="clusterName">
             <span i18n>Cluster Name</span>
             <span class="required"></span>
                  name="clusterName"
                  formControlName="clusterName"
                  autofocus>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('clusterName', formDir, 'required')"
                 i18n>This field is required.</span>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('clusterName', formDir, 'invalidClusterName')"
                 i18n>The cluster name is not valid.</span>
         </div>
 
         <div class="form-group"
-             [ngClass]="{'has-error': editPeerForm.showError('clientID', formDir)}">
-          <label class="control-label"
+             [ngClass]="{':invalid': editPeerForm.showError('clientID', formDir)}">
+          <label class="col-form-label"
                  for="clientID">
             <span i18n>CephX ID</span>
             <span class="required"></span>
                  id="clientID"
                  name="clientID"
                  formControlName="clientID">
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('clientID', formDir, 'required')"
                 i18n>This field is required.</span>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('clientID', formDir, 'invalidClientID')"
                 i18n>The CephX ID is not valid.</span>
         </div>
 
         <div class="form-group"
-             [ngClass]="{'has-error': editPeerForm.showError('monAddr', formDir)}">
-          <label class="control-label"
+             [ngClass]="{':invalid': editPeerForm.showError('monAddr', formDir)}">
+          <label class="col-form-label"
                  for="monAddr">
             <span i18n>Monitor Addresses</span>
           </label>
                  id="monAddr"
                  name="monAddr"
                  formControlName="monAddr">
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('monAddr', formDir, 'invalidMonAddr')"
                 i18n>The monitory address is not valid.</span>
         </div>
 
         <div class="form-group"
-             [ngClass]="{'has-error': editPeerForm.showError('key', formDir)}">
-          <label class="control-label"
+             [ngClass]="{':invalid': editPeerForm.showError('key', formDir)}">
+          <label class="col-form-label"
                  for="key">
             <span i18n>CephX Key</span>
           </label>
@@ -92,7 +92,7 @@
                  id="key"
                  name="key"
                  formControlName="key">
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="editPeerForm.showError('key', formDir, 'invalidKey')"
                 i18n>CephX key must be base64 encoded.</span>
         </div>
index a384af938541bab9d1f208405978ceb793282ab0..00bfcf9cbce94028d0d533d3736a82cec809108f 100644 (file)
@@ -1,19 +1,19 @@
 <fieldset #cfgFormGroup [formGroup]="form.get('configuration')">
   <legend i18n>RBD Configuration</legend>
 
-  <div *ngFor="let section of rbdConfigurationService.sections">
-    <h3 class="page-header">
+  <div *ngFor="let section of rbdConfigurationService.sections" class="col-12">
+    <h3 class="cd-header">
       <span
         (click)="toggleSectionVisibility(section.class)"
         class="collapsible">{{ section.heading }} <i [ngClass]="!sectionVisibility[section.class] ? icons.addCircle : icons.minusCircle" aria-hidden="true"></i></span>
     </h3>
     <div class="{{ section.class }}" [hidden]="!sectionVisibility[section.class]">
       <div
-        class="form-group"
+        class="form-group row"
         *ngFor="let option of section.options"
-        [ngClass]="{'has-error': form.showError('configuration.' + option.name, cfgFormGroup)}">
+        [ngClass]="{':invalid': form.showError('configuration.' + option.name, cfgFormGroup)}">
         <label
-          class="control-label col-sm-3"
+          class="col-form-label col-sm-3"
           [for]="option.name">{{ option.displayName }}<cd-helper>{{ option.description }}</cd-helper></label>
 
         <div class="col-sm-9 {{ section.heading }}">
@@ -51,9 +51,9 @@
                   cdIops>
               </ng-container>
             </ng-container>
-            <span class="input-group-btn">
+            <span class="input-group-append">
               <button
-                class="btn btn-default"
+                class="btn btn-light"
                 type="button"
                 data-toggle="button"
                 [ngClass]="{'active': isDisabled(option.name)}"
@@ -67,7 +67,7 @@
           </div>
           <span
             i18n
-            class="help-block"
+            class="form-text text-muted"
             *ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')">The mininum value is 0</span>
         </div>
       </div>
index bab2324ac69f24fec1a4599bd928e054f0e19590..8743cf3580938cbcb28c498584f34b7102caf898 100644 (file)
@@ -5,6 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing';
 import { NgxDatatableModule } from '@swimlane/ngx-datatable';
 import { ChartsModule } from 'ng2-charts';
 import { AlertModule } from 'ngx-bootstrap/alert';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
 
 import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
 import { ErrorPanelComponent } from '../../../shared/components/error-panel/error-panel.component';
@@ -26,6 +27,7 @@ describe('RbdConfigurationListComponent', () => {
       NgxDatatableModule,
       RouterTestingModule,
       AlertModule,
+      BsDropdownModule.forRoot(),
       ChartsModule,
       PipesModule
     ],
index 889cab1f9a4bda293e97751b11310c473b000410..3f4f04d9bf6d34179237b66d43c4f3941f8e4efa 100644 (file)
       <tbody>
         <tr>
           <td i18n
-              class="bold col-sm-1">Name</td>
-          <td class="col-sm-3">{{ selectedItem.name }}</td>
+              class="bold w-25">Name</td>
+          <td class="w-75">{{ selectedItem.name }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Pool</td>
-          <td class="col-sm-3">{{ selectedItem.pool_name }}</td>
+              class="bold">Pool</td>
+          <td>{{ selectedItem.pool_name }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Data Pool</td>
-          <td class="col-sm-3">{{ selectedItem.data_pool | empty }}</td>
+              class="bold">Data Pool</td>
+          <td>{{ selectedItem.data_pool | empty }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Created</td>
-          <td class="col-sm-3">{{ selectedItem.timestamp | cdDate }}</td>
+              class="bold">Created</td>
+          <td>{{ selectedItem.timestamp | cdDate }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Size</td>
-          <td class="col-sm-3">{{ selectedItem.size | dimlessBinary }}</td>
+              class="bold">Size</td>
+          <td>{{ selectedItem.size | dimlessBinary }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Objects</td>
-          <td class="col-sm-3">{{ selectedItem.num_objs | dimless }}</td>
+              class="bold">Objects</td>
+          <td>{{ selectedItem.num_objs | dimless }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Object size</td>
-          <td class="col-sm-3">{{ selectedItem.obj_size | dimlessBinary }}</td>
+              class="bold">Object size</td>
+          <td>{{ selectedItem.obj_size | dimlessBinary }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Features</td>
-          <td class="col-sm-3">
+              class="bold">Features</td>
+          <td>
             <span *ngFor="let feature of selectedItem.features_name">
-              <span class="badge badge-pill badge-primary margin-right-sm">{{ feature }}</span>
+              <span class="badge badge-pill badge-dark mr-2">{{ feature }}</span>
             </span>
           </td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Provisioned</td>
-          <td class="col-sm-3">
+              class="bold">Provisioned</td>
+          <td>
             <span *ngIf="selectedItem.features_name?.indexOf('fast-diff') === -1">
-              <span class="text-muted"
+              <span class="form-text text-muted"
                     [tooltip]="usageNotAvailableTooltipTpl"
                     placement="right"
                     i18n>N/A</span>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Total provisioned</td>
-          <td class="col-sm-3">
+              class="bold">Total provisioned</td>
+          <td>
             <span *ngIf="selectedItem.features_name?.indexOf('fast-diff') === -1">
-              <span class="text-muted"
+              <span class="form-text text-muted"
                     [tooltip]="usageNotAvailableTooltipTpl"
                     placement="right"
                     i18n>N/A</span>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Striping unit</td>
-          <td class="col-sm-3">{{ selectedItem.stripe_unit | dimlessBinary }}</td>
+              class="bold">Striping unit</td>
+          <td>{{ selectedItem.stripe_unit | dimlessBinary }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Striping count</td>
-          <td class="col-sm-3">{{ selectedItem.stripe_count }}</td>
+              class="bold">Striping count</td>
+          <td>{{ selectedItem.stripe_count }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Parent</td>
-          <td class="col-sm-3">
+              class="bold">Parent</td>
+          <td>
             <span *ngIf="selectedItem.parent">{{ selectedItem.parent.pool_name }}
               /{{ selectedItem.parent.image_name }}
               @{{ selectedItem.parent.snap_name }}</span>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Block name prefix</td>
-          <td class="col-sm-3">{{ selectedItem.block_name_prefix }}</td>
+              class="bold">Block name prefix</td>
+          <td>{{ selectedItem.block_name_prefix }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Order</td>
-          <td class="col-sm-3">{{ selectedItem.order }}</td>
+              class="bold">Order</td>
+          <td>{{ selectedItem.order }}</td>
         </tr>
       </tbody>
     </table>
index 2a458b87fa472a488d01b552014420dd9cdd3a49..93b6c4f82d058db53f1de0a97662a1b7ee34e20a 100644 (file)
@@ -1,21 +1,18 @@
 <div class="col-sm-12 col-lg-6">
   <form name="rbdForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="rbdForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+      <div class="card-body">
 
         <!-- Parent -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="rbdForm.getValue('parent')">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="name">{{ action | titlecase }} from</label>
           <div class="col-sm-9">
             <input class="form-control"
@@ -28,9 +25,9 @@
         </div>
 
         <!-- Name -->
-        <div class="form-group"
-             [ngClass]="{'has-error': rbdForm.showError('name', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': rbdForm.showError('name', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="name">
             <ng-container i18n>Name</ng-container>
             <span class="required"></span>
                    name="name"
                    formControlName="name"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="rbdForm.showError('name', formDir, 'required')">
               <ng-container i18n>This field is required.</ng-container>
             </span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="rbdForm.showError('name', formDir, 'pattern')">
               <ng-container i18n>'/' and '@' are not allowed.</ng-container>
             </span>
         </div>
 
         <!-- Pool -->
-        <div class="form-group"
-             [ngClass]="{'has-error': rbdForm.showError('pool', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': rbdForm.showError('pool', formDir)}"
              (change)="onPoolChange($event.target.value)">
-          <label class="control-label col-sm-3"
+          <label class="col-form-label col-sm-3"
                  for="pool">
             Pool
             <span class="required"
                       [value]="pool.pool_name">{{ pool.pool_name }}</option>
             </select>
             <span *ngIf="rbdForm.showError('pool', formDir, 'required')"
-                  class="help-block"
+                  class="form-text text-muted"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Use a dedicated pool -->
-        <div class="form-group">
-          <div class="col-sm-offset-3 col-sm-9">
-            <div class="checkbox checkbox-primary">
+        <div class="form-group row">
+          <div class="offset-sm-3 col-sm-9">
+            <div class="custom-control custom-checkbox">
               <input type="checkbox"
+                     class="custom-control-input"
                      id="useDataPool"
                      name="useDataPool"
                      formControlName="useDataPool"
                      (change)="onUseDataPoolChange()">
-              <label i18n
-                     for="useDataPool">Use a dedicated data pool</label>
+              <label class="custom-control-label"
+                     for="useDataPool"
+                     i18n>Use a dedicated data pool</label>
             </div>
           </div>
         </div>
 
         <!-- Data Pool -->
-        <div class="form-group"
-             [ngClass]="{'has-error': rbdForm.showError('dataPool', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': rbdForm.showError('dataPool', formDir)}"
              *ngIf="rbdForm.getValue('useDataPool')">
-          <label class="control-label col-sm-3"
+          <label class="col-form-label col-sm-3"
                  for="dataPool">
             <ng-container i18n>Data pool</ng-container>
             <span class="required"
               <option *ngFor="let dataPool of dataPools"
                       [value]="dataPool.pool_name">{{ dataPool.pool_name }}</option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="rbdForm.showError('dataPool', formDir, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Size -->
-        <div class="form-group"
-             [ngClass]="{'has-error': rbdForm.showError('size', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': rbdForm.showError('size', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="size">
             <ng-container i18n>Size</ng-container>
             <span class="required"></span>
                    placeholder="e.g., 10GiB"
                    defaultUnit="GiB"
                    cdDimlessBinary>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="rbdForm.showError('size', formDir, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
                   i18n>You have to increase the size.</span>
           </div>
         </div>
 
         <!-- Features -->
-        <div class="form-group"
-             [ngClass]="{'has-error': (formDir.submitted || rbdForm.get('features').dirty) && rbdForm.get('features').invalid}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': (formDir.submitted || rbdForm.get('features').dirty) && rbdForm.get('features').invalid}"
              formGroupName="features">
           <label i18n
-                 class="col-sm-3 control-label"
+                 class="col-sm-3 col-form-label"
                  for="features">Features</label>
           <div class="col-sm-9">
-            <div class="checkbox checkbox-primary"
+            <div class="custom-control custom-checkbox"
                  *ngFor="let feature of featuresList">
               <input type="checkbox"
+                     class="custom-control-input"
                      id="{{ feature.key }}"
                      name="{{ feature.key }}"
                      formControlName="{{ feature.key }}">
-              <label for="{{ feature.key }}">{{ feature.desc }}</label>
+              <label class="custom-control-label"
+                     for="{{ feature.key }}">{{ feature.desc }}</label>
               <cd-helper *ngIf="feature.helperHtml"
                          html="{{ feature.helperHtml }}">
               </cd-helper>
         <!-- Advanced -->
         <div class="row">
           <div class="col-sm-12">
-            <a class="pull-right margin-right-md"
-               (click)="advancedEnabled = true"
+            <a class="float-right margin-right-md"
+               (click)="advancedEnabled = true; false"
                *ngIf="!advancedEnabled"
+               href=""
                i18n>Advanced...</a>
           </div>
         </div>
+
         <div [hidden]="!advancedEnabled">
 
-          <h2 i18n
-              class="page-header">Advanced</h2>
+          <legend class="cd-header"
+                  i18n>Advanced</legend>
 
-          <div class="section">
-            <h3 class="page-header" i18n>Striping</h3>
+          <div class="col-md-12">
+            <h3 class="cd-header"
+                i18n>Striping</h3>
 
             <!-- Object Size -->
-            <div class="form-group"
-                 [ngClass]="{'has-error': rbdForm.showError('obj_size', formDir)}">
+            <div class="form-group row"
+                 [ngClass]="{':invalid': rbdForm.showError('obj_size', formDir)}">
               <label i18n
-                     class="control-label col-sm-3"
+                     class="col-form-label col-sm-3"
                      for="size">Object size</label>
               <div class="col-sm-9">
                 <select id="obj_size"
               </div>
             </div>
 
-            <!-- Stripe Unit -->
-            <div class="form-group"
-                 [ngClass]="{'has-error': rbdForm.showError('stripingUnit', formDir)}">
-              <label class="control-label col-sm-3"
+            <!-- stripingUnit -->
+            <div class="form-group row"
+                 [ngClass]="{':invalid': rbdForm.showError('stripingUnit', formDir)}">
+              <label class="col-form-label col-sm-3"
                      for="stripingUnit">
                 <span i18n>Stripe unit</span>
                 <span class="required"
                       *ngIf="rbdForm.getValue('stripingCount')">
-              </span>
+                </span>
               </label>
               <div class="col-sm-9">
                 <select id="stripingUnit"
                   <option *ngFor="let objectSize of objectSizes"
                           [value]="objectSize">{{ objectSize }}</option>
                 </select>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="rbdForm.showError('stripingUnit', formDir, 'required')"
                       i18n>This field is required because stripe count is defined!</span>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="rbdForm.showError('stripingUnit', formDir, 'invalidStripingUnit')"
                       i18n>Stripe unit is greater than object size.</span>
               </div>
             </div>
 
             <!-- Stripe Count -->
-            <div class="form-group"
-                 [ngClass]="{'has-error': rbdForm.showError('stripingCount', formDir)}">
-              <label class="control-label col-sm-3"
+            <div class="form-group row"
+                 [ngClass]="{':invalid': rbdForm.showError('stripingCount', formDir)}">
+              <label class="col-form-label col-sm-3"
                      for="stripingCount">
                 <span i18n>Stripe count</span>
                 <span class="required"
                       *ngIf="rbdForm.getValue('stripingUnit')">
-              </span>
+                </span>
               </label>
               <div class="col-sm-9">
                 <input id="stripingCount"
                        formControlName="stripingCount"
                        class="form-control"
                        type="number">
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="rbdForm.showError('stripingCount', formDir, 'required')"
                       i18n>This field is required because stripe unit is defined!</span>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="rbdForm.showError('stripingCount', formDir, 'min')"
                       i18n>Stripe count must be greater than 0.</span>
               </div>
             </div>
           </div>
 
-          <div class="section">
-            <cd-rbd-configuration-form [form]="rbdForm"
-                                       [initializeData]="initializeConfigData"
-                                       (changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
-          </div>
-
+          <cd-rbd-configuration-form [form]="rbdForm"
+                                     [initializeData]="initializeConfigData"
+                                     (changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
         </div>
 
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            [form]="formDir"
-            (submitAction)="submit()"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="submit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 6dc1b8912315455c3dd3fd26304e2a03abe958fe..f7bf87847b9d8168482831e9bb9eb66ef4668f00 100644 (file)
@@ -83,7 +83,10 @@ describe('RbdFormComponent', () => {
   describe('test image configuration component', () => {
     it('is visible', () => {
       fixture.detectChanges();
-      expect(queryNativeElement('cd-rbd-configuration-form').parentElement.hidden).toBe(false);
+      expect(
+        fixture.debugElement.query(By.css('cd-rbd-configuration-form')).nativeElement.parentElement
+          .hidden
+      ).toBe(true);
     });
   });
 
index f11da878598aa233e4e5ff7a237cc28cfc278612..d467c8f68b2b3529774473d251ab4ed76f9a7133 100644 (file)
@@ -1,24 +1,23 @@
 <div class="modal-header">
-  <h4 class="modal-title pull-left"
+  <h4 class="modal-title float-left"
       i18n>{ editing, select, true {Rename} other {Create}} RBD Snapshot</h4>
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="modalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
 <form name="snapshotForm"
-      class="form-horizontal"
       #formDir="ngForm"
       [formGroup]="snapshotForm"
       novalidate>
   <div class="modal-body">
 
     <!-- Name -->
-    <div class="form-group"
-         [ngClass]="{'has-error': snapshotForm.showError('snapshotName', formDir)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': snapshotForm.showError('snapshotName', formDir)}">
+      <label class="col-form-label col-sm-3"
              for="snapshotName">
         <ng-container i18n>Name</ng-container>
         <span class="required"></span>
@@ -31,8 +30,8 @@
                name="snapshotName"
                formControlName="snapshotName"
                autofocus>
-        <span class="help-block"
-              *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
+        <span class="form-text text-muted"
+              *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')">
               i18n>This field is required.</span>
       </div>
     </div>
index a1ae6cd0dcbf5ac9a663729d13c593694ea8e6a4..01263e9a42951618249ae6654e5d8933cec29d5d 100644 (file)
 <ng-template #protectTpl
              let-value="value">
   <span *ngIf="value"
-        class="label label-success"
+        class="badge badge-success">
         i18n>PROTECTED</span>
   <span *ngIf="!value"
-        class="label label-info"
+        class="badge badge-info"
         i18n>UNPROTECTED</span>
 </ng-template>
 
index 438d5d1aac118c2237ff54dca532e03d23b4c7ee..ebf9a5266cd542010f539bb2521aa8a544b90501 100644 (file)
                       [tableActions]="tableActions">
     </cd-table-actions>
 
-    <button class="btn btn-sm btn-default btn-label"
+    <button class="btn btn-light"
             type="button"
             (click)="purgeModal()"
             *ngIf="permission.delete">
-      <i [ngClass]="[icons.destroy, icons.width]"
+      <i [ngClass]="[icons.destroy]"
          aria-hidden="true"></i>
       <ng-container i18n>Purge Trash</ng-container>
     </button>
index e0bb6f0f96e58ac00d002f70ddf7f4122ce52ae3..c979172ee5773443688469605478ff3741565639 100644 (file)
@@ -13,7 +13,7 @@
           click <kbd>Move Image</kbd>. Optionally, you can pick an expiration date.</p>
 
         <div class="form-group"
-             [ngClass]="{'has-error': moveForm.showError('expiresAt', formDir)}">
+             [ngClass]="{':invalid': moveForm.showError('expiresAt', formDir)}">
           <label for="expires"
                  i18n>Protection expires at</label>
           <input type="text"
                  [bsConfig]="bsConfig"
                  formControlName="expiresAt"
                  bsDatepicker>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="moveForm.showError('expiresAt', formDir, 'format')"
                 i18n>Wrong date format. Please use "YYYY-MM-DD HH:mm:ss".</span>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="moveForm.showError('expiresAt', formDir, 'expired')"
                 i18n>Protection has already expired. Please pick a future date or leave it empty.</span>
         </div>
index b8b27911cf09795cc69125056f34888ec219e73e..057702bf1c1df7ff347460f0933b0c0117790383 100644 (file)
@@ -15,7 +15,7 @@
         </p>
 
         <div class="form-group">
-          <label class="center-block"
+          <label class="mx-auto"
                  i18n>Pool:</label>
           <input class="form-control"
                  type="text"
index 3f83e64fd8caff21d2d6ce8c48916fef359c86f8..9af2cf6df5c41e3630966b1a89ae4debd7aa0bbf 100644 (file)
@@ -17,7 +17,7 @@
         </p>
 
         <div class="form-group"
-             [ngClass]="{'has-error': restoreForm.showError('name', formDir)}">
+             [ngClass]="{':invalid': restoreForm.showError('name', formDir)}">
           <label for="name"
                  i18n>New Name</label>
           <input type="text"
@@ -27,7 +27,7 @@
                  autocomplete="off"
                  formControlName="name"
                  autofocus>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="restoreForm.showError('name', formDir, 'required')"
                 i18n>This field is required.</span>
         </div>
index 73a385bee6a04c11382dabacd61a4947046a1f37..f8a5217f9746b477831d8d8602c89ce65bae213c 100644 (file)
@@ -35,7 +35,7 @@
   </tab>
   <tab i18n-heading
        heading="Clients: {{ clientCount }}"
-       (select)="clientsSelect=true"
+       (selectTab)="clientsSelect=true"
        (deselect)="clientsSelect=false">
     <cd-cephfs-clients [id]="id"
                        *ngIf="clientsSelect">
index b5776a7e067b5c5f2c98bcad518057a977f96964..df6ff98cce466747b36dd36fe9c3ae8b49ce4edb 100755 (executable)
       <tbody>
         <tr>
           <td i18n
-              class="bold col-sm-1">Name</td>
-          <td class="col-sm-3">{{ selectedItem.name }}</td>
+              class="bold w-25">Name</td>
+          <td class="w-75">{{ selectedItem.name }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Description</td>
-          <td class="col-sm-3">{{ selectedItem.desc }}</td>
+              class="bold">Description</td>
+          <td>{{ selectedItem.desc }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Long description</td>
-          <td class="col-sm-3">{{ selectedItem.long_desc }}</td>
+              class="bold">Long description</td>
+          <td>{{ selectedItem.long_desc }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Current values</td>
-          <td class="col-sm-3">
+              class="bold">Current values</td>
+          <td>
             <span *ngFor="let conf of selectedItem.value; last as isLast">
-              {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br/>
+              {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br />
             </span>
           </td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Default</td>
-          <td class="col-sm-3">{{ selectedItem.default }}</td>
+              class="bold">Default</td>
+          <td>{{ selectedItem.default }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Daemon default</td>
-          <td class="col-sm-3">{{ selectedItem.daemon_default }}</td>
+              class="bold">Daemon default</td>
+          <td>{{ selectedItem.daemon_default }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Type</td>
-          <td class="col-sm-3">{{ selectedItem.type }}</td>
+              class="bold">Type</td>
+          <td>{{ selectedItem.type }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Min</td>
-          <td class="col-sm-3">{{ selectedItem.min }}</td>
+              class="bold">Min</td>
+          <td>{{ selectedItem.min }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Max</td>
-          <td class="col-sm-3">{{ selectedItem.max }}</td>
+              class="bold">Max</td>
+          <td>{{ selectedItem.max }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Flags</td>
-          <td class="col-sm-3">
+              class="bold">Flags</td>
+          <td>
             <span *ngFor="let flag of selectedItem.flags">
               <span title="{{ flags[flag] }}">
-                <span class="badge badge-pill badge-primary margin-right-sm">{{ flag | uppercase }}</span>
+                <span class="badge badge-pill badge-dark mr-2">{{ flag | uppercase }}</span>
               </span>
             </span>
           </td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Services</td>
-          <td class="col-sm-3">
+              class="bold">Services</td>
+          <td>
             <span *ngFor="let service of selectedItem.services">
-              <span class="badge badge-pill badge-primary margin-right-sm">{{ service }}</span>
+              <span class="badge badge-pill badge-dark mr-2">{{ service }}</span>
             </span>
           </td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Source</td>
-          <td class="col-sm-3">{{ selectedItem.source }}</td>
+              class="bold">Source</td>
+          <td>{{ selectedItem.source }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Level</td>
-          <td class="col-sm-3">{{ selectedItem.level }}</td>
+              class="bold">Level</td>
+          <td>{{ selectedItem.level }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Can be updated at runtime (editable)</td>
-          <td class="col-sm-3">{{ selectedItem.can_update_at_runtime | booleanText }}</td>
+              class="bold">Can be updated at runtime (editable)</td>
+          <td>{{ selectedItem.can_update_at_runtime | booleanText }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Tags</td>
-          <td class="col-sm-3">{{ selectedItem.tags }}</td>
+              class="bold">Tags</td>
+          <td>{{ selectedItem.tags }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">Enum values</td>
-          <td class="col-sm-3">{{ selectedItem.enum_values }}</td>
+              class="bold">Enum values</td>
+          <td>{{ selectedItem.enum_values }}</td>
         </tr>
         <tr>
           <td i18n
-              class="bold col-sm-1">See also</td>
-          <td class="col-sm-3">{{ selectedItem.see_also }}</td>
+              class="bold">See also</td>
+          <td>{{ selectedItem.see_also }}</td>
         </tr>
       </tbody>
     </table>
index a32fb35151e1b609775704ff80bd21e7a33328ee..772a4e230de7b918b23d93126117156af2b3ae5d 100644 (file)
@@ -1,21 +1,18 @@
-<div class="col-sm-12 col-lg-6">
+<div class="col-sm-12 col-md-12 col-lg-6">
   <form name="configForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="configForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          <ng-container i18n>Edit</ng-container> {{ configForm.getValue('name') }}
-        </h3>
+    <div class="card">
+      <div class="card-header">
+        <ng-container i18>Edit</ng-container> {{ configForm.getValue('name') }}
       </div>
-      <div class="panel-body">
 
+      <div class="card-body">
         <!-- Name -->
-        <div class="form-group">
+        <div class="form-group row">
           <label i18n
-                 class="control-label col-sm-3">Name</label>
+                 class="col-form-label col-sm-3">Name</label>
           <div class="col-sm-9">
             <input class="form-control"
                    type="text"
         </div>
 
         <!-- Description -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="configForm.getValue('desc')">
           <label i18n
-                 class="control-label col-sm-3">Description</label>
+                 class="col-form-label col-sm-3">Description</label>
           <div class="col-sm-9">
             <textarea class="form-control resize-vertical"
                       id="desc"
         </div>
 
         <!-- Long description -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="configForm.getValue('long_desc')">
           <label i18n
-                 class="control-label col-sm-3">Long description</label>
+                 class="col-form-label col-sm-3">Long description</label>
           <div class="col-sm-9">
             <textarea class="form-control resize-vertical"
                       id="long_desc"
         </div>
 
         <!-- Default -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="configForm.getValue('default') !== ''">
           <label i18n
-                 class="control-label col-sm-3">Default</label>
+                 class="col-form-label col-sm-3">Default</label>
           <div class="col-sm-9">
             <input class="form-control"
                    type="text"
         </div>
 
         <!-- Daemon default -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="configForm.getValue('daemon_default') !== ''">
           <label i18n
-                 class="control-label col-sm-3">Daemon default</label>
+                 class="col-form-label col-sm-3">Daemon default</label>
           <div class="col-sm-9">
             <input class="form-control"
                    type="text"
         </div>
 
         <!-- Services -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="configForm.getValue('services').length > 0">
           <label i18n
-                 class="control-label col-sm-3">Services</label>
+                 class="col-form-label col-sm-3">Services</label>
           <div class="col-sm-9">
             <span *ngFor="let service of configForm.getValue('services')"
                   class="form-component-badge">
-              <span class="badge badge-pill badge-primary">{{ service }}</span>
+              <span class="badge badge-pill badge-dark">{{ service }}</span>
             </span>
           </div>
         </div>
 
         <!-- Values -->
-        <div class="col-sm-12"
-             formGroupName="values">
+        <div formGroupName="values">
           <h2 i18n
-              class="page-header">Values</h2>
-          <div class="row"
-               *ngFor="let section of availSections">
-            <div class="form-group"
+              class="cd-header">Values</h2>
+          <ng-container *ngFor="let section of availSections">
+            <div class="form-group row"
                  *ngIf="type === 'bool'">
-              <div class="col-sm-offset-3 col-sm-9">
-                <div class="checkbox checkbox-primary">
-                  <input [id]="section"
+              <div class="offset-sm-3 col-sm-9">
+                <div class="form-check abc-checkbox abc-checkbox-primary">
+                  <input class="form-check-input"
+                         [id]="section"
                          type="checkbox"
                          [formControlName]="section">
-                  <label [for]="section">{{ section }}
+                  <label class="form-check-label"
+                         [for]="section">{{ section }}
                   </label>
                 </div>
               </div>
             </div>
-            <div class="form-group"
-                 [ngClass]="{'has-error': configForm.showError(section, formDir)}"
+
+            <div class="form-group row"
+                 [ngClass]="{':invalid': configForm.showError(section, formDir)}"
                  *ngIf="type !== 'bool'">
-              <label class="control-label col-sm-3"
+              <label class="col-form-label col-sm-3"
                      [for]="section">{{ section }}
               </label>
               <div class="col-sm-9">
                        [placeholder]="humanReadableType"
                        [formControlName]="section"
                        [step]="getStep(type, this.configForm.getValue(section))">
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="configForm.showError(section, formDir, 'pattern')">
                   {{ patternHelpText }}
                 </span>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="configForm.showError(section, formDir, 'invalidUuid')">
                   {{ patternHelpText }}
                 </span>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="configForm.showError(section, formDir, 'max')"
                       i18n>The entered value is too high! It must not be greater than {{ maxValue }}.</span>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="configForm.showError(section, formDir, 'min')"
                       i18n>The entered value is too low! It must not be lower than {{ minValue }}.</span>
               </div>
             </div>
-          </div>
+          </ng-container>
         </div>
       </div>
       <!-- Footer -->
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
           <cd-submit-button [form]="formDir"
-                            type="button"
                             (submitAction)="submit()">
             <span i18n>Save</span>
           </cd-submit-button>
index 6c0f7d5a7f2d7f428d98723bb6e592110697bfbe..5c974d97e4317b0a910f3f288df0343f59188f2c 100644 (file)
@@ -8,32 +8,40 @@
                     [selection]="selection"
                     [tableActions]="tableActions">
   </cd-table-actions>
-  <div class="table-filters">
+  <div class="table-filters form-inline">
     <div class="form-group filter"
          *ngFor="let filter of filters">
       <label>{{ filter.label }}: </label>
-      <select class="form-control input-sm"
+      <select class="form-control"
               [(ngModel)]="filter.value"
               (ngModelChange)="updateFilter()">
         <option *ngFor="let opt of filter.options">{{ opt }}</option>
       </select>
     </div>
-    <a [ngClass]="[icons.stack]"
-       title="Reset filters"
-       (click)="resetFilter()">
-      <i [ngClass]="[icons.filter, icons.stack2x]"></i>
-      <i [ngClass]="[icons.destroy, icons.stack1x]" style="margin-left: 8px; margin-top: 5px;"></i>
-    </a>
+
+    <div class="widget-toolbar tc_refreshBtn">
+      <button type="button"
+              title="Reset filters"
+              class="btn btn-light"
+              (click)="resetFilter()">
+        <span [ngClass]="[icons.stack]">
+          <i [ngClass]="[icons.filter, icons.stack2x]"></i>
+          <i [ngClass]="[icons.destroy, icons.stack1x]"
+             style="margin-left: 8px; margin-top: 5px;"></i>
+        </span>
+      </button>
+    </div>
   </div>
   <cd-configuration-details cdTableDetail
                             [selection]="selection">
   </cd-configuration-details>
 </cd-table>
 
-<ng-template #confValTpl let-value="value">
+<ng-template #confValTpl
+             let-value="value">
   <span *ngIf="value">
     <span *ngFor="let conf of value; last as isLast">
-      {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br/>
+      {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br />
     </span>
   </span>
 </ng-template>
index 19b14168c012766523b416d46d9fdcbac0e32ff4..8fcf2fe99e09f77d9fba171a4bfb470dec6ee371 100644 (file)
@@ -2,6 +2,10 @@
   padding-right: 8px;
 }
 
+.fa-stack {
+  font-size: 0.79rem;
+}
+
 ::ng-deep datatable-body-cell.wrap {
   word-break: break-all;
 }
index 5642543073906efd17836b710cb44672e49b0b5f..260faecdd11a83398926ac380b0af7c6c8b61f1b 100644 (file)
@@ -1,29 +1,31 @@
 <div class="row">
   <div class="col-sm-12 col-lg-12">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          <span i18n>CRUSH map viewer</span>
-        </h3>
-      </div>
-      <div class="panel-body">
-        <div class="col-sm-6 col-lg-6">
-          <tree [tree]="tree"
-                [settings]="{rootIsVisible: false}"
-                (nodeSelected)="onNodeSelected($event)">
-            <ng-template let-node>
-              <span class="label"
-                    [ngClass]="{'label-success': ['in', 'up'].includes(node.status), 'label-danger': ['down', 'out'].includes(node.status)}">{{ node.status }}</span>
-              <span>&nbsp;</span>
-              <span class="node-name" [innerHTML]="node.value"></span>
-            </ng-template>
-          </tree>
-        </div>
-        <div class="col-sm-6 col-lg-6 metadata" *ngIf="metadata">
-          <legend>{{ metadataTitle }}</legend>
-          <cd-table-key-value [data]="metadata"></cd-table-key-value>
+    <div class="card">
+      <div class="card-header"
+           i18n>CRUSH map viewer</div>
+      <div class="card-body">
+        <div class="row">
+          <div class="col-sm-6 col-lg-6">
+            <tree [tree]="tree"
+                  [settings]="{rootIsVisible: false}"
+                  (nodeSelected)="onNodeSelected($event)">
+              <ng-template let-node>
+                <span class="badge"
+                      [ngClass]="{'badge-success': ['in', 'up'].includes(node.status), 'badge-danger': ['down', 'out'].includes(node.status)}">
+                  {{ node.status }}
+                </span>
+                <span>&nbsp;</span>
+                <span class="node-name"
+                      [innerHTML]="node.value"></span>
+              </ng-template>
+            </tree>
+          </div>
+          <div class="col-sm-6 col-lg-6 metadata"
+               *ngIf="metadata">
+            <legend>{{ metadataTitle }}</legend>
+            <cd-table-key-value [data]="metadata"></cd-table-key-value>
+          </div>
         </div>
       </div>
     </div>
   </div>
-</div>
index 2e6e458a202f5de025238d36b6f52ab0035eff42..3f6cf763d8c63e35d1697e58f7eef6f5c2663c17 100644 (file)
@@ -33,7 +33,7 @@ describe('CrushmapComponent', () => {
 
   it('should display right title', () => {
     fixture.detectChanges();
-    const span = debugElement.nativeElement.querySelector('span');
+    const span = debugElement.nativeElement.querySelector('.card-header');
     expect(span.textContent).toBe('CRUSH map viewer');
   });
 
index 1a12843a9dac5bd1b6d83bcc50ca52f68664a736..616e9d6369aa86042a304d17ac64c3b1cf470021 100644 (file)
@@ -1,72 +1,80 @@
 <div *ngIf="contentData">
-<ng-container *ngTemplateOutlet="logFiltersTpl"></ng-container>
-<tabset>
-  <tab i18n-heading
-       heading="Cluster Logs">
-  <div class="well">
-    <div *ngIf="clog">
-      <p *ngFor="let line of clog">
-        <span class="timestamp">{{ line.stamp | cdDate }}</span>
-        <span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
-        <span class="message">{{ line.message }}</span>
-      </p>
-    </div>
-    <div *ngIf="contentData.clog.length === 0">
-      <p i18n>No entries found</p>
-    </div>
-  </div>
-  </tab>
+  <ng-container *ngTemplateOutlet="logFiltersTpl"></ng-container>
 
-  <tab i18n-heading
-       heading="Audit Logs">
-  <div class="well">
-    <div *ngIf="audit_log">
-      <p *ngFor="let line of audit_log">
-        <span class="timestamp">{{ line.stamp | cdDate }}</span>
-        <span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
-        <span class="message">{{ line.message }}</span>
-      </p>
-    </div>
-    <div *ngIf="contentData.audit_log.length === 0">
-      <p i18n>No entries found</p>
-    </div>
-  </div>
-  </tab>
-</tabset>
+  <tabset>
+    <tab i18n-heading
+         heading="Cluster Logs">
+      <div class="card bg-light mb-3"
+           *ngIf="clog">
+        <div class="card-body">
+          <p *ngFor="let line of clog">
+            <span class="timestamp">{{ line.stamp | cdDate }}</span>
+            <span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
+            <span class="message">{{ line.message }}</span>
+          </p>
+
+          <span *ngIf="contentData.clog.length === 0"
+                i18n>No entries found</span>
+        </div>
+      </div>
+    </tab>
+
+    <tab i18n-heading
+         heading="Audit Logs">
+      <div class="card bg-light mb-3"
+           *ngIf="audit_log">
+        <div class="card-body">
+          <p *ngFor="let line of audit_log">
+            <span class="timestamp">{{ line.stamp | cdDate }}</span>
+            <span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
+            <span class="message">{{ line.message }}</span>
+          </p>
+
+          <span *ngIf="contentData.audit_log.length === 0"
+                i18n>No entries found</span>
+        </div>
+      </div>
+    </tab>
+  </tabset>
 </div>
 
 <ng-template #logFiltersTpl>
-  <div class="row log-filters">
-    <div class="col-xs-4 col-md-2 cd-col-1 filter-box">
+  <div class="form-inline">
+    <div class="form-group">
       <label i18n>Priority:</label>
       <select class="form-control"
               [(ngModel)]="priority"
               (ngModelChange)="filterLogs()">
-        <option class="form-control"
-                *ngFor="let prio of prioritys"
+        <option *ngFor="let prio of prioritys"
                 [value]="prio.value">{{ prio.name }}</option>
       </select>
     </div>
-    <div class="col-xs-4 col-md-3 cd-col-3 filter-box">
+
+    <div class="form-group">
       <label i18n>Keyword:</label>
       <div class="input-group">
-        <span class="input-group-addon">
-          <i [ngClass]="[icons.search]"></i>
-        </span>
+        <div class="input-group-prepend">
+          <span class="input-group-text">
+            <i [ngClass]="[icons.search]"></i>
+          </span>
+        </div>
+
         <input class="form-control"
                type="text"
                [(ngModel)]="search"
                (keyup)="filterLogs()">
-        <span class="input-group-btn">
+
+        <div class="input-group-append">
           <button type="button"
-                  class="btn btn-default clear-input tc_clearInputBtn"
+                  class="btn btn-light"
                   (click)="clearSearchKey()">
             <i class="icon-prepend {{ icons.destroy }}"></i>
           </button>
-        </span>
+        </div>
       </div>
     </div>
-    <div class="col-xs-4 col-md-3 cd-col-2 filter-box">
+
+    <div class="form-group">
       <label i18n>Date:</label>
       <div class="input-group">
         <input type="text"
                bsDatepicker
                [(ngModel)]="selectedDate"
                (ngModelChange)="filterLogs()">
-        <span class="input-group-btn">
+        <span class="input-group-append">
           <button type="button"
-                  class="btn btn-default clear-input tc_clearInputBtn"
+                  class="btn btn-light"
                   (click)="clearDate()">
             <i class="icon-prepend {{ icons.destroy }}"></i>
           </button>
         </span>
       </div>
     </div>
-    <div class="clearfix visible-xs-block"></div>
-    <div class="col-xs-8 col-md-4 cd-col-4 filter-box time-box">
+
+    <div class="form-group">
       <label i18n>Time range:</label>
-      <timepicker [showMeridian]="false"
-                  [showSpinners]="showSpinners"
-                  [minuteStep]="1"
-                  [(ngModel)]="startTime"
-                  (ngModelChange)="filterLogs()">
-      </timepicker>
-      <span>&nbsp;&mdash;&nbsp;</span>
-      <timepicker [showMeridian]="false"
-                  [showSpinners]="showSpinners"
-                  [minuteStep]="1"
-                  [(ngModel)]="endTime"
-                  (ngModelChange)="filterLogs()">
-      </timepicker>
+      <div class="d-inline-flex">
+        <timepicker [showMeridian]="false"
+                    [showSpinners]="false"
+                    [minuteStep]="1"
+                    [(ngModel)]="startTime"
+                    (ngModelChange)="filterLogs()">
+        </timepicker>
+        <span class="middle">&nbsp;&mdash;&nbsp;</span>
+        <timepicker [showMeridian]="false"
+                    [showSpinners]="false"
+                    [minuteStep]="1"
+                    [(ngModel)]="endTime"
+                    (ngModelChange)="filterLogs()">
+        </timepicker>
+      </div>
     </div>
   </div>
 </ng-template>
index 8c91d4ad8a98c247ca2b90b3341b9ec955fcfebc..d8b1b8de4982087dbee93adc906a86ec9116b314 100644 (file)
@@ -1,11 +1,10 @@
-@import '../../../../defaults';
+@import 'styles';
 
 p {
   font-family: monospace;
-  color: black;
 }
 
-.well {
+.card {
   div p {
     display: flex;
 
@@ -41,103 +40,22 @@ p {
 }
 
 ::ng-deep timepicker table tbody tr td {
-  .bs-timepicker-field {
-    width: 3.5rem;
+  input.bs-timepicker-field {
+    width: 3.5rem !important;
     font-size: 1rem;
     padding: 4px 6px;
   }
-  .btn {
-    font-size: 1rem;
-  }
 }
 
-.log-filters {
-  margin-bottom: 5px;
-  padding: 0 30px;
-  * {
-    box-sizing: border-box;
-  }
-
-  .filter-box {
-    margin: 0;
-    padding: 0 15px 5px 0;
-    display: -webkit-flex;
-    display: flex;
-    justify-content: flex-start;
-    align-items: center;
-    label {
-      padding-top: 5px;
-      padding-right: 5px;
-    }
-  }
-
-  @media (max-width: 991px) {
-    .time-box {
-      margin-top: 20px;
-    }
-  }
-
-  @media (min-width: 1200px) {
-    .cd-col-4 {
-      width: 28vw;
-    }
-
-    .cd-col-3 {
-      width: 20vw;
-    }
-
-    .cd-col-2 {
-      width: 16vw;
-    }
-    .cd-col-1 {
-      width: 14vw;
-    }
-  }
-
-  @media (min-width: 1400px) {
-    .cd-col-4 {
-      width: 24vw;
-    }
-
-    .cd-col-3 {
-      width: 18vw;
-    }
-
-    .cd-col-2 {
-      width: 14vw;
-    }
-    .cd-col-1 {
-      width: 12vw;
-    }
-  }
-
-  @media (min-width: 1600px) {
-    .cd-col-4 {
-      width: 22vw;
-    }
-
-    .cd-col-3 {
-      width: 16vw;
-    }
-
-    .cd-col-2 {
-      width: 12vw;
-    }
-    .cd-col-1 {
-      width: 10vw;
-    }
-  }
+label {
+  @extend .mr-2;
+}
 
-  @media (min-width: 1800px) {
-    .cd-col-3 {
-      width: 14vw;
-    }
+.form-group {
+  @extend .mr-3;
+  @extend .mb-3;
+}
 
-    .cd-col-2 {
-      width: 11vw;
-    }
-    .cd-col-1 {
-      width: 9vw;
-    }
-  }
+.middle {
+  padding-top: 7px;
 }
index 1854e37f243b78cc2a870ba77a9b3b89535ef56d..788ca1fb247fae3a5d5cca5ee3f362524cbfd5cc 100644 (file)
@@ -6,21 +6,19 @@
 <div class="col-sm-12 col-lg-6"
      *ngIf="!loading && !error">
   <form name="mgrModuleForm"
-        class="form-horizontal"
         #frm="ngForm"
         [formGroup]="mgrModuleForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title" i18n>Edit Manager module</h3>
-      </div>
-      <div class="panel-body">
-        <div class="form-group"
-             [ngClass]="{'has-error': mgrModuleForm.showError(moduleOption.value.name, frm)}"
+    <div class="card">
+      <div class="card-header"
+           i18n>Edit Manager module</div>
+      <div class="card-body">
+        <div class="form-group row"
+             [ngClass]="{':invalid': mgrModuleForm.showError(moduleOption.value.name, frm)}"
              *ngFor="let moduleOption of moduleOptions | keyvalue">
 
           <!-- Field label -->
-          <label class="control-label col-sm-3"
+          <label class="col-form-label col-sm-3"
                  for="{{ moduleOption.value.name }}">
             {{ moduleOption.value.name }}
             <cd-helper *ngIf="moduleOption.value.long_desc || moduleOption.value.desc">
                 {{ value }}
               </option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'invalidUuid')"
                   i18n>The entered value is not a valid UUID, e.g.: 67dcac9f-2c03-4d6c-b7bd-1210b3a259a8</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
                   i18n>The entered value needs to be a valid IP address.</span>
           </div>
                    formControlName="{{ moduleOption.value.name }}"
                    min="{{ moduleOption.value.min }}"
                    max="{{ moduleOption.value.max }}">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'max')"
                   i18n>The entered value is too high! It must be lower or equal to {{ moduleOption.value.max }}.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'min')"
                   i18n>The entered value is too low! It must be greater or equal to {{ moduleOption.value.min }}.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
                   i18n>The entered value needs to be a number.</span>
           </div>
                    class="form-control"
                    type="number"
                    formControlName="{{ moduleOption.value.name }}">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
                   i18n>The entered value needs to be a number or decimal.</span>
           </div>
 
         </div>
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button type="button"
-                            (submitAction)="onSubmit()"
+          <cd-submit-button (submitAction)="onSubmit()"
                             [form]="mgrModuleForm">
             <ng-container i18n>Update</ng-container>
           </cd-submit-button>
           <button type="button"
-                  class="btn btn-sm btn-default"
+                  class="btn btn-light"
                   routerLink="/mgr-modules"
                   i18n>Back</button>
         </div>
index af863b635376031f71d63fac499f50da110cc120..531fa3a46da2b725e82ae4baf7c18a2c931889cc 100644 (file)
@@ -1,7 +1,7 @@
 <div class="row">
-  <div class="col-md-4">
+  <div class="col-lg-4">
     <fieldset>
-      <legend i18n>Status</legend>
+      <legend class="cd-header" i18n>Status</legend>
       <table class="table table-striped"
              *ngIf="mon_status">
         <tr>
     </fieldset>
   </div>
 
-  <div class="col-md-8">
+  <div class="col-lg-8">
     <legend i18n
-            class="in-quorum">In Quorum</legend>
+            class="in-quorum cd-header">In Quorum</legend>
     <cd-table [data]="inQuorum.data"
               [columns]="inQuorum.columns">
     </cd-table>
 
     <legend i18n
-            class="in-quorum">Not In Quorum</legend>
+            class="in-quorum cd-header">Not In Quorum</legend>
     <cd-table [data]="notInQuorum.data"
               (fetchData)="refresh()"
               [columns]="notInQuorum.columns">
index 13ed7dfea77962f5059db38958d0c5db97bd8e97..659aae6a89e6754cc0c00673642836c6bfda09cd 100644 (file)
@@ -8,19 +8,21 @@
           [formGroup]="osdFlagsForm"
           novalidate>
       <div class="modal-body osd-modal">
-        <div class="checkbox checkbox-primary"
+        <div class="form-check abc-checkbox  abc-checkbox-primary"
              *ngFor="let flag of flags; let last = last">
-          <input type="checkbox"
+          <input class="form-check-input"
+                 type="checkbox"
                  [checked]="flag.value"
                  (change)="flag.value = !flag.value"
                  [name]="flag.code"
                  [id]="flag.code"
                  [disabled]="flag.disabled">
-          <label [for]="flag.code"
+          <label class="form-check-label"
+                 [for]="flag.code"
                  ng-class="['tc_' + key]">
             <strong>{{ flag.name }}</strong>
             <br>
-            <span class="text-muted">{{ flag.description }}</span>
+            <span class="form-text text-muted">{{ flag.description }}</span>
           </label>
           <hr class="oa-hr-small"
               *ngIf="!last">
index 34a099cbcd4b075106a4a19fe864a72dc13089d6..19f79533f101188f4e9fda41309fd15bfdeacecd 100644 (file)
@@ -17,7 +17,7 @@
         <cd-table-actions [permission]="{read: true}"
                           [selection]="selection"
                           dropDownOnly="Cluster-wide configuration"
-                          btnColor="default"
+                          btnColor="light"
                           class="btn-group"
                           id="cluster-wide-actions"
                           [tableActions]="clusterWideActions">
@@ -32,8 +32,8 @@
     <ng-template #statusColor
                  let-value="value">
       <span *ngFor="let state of value; last as last">
-        <span class="label"
-              [ngClass]="{'label-success': ['in', 'up'].includes(state), 'label-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
+        <span class="badge"
+              [ngClass]="{'badge-success': ['in', 'up'].includes(state), 'badge-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
         <span *ngIf="!last">&nbsp;</span>
       </span>
     </ng-template>
@@ -58,7 +58,7 @@
 <ng-template #markOsdConfirmationTpl
              let-markActionDescription="markActionDescription">
   <ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be marked
-  <strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
+<strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
 </ng-template>
 
 <ng-template #criticalConfirmationTpl
@@ -69,5 +69,5 @@
     <cd-warning-panel i18n>The OSD is not safe to destroy!</cd-warning-panel>
   </div>
   <ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be
-  <strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
+<strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
 </ng-template>
index b1113d7c06adc5cc3aba805a8130cdd6c18d6548..fdd50c66e6154316220e18ac3f6f54241a57a41f 100644 (file)
@@ -263,7 +263,7 @@ describe('OsdListComponent', () => {
       const tableActionElement = fixture.debugElement.query(By.directive(TableActionsComponent));
       const toClassName = TestBed.get(TableActionsComponent).toClassName;
       const getActionClasses = (action: CdTableAction) =>
-        tableActionElement.query(By.css('.' + toClassName(action.name))).classes;
+        tableActionElement.query(By.css(`.${toClassName(action.name)} .dropdown-item`)).classes;
 
       component.tableActions.forEach((action) => {
         expect(getActionClasses(action).disabled).toBe(true);
index 9f447db83415bd8cafcb6dae21d419f8847a8d9a..054a9c5c0cc29bb5656aa02e99b57d25b1548fc6 100644 (file)
@@ -3,8 +3,7 @@
                 class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
 
   <ng-container class="modal-content">
-    <form class="form-horizontal"
-          #formDir="ngForm"
+    <form #formDir="ngForm"
           [formGroup]="osdPgScrubForm"
           novalidate>
       <div class="modal-body osd-modal">
@@ -37,9 +36,8 @@
         <div class="button-group text-right">
           <cd-submit-button *ngIf="permissions.configOpt.update"
                             (submitAction)="submitAction()"
-                            [form]="osdPgScrubForm"
                             i18n="form action button|Example: Create Pool@@formActionButton"
-                            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+                            [form]="osdPgScrubForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button [back]="bsModalRef.hide">
           </cd-back-button>
         </div>
index c06d1b99684fab48a5c3e1da20ef13640b0933af..cdd52bb3a1e4d59e6ae14aeb2acd05000e825c93 100755 (executable)
@@ -3,15 +3,14 @@
                 i18n>OSD Recovery Priority</ng-container>
 
   <ng-container class="modal-content">
-    <form class="form-horizontal"
-          #formDir="ngForm"
+    <form #formDir="ngForm"
           [formGroup]="osdRecvSpeedForm"
           novalidate>
       <div class="modal-body">
         <!-- Priority -->
-        <div class="form-group"
-             [ngClass]="{'has-error': osdRecvSpeedForm.showError('priority', formDir)}">
-          <label class="control-label col-sm-6"
+        <div class="form-group row"
+             [ngClass]="{':invalid': osdRecvSpeedForm.showError('priority', formDir)}">
+          <label class="col-form-label col-sm-6"
                  for="priority">
             <ng-container i18n>Priority</ng-container>
             <span class="required"></span>
                 {{ priority.text }}
               </option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="osdRecvSpeedForm.showError('priority', formDir, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Customize priority -->
-        <div class="form-group">
-          <div class="col-sm-offset-6 col-sm-6">
-            <div class="checkbox checkbox-primary">
+        <div class="form-group row">
+          <div class="offset-sm-6 col-sm-6">
+            <div class="form-check abc-checkbox abc-checkbox-primary">
               <input formControlName="customizePriority"
+                     class="form-check-input"
                      id="customizePriority"
+                     name="customizePriority"
                      type="checkbox"
                      (change)="onCustomizePriorityChange()">
-              <label i18n
-                     for="customizePriority">Customize priority values</label>
+              <label class="form-check-label"
+                     for="customizePriority"
+                     i18n>Customize priority values</label>
             </div>
           </div>
         </div>
 
         <!-- Priority values -->
-        <div class="form-group" *ngFor="let attr of priorityAttrs | keyvalue"
-             [ngClass]="{'has-error': osdRecvSpeedForm.getValue('customizePriority') &&
+        <div class="form-group row"
+             *ngFor="let attr of priorityAttrs | keyvalue"
+             [ngClass]="{':invalid': osdRecvSpeedForm.getValue('customizePriority') &&
              osdRecvSpeedForm.showError(attr.key, formDir)}">
-          <label class="control-label col-sm-6"
+          <label class="col-form-label col-sm-6"
                  [for]="attr.key">{{ attr.value.text }}
             <cd-helper *ngIf="attr.value.desc">{{ attr.value.desc }}</cd-helper>
-            <span class="required" *ngIf="osdRecvSpeedForm.getValue('customizePriority')"></span>
+            <span class="required"
+                  *ngIf="osdRecvSpeedForm.getValue('customizePriority')"></span>
           </label>
           <div class="col-sm-6">
             <input class="form-control"
                    [id]="attr.key"
                    [formControlName]="attr.key"
                    [readonly]="!osdRecvSpeedForm.getValue('customizePriority')">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
                   osdRecvSpeedForm.showError(attr.key, formDir, 'required')"
                   i18n>This field is required!</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
                   osdRecvSpeedForm.showError(attr.key, formDir, 'pattern')"
                   i18n>{{ attr.value.patternHelpText }}</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
                   osdRecvSpeedForm.showError(attr.key, formDir, 'max')"
                   i18n>The entered value is too high! It must not be greater than {{ attr.value.maxValue }}.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
                   osdRecvSpeedForm.showError(attr.key, formDir, 'min')"
                   i18n>The entered value is too low! It must not be lower than {{ attr.value.minValue }}.</span>
index 7d9e28eb428b6a9be1be973dec3a72b8f0c620c9..a282584b7ed6c972ac30ee3899ff2fac0fb6befb 100644 (file)
@@ -3,16 +3,15 @@
                 i18n>Reweight OSD</ng-container>
 
   <ng-container class="modal-content">
-    <form class="form-horizontal"
-          [formGroup]="reweightForm">
-      <div class="modal-body" [ngClass]="{'has-error': weight.errors}">
+    <form [formGroup]="reweightForm">
+      <div class="modal-body" [ngClass]="{':invalid': weight.errors}">
         <div class="row">
-          <label for="weight" class="col-sm-2 control-label">Weight</label>
+          <label for="weight" class="col-sm-2 col-form-label">Weight</label>
           <div class="col-sm-10">
             <input id="weight" class="form-control" type="number"
                    step="0.1" formControlName="weight" min="0" max="1"
                    [value]="currentWeight">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="weight.errors">
               <span *ngIf="weight.errors?.required"
                     i18n>This field is required.</span>
index ba05c97515bd50bd7fa677353c4ec10906bf3004..1000f5fb34e3522b72b15618fb448395ebc0c24b 100644 (file)
@@ -4,7 +4,6 @@
 
   <ng-container class="modal-content">
     <form name="scrubForm"
-          class="form-horizontal"
           #formDir="ngForm"
           [formGroup]="scrubForm"
           novalidate>
index 927f3cff4d4be05687fb80af762bc136a788cced..e043c7244c8d733bf2d77f1a7b057ea756de634d 100644 (file)
@@ -28,9 +28,9 @@ export class AlertListComponent implements OnInit {
   selection = new CdTableSelection();
   icons = Icons;
   customCss = {
-    'label label-danger': 'active',
-    'label label-warning': 'unprocessed',
-    'label label-info': 'suppressed'
+    'badge badge-danger': 'active',
+    'badge badge-warning': 'unprocessed',
+    'badge badge-info': 'suppressed'
   };
 
   constructor(
index b2f530a7e8622f09180f0ef4159a929b5b7ef473..b73a09ff4de47084ac11517c7b9af95287236bbb 100644 (file)
@@ -2,12 +2,12 @@
   <tab heading="Alerts"
        i18n-heading
        [active]="url === '/alerts'"
-       (select)="navigateTo('/alerts')">
+       (selectTab)="navigateTo('/alerts')">
   </tab>
   <tab heading="Silences"
        i18n-heading
        [active]="url === '/silence'"
-       (select)="navigateTo('/silence')">
+       (selectTab)="navigateTo('/silence')">
   </tab>
 </tabset>
 
index 65cc58d235dd585a10a881fd47048d951230d449..47760b549e439bcc5f32a8fa1625c8b54bd21ea0 100644 (file)
@@ -15,7 +15,7 @@ describe('PrometheusTabsComponent', () => {
   let router: Router;
 
   const selectTab = (index) => {
-    fixture.debugElement.queryAll(By.css('tab'))[index].triggerEventHandler('select', null);
+    fixture.debugElement.queryAll(By.css('tab'))[index].triggerEventHandler('selectTab', null);
   };
 
   configureTestBed({
index 0050c87ec705035080bb01d070669b886d602012..e48f2bbef5b7f8bf65305e59e3bcdf993bdf80ea 100644 (file)
@@ -1,10 +1,15 @@
-<ng-template #matcherTpl let-matcher="matcher" let-index="index">
-  <div class="input-group">
+<ng-template #matcherTpl
+             let-matcher="matcher"
+             let-index="index">
+  <div class="input-group my-2">
     <ng-container *ngFor="let config of matcherConfig">
-      <span class="input-group-addon"
-            [tooltip]=config.tooltip>
-        <i class="icon-prepend" [ngClass]="[config.icon]"></i>
-      </span>
+      <div class="input-group-prepend">
+        <span class="input-group-text"
+              [tooltip]=config.tooltip>
+          <i [ngClass]="[config.icon]"></i>
+        </span>
+      </div>
+
       <ng-container *ngIf="config.attribute !== 'isRegex'">
         <input type="text"
                id="matcher-{{config.attribute}}-{{index}}"
                disabled
                readonly>
       </ng-container>
+
       <ng-container *ngIf="config.attribute === 'isRegex'">
-        <span class="input-group-addon">
-          <input type="checkbox"
-                 id="matcher-{{config.attribute}}-{{index}}"
-                 [checked]="matcher[config.attribute]"
-                 disabled
-                 readonly>
-        </span>
+        <div class="input-group-append">
+          <div class="input-group-text">
+            <input type="checkbox"
+                   id="matcher-{{config.attribute}}-{{index}}"
+                   [checked]="matcher[config.attribute]"
+                   disabled
+                   readonly>
+          </div>
+        </div>
       </ng-container>
     </ng-container>
+
     <!-- Matcher actions -->
-    <span class="input-group-btn">
+    <span class="input-group-append">
       <button type="button"
-              class="btn btn-default"
+              class="btn btn-light"
               id="matcher-edit-{{index}}"
               i18n-tooltip
               tooltip="Edit"
@@ -34,7 +43,7 @@
         <i [ngClass]="[icons.edit]"></i>
       </button>
       <button type="button"
-              class="btn btn-default"
+              class="btn btn-light"
               id="matcher-delete-{{index}}"
               i18n-tooltip
               tooltip="Delete"
 <div class="col-sm-12 col-lg-6">
   <form #formDir="ngForm"
         [formGroup]="form"
-        class="form-horizontal"
+        class="form"
         name="form"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          <span i18n="@@formTitle">
-            {{ action | titlecase }} {{ resource | upperFirst }}
-          </span>
-          <cd-helper *ngIf="edit"
-                     i18n>Editing a silence will expire the old silence and recreate it as a new silence</cd-helper>
-        </h3>
+    <div class="card">
+      <div class="card-header">
+        <span i18n="@@formTitle">
+          {{ action | titlecase }} {{ resource | upperFirst }}
+        </span>
+        <cd-helper *ngIf="edit"
+                   i18n>Editing a silence will expire the old silence and recreate it as a new silence</cd-helper>
       </div>
 
       <!-- Creator -->
-      <div class="panel-body">
-        <div [ngClass]="{'has-error': form.showError('createdBy', formDir)}"
-             class="form-group">
-          <label class="control-label col-sm-3"
+      <div class="card-body">
+        <div class="form-group row">
+          <label class="col-form-label col-sm-3"
                  for="created-by">
             <ng-container i18n>Creator</ng-container>
             <span class="required"></span>
                    name="created-by"
                    type="text">
             <span *ngIf="form.showError('createdBy', formDir, 'required')"
-                  class="help-block"
+                  class="invalid-feedback"
                   i18n>This field is required!</span>
           </div>
         </div>
 
         <!-- Comment -->
-        <div [ngClass]="{'has-error': form.showError('comment', formDir)}"
-             class="form-group">
-          <label class="control-label col-sm-3"
+        <div class="form-group row">
+          <label class="col-form-label col-sm-3"
                  for="comment">
             <ng-container i18n>Comment</ng-container>
             <span class="required"></span>
                       type="text">
             </textarea>
             <span *ngIf="form.showError('comment', formDir, 'required')"
-                  class="help-block"
+                  class="invalid-feedback"
                   i18n>This field is required!</span>
           </div>
         </div>
 
         <!-- Start time -->
-        <div [ngClass]="{'has-error': form.showError('startsAt', formDir)}"
-             class="form-group">
-          <label class="control-label col-sm-3"
+        <div class="form-group row">
+          <label class="col-form-label col-sm-3"
                  for="starts-at">
             <ng-container i18n>Start time</ng-container>
             <cd-helper i18n>If the start time lies in the past the creation time will be used</cd-helper>
                    id="starts-at"
                    name="starts-at">
             <span *ngIf="form.showError('startsAt', formDir, 'required')"
-                  class="help-block"
+                  class="invalid-feedback"
                   i18n>This field is required!</span>
           </div>
         </div>
 
         <!-- Duration -->
-        <div [ngClass]="{'has-error': form.showError('duration', formDir)}"
-             class="form-group">
-          <label class="control-label col-sm-3"
+        <div class="form-group row">
+          <label class="col-form-label col-sm-3"
                  for="duration">
             <ng-container i18n>Duration</ng-container>
             <span class="required"></span>
                    name="duration"
                    type="text">
             <span *ngIf="form.showError('duration', formDir, 'required')"
-                  class="help-block"
+                  class="invalid-feedback"
                   i18n>This field is required!</span>
           </div>
         </div>
 
         <!-- End time -->
-        <div [ngClass]="{'has-error': form.showError('endsAt', formDir)}"
-             class="form-group">
-          <label class="control-label col-sm-3"
+        <div class="form-group row">
+          <label class="col-form-label col-sm-3"
                  for="ends-at">
             <ng-container i18n>End time</ng-container>
             <span class="required"></span>
                    id="ends-at"
                    name="ends-at">
             <span *ngIf="form.showError('endsAt', formDir, 'required')"
-                  class="help-block"
+                  class="invalid-feedback"
                   i18n>This field is required!</span>
           </div>
         </div>
         <!-- Matchers -->
         <fieldset>
           <legend i18n>Matchers<span class="required">*</span></legend>
-          <div class="col-sm-offset-3 col-sm-9">
+
+          <div class="offset-sm-3 col-sm-9">
             <h5 *ngIf="matchers.length === 0"
                 [ngClass]="{'text-warning': !formDir.submitted, 'text-danger': formDir.submitted}">
               <strong i18n>A silence requires at least one matcher</strong>
               <ng-container *ngTemplateOutlet="matcherTpl; context:{index: i, matcher: matcher}"></ng-container>
             </span>
 
-            <span class="form-control no-border">
-              <button type="button"
-                      id="add-matcher"
-                      class="btn btn-sm btn-default btn-label pull-right"
-                      [ngClass]="{'btn-warning': formDir.submitted && matchers.length === 0 }"
-                      (click)="showMatcherModal()">
-                <i [ngClass]="[icons.width, icons.add]"></i>
-                <ng-container i18n>Add matcher</ng-container>
-              </button>
-            </span>
+            <div class="row">
+              <div class="col-12">
+                <button type="button"
+                        id="add-matcher"
+                        class="btn btn-light float-right my-3"
+                        [ngClass]="{'btn-warning': formDir.submitted && matchers.length === 0 }"
+                        (click)="showMatcherModal()">
+                  <i [ngClass]="[icons.add]"></i>
+                  <ng-container i18n>Add matcher</ng-container>
+                </button>
+              </div>
+            </div>
           </div>
+
           <div *ngIf="matchers.length && matcherMatch"
-               class="col-sm-offset-3 col-sm-9 {{matcherMatch.cssClass}}"
+               class="offset-sm-3 col-sm-9 {{matcherMatch.cssClass}}"
                id="match-state">
-            <span class="help-block {{matcherMatch.cssClass}}">
+            <span class="text-muted {{matcherMatch.cssClass}}">
               {{ matcherMatch.status }}
             </span>
           </div>
         </fieldset>
       </div>
 
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
           <cd-submit-button (submitAction)="submit()"
                             [form]="formDir"
-                            id="submit"
-                            i18n="@@formTitle"
-                            type="button">
+                            i18n="@@formTitle">
             {{ action | titlecase }} {{ resource | upperFirst }}
           </cd-submit-button>
           <cd-back-button></cd-back-button>
index 9c8360eb7b0a9aa46255026254b9e69e197c6680..d2ea0ee438244443cb207825dacd4ce06d54f921 100644 (file)
@@ -40,9 +40,9 @@ export class SilenceListComponent implements OnInit {
   selection = new CdTableSelection();
   modalRef: BsModalRef;
   customCss = {
-    'label label-danger': 'active',
-    'label label-warning': 'pending',
-    'label label-default': 'expired'
+    'badge badge-danger': 'active',
+    'badge badge-warning': 'pending',
+    'badge badge-default': 'expired'
   };
   sorts: SortPropDir[] = [{ prop: 'endsAt', dir: SortDirection.desc }];
 
index c0ad6ac65ebbff3282212e5c8aa8240de6da4acb..3ca8dfdccd0cb99b3082a5cd25f8a205d28c7d80 100644 (file)
@@ -9,15 +9,14 @@
   </button>
 </div>
 
-<form class="form-horizontal"
+<form class="form"
       #formDir="ngForm"
       [formGroup]="form"
       novalidate>
   <div class="modal-body">
     <!-- Name -->
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('name', formDir)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row">
+      <label class="col-form-label col-sm-3"
              for="name">
         <ng-container i18n>Name</ng-container>
         <span class="required"></span>
@@ -41,9 +40,8 @@
     </div>
 
     <!-- Value -->
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('value', formDir)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row">
+      <label class="col-form-label col-sm-3"
              for="value">
         <ng-container i18n>Value</ng-container>
         <span class="required"></span>
               i18n>This field is required!</span>
       </div>
       <div *ngIf="form.getValue('value') && !form.getValue('isRegex') && matcherMatch"
-           class="col-sm-offset-3 col-sm-9 {{matcherMatch.cssClass}}"
+           class="offset-sm-3 col-sm-9 {{matcherMatch.cssClass}}"
            id="match-state">
-        <span class="help-block {{matcherMatch.cssClass}}">
+        <span class="text-muted {{matcherMatch.cssClass}}">
           {{matcherMatch.status}}
         </span>
       </div>
     </div>
 
     <!-- isRegex -->
-    <div class="form-group">
-      <div class="col-sm-offset-3 col-sm-9">
-        <div class="input-group">
-          <div class="checkbox checkbox-primary">
-            <input id="is-regex"
-                   type="checkbox"
-                   formControlName="isRegex">
-            <label for="is-regex"
-                   i18n>Use regular expression</label>
-          </div>
+    <div class="form-group row">
+      <div class="offset-sm-3 col-sm-9">
+        <div class="custom-control custom-checkbox">
+          <input type="checkbox"
+                 class="custom-control-input"
+                 formControlName="isRegex"
+                 name="is-regex"
+                 id="is-regex">
+          <label for="is-regex"
+                 class="custom-control-label"
+                 i18n>Use regular expression</label>
         </div>
       </div>
     </div>
@@ -95,4 +94,3 @@
     </cd-back-button>
   </div>
 </form>
-
index 53d48f888f3e3297b275f03fb981dce77368cc2b..4ac9b3421503aa46c648899336af23f7bc74493f 100644 (file)
@@ -2,7 +2,6 @@
      class="container-fluid">
   <cd-info-group groupTitle="Status"
                  i18n-groupTitle
-                 class="row info-group"
                  *ngIf="healthData.health?.status
                  || healthData.mon_status
                  || healthData.osd_map
@@ -14,8 +13,8 @@
 
     <cd-info-card cardTitle="Cluster Status"
                   i18n-cardTitle
-                  class="col-sm-6 col-md-4 col-lg-3"
-                  [contentClass]="healthData.health?.checks?.length > 0 ? 'content-highlight text-area-size-2' : 'content-highlight'"
+                  class="cd-status-card"
+                  contentClass="content-highlight"
                   *ngIf="healthData.health?.status">
       <ng-container *ngIf="healthData.health?.checks?.length > 0">
         <ng-template #healthChecks>
@@ -48,7 +47,7 @@
     <cd-info-card cardTitle="Monitors"
                   i18n-cardTitle
                   link="/monitor"
-                  class="col-sm-6 col-md-4 col-lg-3"
+                  class="cd-status-card"
                   contentClass="content-highlight"
                   *ngIf="healthData.mon_status">
       {{ healthData.mon_status | monSummary }}
@@ -57,9 +56,9 @@
     <cd-info-card cardTitle="OSDs"
                   i18n-cardTitle
                   link="/osd"
-                  class="col-sm-6 col-md-4 col-lg-3"
+                  class="cd-status-card"
                   *ngIf="(healthData.osd_map | osdSummary) as transformedResult"
-                  [contentClass]="(transformedResult.length == 5 ? 'text-area-size-3' : 'text-area-size-2') + ' content-highlight'">
+                  contentClass="content-highlight">
       <span *ngFor="let result of transformedResult"
             [ngClass]="result.class">
         {{ result.content }}
@@ -68,8 +67,8 @@
 
     <cd-info-card cardTitle="Manager Daemons"
                   i18n-cardTitle
-                  class="col-sm-6 col-md-4 col-lg-3"
-                  contentClass="content-highlight text-area-size-2"
+                  class="cd-status-card"
+                  contentClass="content-highlight"
                   *ngIf="healthData.mgr_map">
       <span *ngFor="let result of (healthData.mgr_map | mgrSummary)"
             [ngClass]="result.class"
@@ -81,8 +80,8 @@
     <cd-info-card cardTitle="Hosts"
                   i18n-cardTitle
                   link="/hosts"
-                  class="col-sm-6 col-md-4 col-lg-3"
-                  contentClass="content-medium content-highlight"
+                  class="cd-status-card"
+                  contentClass="content-highlight"
                   *ngIf="healthData.hosts != null">
       {{ healthData.hosts }} total
     </cd-info-card>
     <cd-info-card cardTitle="Object Gateways"
                   i18n-cardTitle
                   link="/rgw/daemon"
-                  class="col-sm-6 col-md-4 col-lg-3"
-                  contentClass="content-medium content-highlight"
+                  class="cd-status-card"
+                  contentClass="content-highlight"
                   *ngIf="enabledFeature.rgw && healthData.rgw != null">
       {{ healthData.rgw }} total
     </cd-info-card>
+
     <cd-info-card cardTitle="Metadata Servers"
                   i18n-cardTitle
-                  class="col-sm-6 col-md-4 col-lg-3"
+                  class="cd-status-card"
                   *ngIf="(enabledFeature.cephfs && healthData.fs_map | mdsSummary) as transformedResult"
                   [contentClass]="(transformedResult.length > 1 ? 'text-area-size-2' : '') + ' content-highlight'">
+      <!-- TODO: check text-area-size-2 -->
       <span *ngFor="let result of transformedResult"
             [ngClass]="result.class">
         {{ result.content }}
     <cd-info-card cardTitle="iSCSI Gateways"
                   i18n-cardTitle
                   link="/block/iscsi"
-                  class="col-sm-6 col-md-4 col-lg-3"
-                  contentClass="content-medium content-highlight"
+                  class="cd-status-card"
+                  contentClass="content-highlight"
                   *ngIf="enabledFeature.iscsi && healthData.iscsi_daemons != null">
       {{ healthData.iscsi_daemons }} total
     </cd-info-card>
 
   <cd-info-group groupTitle="Performance"
                  i18n-groupTitle
-                 class="row info-group"
                  *ngIf="healthData.client_perf || healthData.scrub_status">
 
-    <div class="cd-container-flex">
-      <cd-info-card cardTitle="Client IOPS"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.client_perf">
-        {{ (healthData.client_perf.read_op_per_sec + healthData.client_perf.write_op_per_sec) | round:1 }}
-      </cd-info-card>
+    <cd-info-card cardTitle="Client IOPS"
+                  i18n-cardTitle
+                  class="cd-performance-card"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.client_perf">
+      {{ (healthData.client_perf.read_op_per_sec + healthData.client_perf.write_op_per_sec) | round:1 }}
+    </cd-info-card>
 
-      <cd-info-card cardTitle="Client Throughput"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.client_perf">
-        {{ ((healthData.client_perf.read_bytes_sec + healthData.client_perf.write_bytes_sec) | dimlessBinary) + '/s' }}
-      </cd-info-card>
+    <cd-info-card cardTitle="Client Throughput"
+                  i18n-cardTitle
+                  class="cd-performance-card"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.client_perf">
+      {{ ((healthData.client_perf.read_bytes_sec + healthData.client_perf.write_bytes_sec) | dimlessBinary) + '/s' }}
+    </cd-info-card>
 
-      <cd-info-card cardTitle="Client Read/Write"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    [contentClass]="isClientReadWriteChartShowable() ? 'content-chart': 'content-medium content-highlight'"
-                    *ngIf="healthData.client_perf">
-        <cd-health-pie *ngIf="isClientReadWriteChartShowable()"
-                       [data]="healthData"
-                       (prepareFn)="prepareReadWriteRatio($event[0], $event[1])">
-        </cd-health-pie>
-        <span *ngIf="!isClientReadWriteChartShowable()">
-          N/A
-        </span>
-      </cd-info-card>
+    <cd-info-card cardTitle="Client Read/Write"
+                  i18n-cardTitle
+                  class="cd-performance-card"
+                  [contentClass]="isClientReadWriteChartShowable() ? 'content-chart': 'content-highlight'"
+                  *ngIf="healthData.client_perf">
+      <cd-health-pie *ngIf="isClientReadWriteChartShowable()"
+                     [data]="healthData"
+                     (prepareFn)="prepareReadWriteRatio($event[0], $event[1])">
+      </cd-health-pie>
+      <span *ngIf="!isClientReadWriteChartShowable()">
+        N/A
+      </span>
+    </cd-info-card>
 
-      <cd-info-card cardTitle="Recovery Throughput"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.client_perf">
-        {{ (healthData.client_perf.recovering_bytes_per_sec | dimlessBinary) + '/s' }}
-      </cd-info-card>
+    <cd-info-card cardTitle="Recovery Throughput"
+                  i18n-cardTitle
+                  class="cd-performance-card"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.client_perf">
+      {{ (healthData.client_perf.recovering_bytes_per_sec | dimlessBinary) + '/s' }}
+    </cd-info-card>
 
-      <cd-info-card cardTitle="Scrub"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.scrub_status">
-        {{ healthData.scrub_status }}
-      </cd-info-card>
-    </div>
+    <cd-info-card cardTitle="Scrub"
+                  i18n-cardTitle
+                  class="cd-performance-card"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.scrub_status">
+      {{ healthData.scrub_status }}
+    </cd-info-card>
   </cd-info-group>
 
   <cd-info-group groupTitle="Capacity"
                  i18n-groupTitle
-                 class="row info-group"
                  *ngIf="healthData.pools
                  || healthData.df
                  || healthData.pg_info">
+    <cd-info-card cardTitle="Pools"
+                  i18n-cardTitle
+                  link="/pool"
+                  class="cd-capacity-card order-md-1 order-lg-4 order-xl-1"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.pools">
+      {{ healthData.pools.length }}
+    </cd-info-card>
 
-    <div class="cd-container-flex">
-      <cd-info-card cardTitle="Pools"
-                    i18n-cardTitle
-                    link="/pool"
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.pools">
-        {{ healthData.pools.length }}
-      </cd-info-card>
-
-      <cd-info-card cardTitle="Raw Capacity"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-chart"
-                    *ngIf="healthData.df">
-        <cd-health-pie [data]="healthData"
-                       [config]="rawCapacityChartConfig"
-                       [showLabelAsTooltip]="true"
-                       (prepareFn)="prepareRawUsage($event[0], $event[1])">
-        </cd-health-pie>
-      </cd-info-card>
+    <cd-info-card cardTitle="Raw Capacity"
+                  i18n-cardTitle
+                  class="cd-capacity-card order-md-3 order-lg-1 order-xl-2"
+                  contentClass="content-chart"
+                  *ngIf="healthData.df">
+      <cd-health-pie [data]="healthData"
+                     [config]="rawCapacityChartConfig"
+                     [isBytesData]="true"
+                     (prepareFn)="prepareRawUsage($event[0], $event[1])">
+      </cd-health-pie>
+    </cd-info-card>
 
-      <cd-info-card cardTitle="Objects"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-chart"
-                    *ngIf="healthData.pg_info?.object_stats?.num_objects != null">
-        <cd-health-pie [data]="healthData"
-                       [config]="objectsChartConfig"
-                       (prepareFn)="prepareObjects($event[0], $event[1])">
-        </cd-health-pie>
-      </cd-info-card>
+    <cd-info-card cardTitle="Objects"
+                  i18n-cardTitle
+                  class="cd-capacity-card order-md-4 order-lg-2 order-xl-3"
+                  contentClass="content-chart"
+                  *ngIf="healthData.pg_info?.object_stats?.num_objects != null">
+      <cd-health-pie [data]="healthData"
+                     [config]="objectsChartConfig"
+                     (prepareFn)="prepareObjects($event[0], $event[1])">
+      </cd-health-pie>
+    </cd-info-card>
 
-      <cd-info-card cardTitle="PGs per OSD"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-medium content-highlight"
-                    *ngIf="healthData.pg_info">
-        {{ healthData.pg_info.pgs_per_osd | dimless }}
-      </cd-info-card>
+    <cd-info-card cardTitle="PGs per OSD"
+                  i18n-cardTitle
+                  class="cd-capacity-card order-md-2 order-lg-5 order-xl-4"
+                  contentClass="content-highlight"
+                  *ngIf="healthData.pg_info">
+      {{ healthData.pg_info.pgs_per_osd | dimless }}
+    </cd-info-card>
 
-      <cd-info-card cardTitle="PG Status"
-                    i18n-cardTitle
-                    class="cd-col-5"
-                    cardClass="card-medium"
-                    contentClass="content-chart"
-                    (click)="pgStatusTarget.toggle()"
-                    *ngIf="healthData.pg_info">
-        <ng-template #pgStatus>
-          <ng-container *ngTemplateOutlet="logsLink"></ng-container>
-          <ul>
-            <li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
-              {{ pgStatesText.key }}: {{ pgStatesText.value }}
-            </li>
-          </ul>
-        </ng-template>
-        <div class="pg-status-popover-wrapper">
-          <div [popover]="pgStatus"
-               triggers=""
-               #pgStatusTarget="bs-popover"
-               placement="bottom">
-            <cd-health-pie [data]="healthData"
-                           [config]="pgStatusChartConfig"
-                           (prepareFn)="preparePgStatus($event[0], $event[1])">
-            </cd-health-pie>
-          </div>
+    <cd-info-card cardTitle="PG Status"
+                  i18n-cardTitle
+                  class="cd-capacity-card order-md-5 order-lg-3 order-xl-5"
+                  contentClass="content-chart"
+                  (click)="pgStatusTarget.toggle()"
+                  *ngIf="healthData.pg_info">
+      <ng-template #pgStatus>
+        <ng-container *ngTemplateOutlet="logsLink"></ng-container>
+        <ul>
+          <li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
+            {{ pgStatesText.key }}: {{ pgStatesText.value }}
+          </li>
+        </ul>
+      </ng-template>
+      <div class="pg-status-popover-wrapper">
+        <div [popover]="pgStatus"
+             triggers=""
+             #pgStatusTarget="bs-popover"
+             placement="bottom">
+          <cd-health-pie [data]="healthData"
+                         [config]="pgStatusChartConfig"
+                         (prepareFn)="preparePgStatus($event[0], $event[1])">
+          </cd-health-pie>
         </div>
-      </cd-info-card>
-    </div>
+      </div>
+    </cd-info-card>
   </cd-info-group>
 
   <ng-template #logsLink>
index 17d0134b91bb363731b27edf3680f8c13adbc47f..800fd768400481d6056cc558fbf2216581b8e9c4 100644 (file)
@@ -1,55 +1,9 @@
-@import '../../../../defaults';
+@import 'styles';
 
 cd-info-card {
   padding: 0 0.5vw 0 0.5vw;
-}
-
-.cd-container-flex {
-  margin: 0;
-  padding: 0;
-  display: -webkit-box;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  flex-flow: row wrap;
-  justify-content: space-between;
-}
-
-.cd-col-5 {
-  width: 20%;
-}
-
-@media (max-width: 1599px) {
-  .cd-col-5 {
-    width: 25%;
-  }
-}
-
-@media (max-width: $screen-md-max) {
-  .cd-col-5 {
-    width: 33%;
-  }
-}
-
-@media (max-width: $screen-sm-max) {
-  .cd-col-5 {
-    width: 50%;
-  }
-}
-
-@media (max-width: $screen-xs-max) {
-  cd-info-card {
-    padding: 0;
-  }
-
-  .cd-col-5 {
-    width: 100%;
-  }
-}
-
-.info-group {
-  margin: 0;
-  padding: 0;
+  @extend .d-flex;
+  @extend .flex-column;
 }
 
 ::ng-deep .pg-status-popover-wrapper {
@@ -87,3 +41,19 @@ cd-info-card {
 .mgr-active-name:hover {
   cursor: pointer;
 }
+
+::ng-deep cd-info-card {
+  @extend .col-12;
+  @extend .col-sm-12;
+  @extend .col-md-6;
+  @extend .col-lg-4;
+
+  &.cd-status-card {
+    @extend .col-xl-3;
+  }
+
+  &.cd-performance-card,
+  &.cd-capacity-card {
+    @extend .col-xl;
+  }
+}
index 1ec12366edd9036a7870af5f060c607c51ee7ee4..dcfc4a40058aab90ff2a21c197c70b79c81a7a72 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 .info-card-popover-cluster-status {
   max-width: 23vw;
   }
 }
 
-@media (max-width: $screen-md-max) {
+@media (max-width: $screen-lg-max) {
   .info-card-popover-cluster-status {
     max-width: 31vw;
   }
 }
 
-@media (max-width: $screen-sm-max) {
+@media (max-width: $screen-md-max) {
   .info-card-popover-cluster-status {
     max-width: 46vw;
   }
 }
-@media (max-width: $screen-xs-max) {
+@media (max-width: $screen-sm-max) {
   .info-card-popover-cluster-status {
     max-width: 83vw;
   }
index ae672510a8cccb83cc5286c58dfb08a333aaab08..71894688f3a59e8795487ee4380498f61644953a 100644 (file)
@@ -1,14 +1,18 @@
-<div class="card"
+<div class="card mb-4"
      [ngClass]="cardClass">
-  <div class="card-title">
-    <a *ngIf="link; else noLinkTitle"
-       [routerLink]="link">{{ cardTitle }}</a>
-    <ng-template #noLinkTitle>
-      {{ cardTitle }}
-    </ng-template>
-  </div>
-  <div class="card-body"
-       [ngClass]="contentClass">
-    <ng-content></ng-content>
+  <div class="card-body d-flex align-items-center justify-content-center">
+    <h5 class="card-title m-4">
+      <a *ngIf="link; else noLinkTitle"
+         [routerLink]="link">{{ cardTitle }}</a>
+
+      <ng-template #noLinkTitle>
+        {{ cardTitle }}
+      </ng-template>
+    </h5>
+
+    <div class="card-text text-center"
+         [ngClass]="contentClass">
+      <ng-content></ng-content>
+    </div>
   </div>
 </div>
index dd0ce775e04559e394cf19bbca62255540466ba3..f5cfcb708ff3a8802ca92f19691766da0b144b25 100644 (file)
@@ -1,53 +1,36 @@
-@import '../../../../defaults';
+@import 'styles';
 
-$card-height: 6vw;
-$card-medium-height: 12vw;
 $card-font-min-width: 320px;
 $card-font-max-width: 2048px;
 $card-font-min-size: 12px;
 $card-font-max-size: 21px;
-$logs-text-font-size: $card-font-min-size;
 
 .card {
+  height: 100%;
+  @extend .pb-2;
   border: 0.5px solid $color-info-card-border;
   border-radius: 3px;
-  background-color: $color-solid-white;
   box-shadow: 0 1px 1px $color-shadow-gray;
-  margin: 0 -10px 20px;
-  padding: 0 20px;
-  width: auto;
-  height: auto;
-  margin-left: auto;
-  margin-right: auto;
-  min-height: $card-height;
   @include fluid-font-size(
     $card-font-min-width,
     $card-font-max-width,
     $card-font-min-size,
     $card-font-max-size
   );
-  position: relative;
-}
 
-.card-title {
-  margin: 1.1vw 0;
-  padding: 0;
-}
+  .card-body {
+    padding-top: 40px !important;
 
-.card-body {
-  text-align: center;
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%);
-}
+    .card-title {
+      position: absolute;
+      left: 0;
+      top: 0;
+    }
 
-.content-chart {
-  margin-top: -0.7vw;
-  position: unset;
-  top: unset;
-  left: unset;
-  transform: unset;
+    .card-text {
+      @extend .pt-2;
+    }
+  }
 }
 
 .no-center {
@@ -57,79 +40,6 @@ $logs-text-font-size: $card-font-min-size;
   transform: unset;
 }
 
-.text-area-size-2 {
-  margin-right: -50%;
-  transform: translate(-50%, -20%);
-}
-
-.text-area-size-3 {
-  margin-right: -50%;
-  transform: translate(-50%, -40%);
-}
-
 .content-highlight {
   font-weight: bold;
 }
-
-.card-medium {
-  min-height: $card-medium-height;
-}
-
-.scroll {
-  max-height: ($card-medium-height * 1.5);
-  overflow-y: auto;
-}
-
-.text-monospace {
-  font-size: $logs-text-font-size;
-  font-family: monospace;
-  text-align: left;
-}
-
-@media (max-width: 1599px) {
-  .card {
-    min-height: $card-height * 1.3;
-  }
-
-  .card-medium {
-    min-height: $card-medium-height * 1.2;
-  }
-}
-
-@media (max-width: $screen-md-max) {
-  .card-medium {
-    min-height: $card-medium-height * 1.5;
-  }
-
-  .content-chart {
-    margin-top: -0.6vw;
-  }
-}
-
-@media (max-width: $screen-sm-max) {
-  .card {
-    min-height: $card-height * 2;
-  }
-
-  .content-chart {
-    margin-top: -0.3vw;
-  }
-}
-
-@media (max-width: $screen-sm-max) and (min-width: $screen-sm-min) {
-  .card-medium {
-    min-height: $card-medium-height * 2.2;
-  }
-}
-
-@media (max-width: 599px) {
-  .card {
-    min-height: $card-height * 3;
-  }
-}
-
-@media (max-width: 319px) {
-  .card {
-    min-height: $card-height * 4;
-  }
-}
index b7082b3a57e2ca691578f89db2469604028ed33e..a4be2aeb9e9764cb5abc8a495d543e4528a8c7d6 100644 (file)
@@ -58,7 +58,7 @@ describe('InfoCardComponent', () => {
     const contentClass = 'my-css-content-class';
     component.contentClass = contentClass;
     fixture.detectChanges();
-    const card = fixture.debugElement.nativeElement.querySelector(`.card-body.${contentClass}`);
+    const card = fixture.debugElement.nativeElement.querySelector(`.card-body .${contentClass}`);
 
     expect(card).toBeTruthy();
   });
index 48e516ba3ec9a511ed78ce9ca3c027649266a143..39d7246d54f27564299472f7875ab5be9ce4f070 100644 (file)
@@ -1,4 +1,6 @@
-<div class="info-group-title">
-  {{ groupTitle }}
+<div class="row">
+  <span class="info-group-title">{{ groupTitle }}</span>
+</div>
+<div class="row">
+  <ng-content></ng-content>
 </div>
-<ng-content></ng-content>
index 3f2efa997a03ffe04821e7ecd93c87616f15c204..8e8a370bdfdde0417736564bab21daa835c1cc2c 100644 (file)
@@ -1,7 +1,4 @@
-@import '../../../../defaults';
-
 .info-group-title {
   margin: 0 0 0.5vw 0.5vw;
-  padding: 0;
   font-size: 21px;
 }
index bce4513160534f823f6a060daeea52a2d7f6e46c..e1b3a702fe6d94a6ab887adf0ffdb702d81ca190 100644 (file)
@@ -1,34 +1,33 @@
-<div class="form-group">
-  <label class="col-sm-3 control-label"
+<div class="form-group row">
+  <label class="col-sm-3 col-form-label"
          i18n>Clients</label>
 
   <div class="col-sm-9"
        [formGroup]="form"
        #formDir="ngForm">
     <span *ngIf="form.get('clients').value.length === 0"
-          class="form-control no-border text-muted">
-      <span class="text-muted"
+          class="no-border text-muted">
+      <span class="form-text text-muted"
             i18n>Any client can access</span>
     </span>
 
     <ng-container formArrayName="clients">
       <div *ngFor="let item of form.get('clients').value; let index = index; trackBy: trackByFn">
-        <div class="panel panel-default"
+        <div class="card"
              [formGroupName]="index">
-          <div class="panel-heading">
-            <h3 class="panel-title">{{ (index + 1) | ordinal }}
-              <span class="pull-right clickable"
-                    (click)="removeClient(index)"
-                    tooltip="Remove">&times;</span>
-            </h3>
+          <div class="card-header">
+            {{ (index + 1) | ordinal }}
+            <span class="float-right clickable"
+                  (click)="removeClient(index)"
+                  tooltip="Remove">&times;</span>
           </div>
 
-          <div class="panel-body">
+          <div class="card-body">
             <!-- Addresses -->
-            <div class="form-group"
-                 [ngClass]="{ 'has-error': showError(index, 'addresses', formDir) }">
+            <div class="form-group row"
+                 [ngClass]="{ ':invalid': showError(index, 'addresses', formDir) }">
               <label i18n
-                     class="col-sm-3 control-label"
+                     class="col-sm-3 col-form-label"
                      for="addresses">Addresses</label>
               <div class="col-sm-9">
                 <input type="text"
@@ -37,7 +36,7 @@
                        id="addresses"
                        formControlName="addresses"
                        placeholder="192.168.0.10, 192.168.1.0/8">
-                <span class="help-block">
+                <span class="form-text text-muted">
                   <span *ngIf="showError(index, 'addresses', formDir, 'required')"
                         i18n>Required field</span>
 
@@ -51,9 +50,9 @@
             </div>
 
             <!-- Access Type-->
-            <div class="form-group">
+            <div class="form-group row">
               <label i18n
-                     class="col-sm-3 control-label"
+                     class="col-sm-3 col-form-label"
                      for="access_type">Access Type</label>
               <div class="col-sm-9">
                 <select class="form-control"
@@ -64,7 +63,7 @@
                   <option *ngFor="let item of nfsAccessType"
                           [value]="item.value">{{ item.value }}</option>
                 </select>
-                <span class="help-block"
+                <span class="form-text text-muted"
                       *ngIf="getValue(index, 'access_type')">
                   {{ getAccessTypeHelp(index) }}
                 </span>
@@ -72,9 +71,9 @@
             </div>
 
             <!-- Squash -->
-            <div class="form-group">
+            <div class="form-group row">
               <label i18n
-                     class="col-sm-3 control-label"
+                     class="col-sm-3 col-form-label"
                      for="squash">Squash</label>
               <div class="col-sm-9">
                 <select class="form-control"
       </div>
     </ng-container>
 
-    <span class="form-control no-border">
-      <button class="btn btn-default btn-label pull-right"
-              (click)="addClient()">
-        <i [ngClass]="[icons.add, icons.width]"></i>
-        <ng-container i18n>Add clients</ng-container>
-      </button>
-    </span>
-    <hr>
+    <div class="row">
+      <div class="col-12">
+        <div class="float-right">
+          <button class="btn btn-light "
+                  (click)="addClient()">
+            <i [ngClass]="[icons.add]"></i>
+            <ng-container i18n>Add clients</ng-container>
+          </button>
+        </div>
+      </div>
+    </div>
   </div>
 </div>
index 5057a1faf1d78d7d76898d1196ad4e7d0fb0e701..a22f42d0dbe3d942a47551461a6f08b563291d5e 100644 (file)
@@ -1,22 +1,18 @@
 <div class="col-sm-12 col-lg-6">
   <form name="nfsForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="nfsForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
 
+      <div class="card-body">
         <!-- cluster_id -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('cluster_id', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('cluster_id', formDir)}"
              *ngIf="!isDefaultCluster">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="cluster_id">
             <ng-container i18n>Cluster</ng-container>
             <span class="required"></span>
               <option *ngFor="let cluster of allClusters"
                       [value]="cluster">{{ cluster }}</option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('cluster_id', formDir, 'required')"
                   i18n>Required field</span>
           </div>
         </div>
 
         <!-- daemons -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('daemons', formDir)}">
-          <label class="col-sm-3 control-label"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('daemons', formDir)}">
+          <label class="col-sm-3 col-form-label"
                  for="daemons">
             <ng-container i18n>Daemons</ng-container>
           </label>
           <div class="col-sm-9">
             <ng-container *ngFor="let daemon of nfsForm.getValue('daemons'); let i = index">
               <div class="input-group cd-mb">
-                <input class="form-control"
+                <input class="cd-form-control"
                        type="text"
                        [value]="daemon"
                        disabled />
-                <span class="input-group-btn">
-                  <button class="btn btn-default"
+                <span class="input-group-append">
+                  <button class="btn btn-light"
                           type="button"
                           (click)="removeDaemon(i, daemon)">
-                    <i [ngClass]="[icons.destroy, icons.width]"
+                    <i [ngClass]="[icons.destroy]"
                        aria-hidden="true"></i>
                   </button>
                 </span>
@@ -76,8 +72,8 @@
                            [options]="daemonsSelections"
                            [messages]="daemonsMessages"
                            (selection)="onDaemonSelection()"
-                           elemClass="btn btn-default pull-right">
-                  <i [ngClass]="[icons.add, icons.width]"></i>
+                           elemClass="btn btn-light float-right">
+                  <i [ngClass]="[icons.add]"></i>
                   <ng-container i18n>Add daemon</ng-container>
                 </cd-select>
               </div>
@@ -88,9 +84,9 @@
         <!-- FSAL -->
         <div formGroupName="fsal">
           <!-- Name -->
-          <div class="form-group"
-               [ngClass]="{'has-error': nfsForm.showError('name', formDir)}">
-            <label class="col-sm-3 control-label"
+          <div class="form-group row"
+               [ngClass]="{':invalid': nfsForm.showError('name', formDir)}">
+            <label class="col-sm-3 col-form-label"
                    for="name">
               <ng-container i18n>Storage Backend</ng-container>
               <span class="required"></span>
                 <option *ngFor="let fsal of allFsals"
                         [value]="fsal.value">{{ fsal.descr }}</option>
               </select>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="nfsForm.showError('name', formDir, 'required')"
                     i18n>Required field</span>
             </div>
           </div>
 
           <!-- RGW user -->
-          <div class="form-group"
-               [ngClass]="{'has-error': nfsForm.showError('rgw_user_id', formDir)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': nfsForm.showError('rgw_user_id', formDir)}"
                *ngIf="nfsForm.getValue('name') === 'RGW'">
-            <label class="col-sm-3 control-label"
+            <label class="col-sm-3 col-form-label"
                    for="rgw_user_id">
               <ng-container i18n>Object Gateway User</ng-container>
               <span class="required"></span>
                 <option *ngFor="let rgwUserId of allRgwUsers"
                         [value]="rgwUserId">{{ rgwUserId }}</option>
               </select>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="nfsForm.showError('rgw_user_id', formDir, 'required')"
                     i18n>Required field</span>
             </div>
           </div>
 
           <!-- CephFS user_id -->
-          <div class="form-group"
-               [ngClass]="{'has-error': nfsForm.showError('user_id', formDir)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': nfsForm.showError('user_id', formDir)}"
                *ngIf="nfsForm.getValue('name') === 'CEPH'">
-            <label class="col-sm-3 control-label"
+            <label class="col-sm-3 col-form-label"
                    for="user_id">
               <ng-container i18n>CephFS User ID</ng-container>
               <span class="required"></span>
                 <option *ngFor="let client of allCephxClients"
                         [value]="client">{{ client }}</option>
               </select>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="nfsForm.showError('user_id', formDir, 'required')"
                     i18n>Required field</span>
             </div>
           </div>
 
           <!-- CephFS fs_name -->
-          <div class="form-group"
-               [ngClass]="{'has-error': nfsForm.showError('fs_name', formDir)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': nfsForm.showError('fs_name', formDir)}"
                *ngIf="nfsForm.getValue('name') === 'CEPH'">
-            <label class="col-sm-3 control-label"
+            <label class="col-sm-3 col-form-label"
                    for="fs_name">
               <ng-container i18n>CephFS Name</ng-container>
               <span class="required"></span>
                 <option *ngFor="let filesystem of allFsNames"
                         [value]="filesystem.name">{{ filesystem.name }}</option>
               </select>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="nfsForm.showError('fs_name', formDir, 'required')"
                     i18n>Required field</span>
             </div>
         </div>
 
         <!-- Secutiry Label -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('security_label', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('security_label', formDir)}"
              *ngIf="nfsForm.getValue('name') === 'CEPH'">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="security_label">
             <ng-container i18n>Security Label</ng-container>
             <span class="required"
                    id="sec_label_xattr"
                    formControlName="sec_label_xattr">
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('sec_label_xattr', formDir, 'required')"
                   i18n>Required field</span>
           </div>
         </div>
 
         <!-- Path -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('path', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('path', formDir)}"
              *ngIf="nfsForm.getValue('name') === 'CEPH'">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="path">
             <ng-container i18n>CephFS Path</ng-container>
             <span class="required"></span>
                    [typeahead]="pathDataSource"
                    (typeaheadOnSelect)="pathChangeHandler()"
                    (blur)="pathChangeHandler()">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('path', formDir, 'required')"
                   i18n>Required field</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('path', formDir, 'pattern')"
                   i18n>Path need to start with a '/' and can be followed by a word</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="isNewDirectory && !nfsForm.showError('path', formDir)"
                   i18n>New directory will be created</span>
           </div>
         </div>
 
         <!-- Bucket -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('path', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('path', formDir)}"
              *ngIf="nfsForm.getValue('name') === 'RGW'">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="path">
             <ng-container i18n>Path</ng-container>
             <span class="required"></span>
                    (typeaheadOnSelect)="bucketChangeHandler()"
                    (blur)="bucketChangeHandler()">
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('path', formDir, 'required')"
                   i18n>Required field</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('path', formDir, 'pattern')"
                   i18n>Path can only be a single '/' or a word</span>
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="isNewBucket && !nfsForm.showError('path', formDir)"
                   i18n>New bucket will be created</span>
           </div>
         </div>
 
         <!-- NFS Protocol -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('protocolNfsv3', formDir) || nfsForm.showError('protocolNfsv4', formDir)}">
-          <label class="col-sm-3 control-label"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('protocolNfsv3', formDir) || nfsForm.showError('protocolNfsv4', formDir)}">
+          <label class="col-sm-3 col-form-label"
                  for="protocols">
             <ng-container i18n>NFS Protocol</ng-container>
             <span class="required"></span>
               <label i18n
                      for="protocolNfsv4">NFSv4</label>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('protocolNfsv3', formDir, 'required') ||
                   nfsForm.showError('protocolNfsv4', formDir, 'required')"
                   i18n>Required field</span>
         </div>
 
         <!-- Tag -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="nfsForm.getValue('protocolNfsv3')">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="tag">
             <ng-container i18n>NFS Tag</ng-container>
             <cd-helper>
         </div>
 
         <!-- Pseudo -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('pseudo', formDir)}"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('pseudo', formDir)}"
              *ngIf="nfsForm.getValue('protocolNfsv4')">
-          <label class="col-sm-3 control-label"
+          <label class="col-sm-3 col-form-label"
                  for="pseudo">
             <ng-container i18n>Pseudo</ng-container>
             <span class="required"></span>
                    name="pseudo"
                    id="pseudo"
                    formControlName="pseudo">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('pseudo', formDir, 'required')"
                   i18n>Required field</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('pseudo', formDir, 'pattern')"
                   i18n>Pseudo needs to start with a '/' and can't contain any of the following: >, <, |, &, ( or ).</span>
           </div>
         </div>
 
         <!-- Access Type -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('access_type', formDir)}">
-          <label class="col-sm-3 control-label"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('access_type', formDir)}">
+          <label class="col-sm-3 col-form-label"
                  for="access_type">
             <ng-container i18n>Access Type</ng-container>
             <span class="required"></span>
               <option *ngFor="let accessType of nfsAccessType"
                       [value]="accessType.value">{{ accessType.value }}</option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.getValue('access_type')">
               {{ getAccessTypeHelp(nfsForm.getValue('access_type')) }}
             </span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('access_type', formDir, 'required')"
                   i18n>Required field</span>
           </div>
         </div>
 
         <!-- Squash -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('squash', formDir)}">
-          <label class="col-sm-3 control-label"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('squash', formDir)}">
+          <label class="col-sm-3 col-form-label"
                  for="squash">
             <ng-container i18n>Squash</ng-container>
             <span class="required"></span>
                       [value]="squash">{{ squash }}</option>
 
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('squash', formDir,'required')"
                   i18n>Required field</span>
           </div>
         </div>
 
         <!-- Transport Protocol -->
-        <div class="form-group"
-             [ngClass]="{'has-error': nfsForm.showError('transportUDP', formDir) || nfsForm.showError('transportTCP', formDir)}">
-          <label class="col-sm-3 control-label"
+        <div class="form-group row"
+             [ngClass]="{':invalid': nfsForm.showError('transportUDP', formDir) || nfsForm.showError('transportTCP', formDir)}">
+          <label class="col-sm-3 col-form-label"
                  for="transports">
             <ng-container i18n>Transport Protocol</ng-container>
             <span class="required"></span>
               <label for="transportTCP"
                      i18n>TCP</label>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="nfsForm.showError('transportUDP', formDir, 'required') ||
                   nfsForm.showError('transportTCP', formDir, 'required')"
                   i18n>Required field</span>
 
       </div>
 
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
           <cd-submit-button
-            [form]="formDir"
             (submitAction)="submitAction()"
             i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+            [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 4806bf21d062d8c0efe44e06d5022a480de326cb..d32333dca03bc7965cb36fc44b1900bc2386e93d 100644 (file)
@@ -1,23 +1,23 @@
 <div class="modal-header">
   <h4 i18n="form title|Example: Create Pool@@formTitle"
-      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+      class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="bsModalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
 
-<form class="form-horizontal"
-      #frm="ngForm"
+<form #frm="ngForm"
       [formGroup]="form"
       novalidate>
   <div class="modal-body">
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('name', frm)}">
+    <div class="form-group row"
+         [ngClass]="{':invalid': form.showError('name', frm)}">
       <label for="name"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Name</ng-container>
         <span class="required"></span>
       </label>
                placeholder="Name..."
                formControlName="name"
                autofocus>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('name', frm, 'required')"
               i18n>This field is required!</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('name', frm, 'pattern')"
               i18n>The name can only consist of alphanumeric characters, dashes and underscores.</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('name', frm, 'uniqueName')"
               i18n>The chosen erasure code profile name is already in use.</span>
       </div>
     </div>
 
-    <div class="form-group">
+    <div class="form-group row">
       <label for="plugin"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Plugin</ng-container>
         <span class="required"></span>
         <cd-helper [html]="tooltips.plugins[plugin].description">
             {{ plugin }}
           </option>
         </select>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('name', frm, 'required')"
               i18n>This field is required!</span>
       </div>
     </div>
 
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('k', frm)}">
+    <div class="form-group row"
+         [ngClass]="{':invalid': form.showError('k', frm)}">
       <label for="k"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Data chunks (k)</ng-container>
         <span class="required"
               *ngIf="requiredControls.includes('k')"></span>
                ng-model="$ctrl.erasureCodeProfile.k"
                placeholder="Data chunks..."
                formControlName="k">
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('k', frm, 'required')"
               i18n>This field is required!</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('k', frm, 'min')"
               i18n>Must be equal to or greater than 2.</span>
       </div>
     </div>
 
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('m', frm)}">
+    <div class="form-group row"
+         [ngClass]="{':invalid': form.showError('m', frm)}">
       <label for="m"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Coding chunks (m)</ng-container>
         <span class="required"
               *ngIf="requiredControls.includes('m')"></span>
                class="form-control"
                placeholder="Coding chunks..."
                formControlName="m">
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('m', frm, 'required')"
               i18n>This field is required!</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('m', frm, 'min')"
               i18n>Must be equal to or greater than 1.</span>
       </div>
     </div>
 
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="plugin === 'shec'"
-         [ngClass]="{'has-error': form.showError('c', frm)}">
+         [ngClass]="{':invalid': form.showError('c', frm)}">
       <label for="c"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Durability estimator (c)</ng-container>
         <cd-helper [html]="tooltips.plugins.shec.c">
         </cd-helper>
                class="form-control"
                placeholder="Coding chunks..."
                formControlName="c">
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('c', frm, 'min')"
               i18n>Must be equal to or greater than 1.</span>
       </div>
     </div>
 
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="plugin === PLUGIN.LRC"
-         [ngClass]="{'has-error': form.showError('l', frm)}">
+         [ngClass]="{':invalid': form.showError('l', frm)}">
       <label for="l"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Locality (l)</ng-container>
         <span class="required"></span>
         <cd-helper [html]="tooltips.plugins.lrc.l">
                class="form-control"
                placeholder="Coding chunks..."
                formControlName="l">
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('l', frm, 'required')"
               i18n>This field is required!</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('l', frm, 'min')"
               i18n>Must be equal to or greater than 1.</span>
       </div>
     </div>
 
-    <div class="form-group">
+    <div class="form-group row">
       <label for="crushFailureDomain"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Crush failure domain</ng-container>
         <cd-helper [html]="tooltips.crushFailureDomain">
         </cd-helper>
       </div>
     </div>
 
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="plugin === PLUGIN.LRC">
       <label for="crushLocality"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Crush Locality</ng-container>
         <cd-helper [html]="tooltips.plugins.lrc.crushLocality">
         </cd-helper>
       </div>
     </div>
 
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="[PLUGIN.JERASURE, PLUGIN.ISA].includes(plugin)">
       <label for="technique"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Technique</ng-container>
         <cd-helper [html]="tooltips.plugins[plugin].technique">
         </cd-helper>
       </div>
     </div>
 
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="plugin === PLUGIN.JERASURE"
-         [ngClass]="{'has-error': form.showError('packetSize', frm)}">
+         [ngClass]="{':invalid': form.showError('packetSize', frm)}">
       <label for="packetSize"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Packetsize</ng-container>
         <cd-helper [html]="tooltips.plugins.jerasure.packetSize">
         </cd-helper>
                class="form-control"
                placeholder="Packetsize..."
                formControlName="packetSize">
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="form.showError('packetSize', frm, 'min')"
               i18n>Must be equal to or greater than 1.</span>
       </div>
     </div>
 
-    <div class="form-group"
-         [ngClass]="{'has-error': form.showError('crushRoot', frm)}">
+    <div class="form-group row"
+         [ngClass]="{':invalid': form.showError('crushRoot', frm)}">
       <label for="crushRoot"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Crush root</ng-container>
         <cd-helper [html]="tooltips.crushRoot">
         </cd-helper>
       </div>
     </div>
 
-    <div class="form-group">
+    <div class="form-group row">
       <label for="crushDeviceClass"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Crush device class</ng-container>
         <cd-helper [html]="tooltips.crushDeviceClass">
         </cd-helper>
       </div>
     </div>
 
-    <div class="form-group">
+    <div class="form-group row">
       <label for="directory"
-             class="control-label col-sm-3">
+             class="col-form-label col-sm-3">
         <ng-container i18n>Directory</ng-container>
         <cd-helper [html]="tooltips.directory">
         </cd-helper>
   </div>
 
   <div class="modal-footer">
-    <cd-submit-button
-      (submitAction)="onSubmit()"
-      i18n="form action button|Example: Create Pool@@formActionButton"
-      [form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+    <cd-submit-button (submitAction)="onSubmit()"
+                      i18n="form action button|Example: Create Pool@@formActionButton"
+                      [form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
     <cd-back-button [back]="bsModalRef.hide"></cd-back-button>
   </div>
 </form>
index 1ae48188ace321b476809829aadcbe5f9f1df30b..b8515ca47c20d9e74cec6bcbf0d4b9e1b343dcb0 100644 (file)
@@ -1,26 +1,24 @@
 <div class="col-sm-12 col-lg-6">
   <h1 *ngIf="!(info && ecProfiles)"
       class="jumbotron">
-    <i [ngClass]="[icons.spinner, icons.pulse, icons.large]" class="text-primary"></i>
+    <i [ngClass]="[icons.spinner, icons.pulse, icons.large]"
+       class="text-primary"></i>
     <ng-container i18n>Loading...</ng-container>
   </h1>
   <form name="form"
         *ngIf="info && ecProfiles"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="form"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
 
-      <div class="panel-body">
+      <div class="card-body">
         <!-- Name -->
-        <div class="form-group"
-             [ngClass]="{'has-error': form.showError('name', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': form.showError('name', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="name">
             <ng-container i18n>Name</ng-container>
             <span class="required"></span>
                    i18n-placeholder
                    formControlName="name"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="form.showError('name', formDir, 'required')"
                   i18n>This field is required!</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="form.showError('name', formDir, 'uniqueName')"
                   i18n>The chosen Ceph pool name is already in use.</span>
           </div>
         </div>
 
         <!-- Pool type selection -->
-        <div class="form-group"
-             [ngClass]="{'has-error': form.showError('poolType', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': form.showError('poolType', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="poolType">
             <ng-container i18n>Pool type</ng-container>
             <span class="required"></span>
@@ -63,7 +61,7 @@
                 {{ poolType }}
               </option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="form.showError('poolType', formDir, 'required')"
                   i18n>This field is required!</span>
           </div>
@@ -71,9 +69,9 @@
 
         <div *ngIf="form.getValue('poolType')">
           <!-- Pg number -->
-          <div class="form-group"
-               [ngClass]="{'has-error': form.showError('pgNum', formDir)}">
-            <label class="control-label col-sm-3"
+          <div class="form-group row"
+               [ngClass]="{':invalid': form.showError('pgNum', formDir)}">
+            <label class="col-form-label col-sm-3"
                    for="pgNum">
               <ng-container i18n>Placement groups</ng-container>
               <span class="required"></span>
                      (focus)="externalPgChange = false"
                      (blur)="alignPgs()"
                      required>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('pgNum', formDir, 'required')"
                     i18n>This field is required!</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('pgNum', formDir, 'min')"
                     i18n>At least one placement group is needed!</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('pgNum', formDir, '34')"
                     i18n>Your cluster can't handle this many PGs. Please recalculate the PG amount needed.</span>
-              <span class="help-block">
+              <span class="form-text text-muted">
                 <a i18n
                    target="_blank"
                    href="http://ceph.com/pgcalc">Calculation help</a>
               </span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="externalPgChange"
                     i18n>The current PGs settings were calculated for you, you
                     should make sure the values suit your needs before submit.</span>
           </div>
 
           <!-- Crush ruleset selection -->
-          <div class="form-group"
-               [ngClass]="{'has-error': form.showError('crushRule', formDir)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': form.showError('crushRule', formDir)}"
                *ngIf="form.getValue('poolType') && current.rules.length > 0">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="crushRule"
                    i18n>Crush ruleset</label>
             <div class="col-sm-9">
                     {{ rule.rule_name }}
                   </option>
                 </select>
-                <span class="input-group-btn">
-                  <button class="btn btn-default"
+                <span class="input-group-append">
+                  <button class="btn btn-light"
                           [ngClass]="{'active': data.crushInfo}"
                           id="crush-info-button"
                           type="button"
                   </button>
                 </span>
               </div>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     id="crush-info-block"
                     *ngIf="data.crushInfo && form.getValue('crushRule')">
                 <tabset>
-                  <tab i18n-heading heading="Crush rule" class="crush-rule-info">
+                  <tab i18n-heading
+                       heading="Crush rule"
+                       class="crush-rule-info">
                     <cd-table-key-value [renderObjects]="true"
                                         [data]="form.getValue('crushRule')"
                                         [autoReload]="false">
                     </cd-table-key-value>
                   </tab>
-                  <tab i18n-heading heading="Crush steps" class="crush-rule-steps">
+                  <tab i18n-heading
+                       heading="Crush steps"
+                       class="crush-rule-steps">
                     <ol>
                       <li *ngFor="let step of form.get('crushRule').value.steps">
                         {{ describeCrushStep(step) }}
                   </tab>
                 </tabset>
               </span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('crushRule', formDir, 'tooFewOsds')"
                     i18n>The rule can't be used in the current cluster as it has
                 to few OSDs to meet the minimum required OSD by this rule.</span>
           </div>
 
           <!-- Replica Size -->
-          <div class="form-group"
-               [ngClass]="{'has-error': form.showError('size', formDir)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': form.showError('size', formDir)}"
                *ngIf="form.getValue('poolType') === 'replicated'">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="size">
               <ng-container i18n>Replicated size</ng-container>
               <span class="required"></span>
                      name="size"
                      type="number"
                      formControlName="size">
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('size', formDir)">
                 <ul class="list-inline">
                   <li i18n>Minimum: {{ getMinSize() }}</li>
                   <li i18n>Maximum: {{ getMaxSize() }}</li>
                 </ul>
               </span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="form.showError('size', formDir)"
                     i18n>The size specified is out of range. A value from
-                    {{ getMinSize() }} to {{ getMaxSize() }} is valid.</span>
+                {{ getMinSize() }} to {{ getMaxSize() }} is valid.</span>
             </div>
           </div>
 
           <!-- Erasure Profile select -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="form.getValue('poolType') === 'erasure'">
             <label i18n
-                   class="control-label col-sm-3"
+                   class="col-form-label col-sm-3"
                    for="erasureProfile">Erasure code profile</label>
             <div class="col-sm-9">
               <div class="input-group">
                     {{ ecp.name }}
                   </option>
                 </select>
-                <span class="input-group-btn">
-                  <button class="btn btn-default"
+                <span class="input-group-append">
+                  <button class="btn btn-light"
                           [ngClass]="{'active': data.erasureInfo}"
                           id="ecp-info-button"
                           type="button"
                     <i [ngClass]="[icons.questionCircle]"
                        aria-hidden="true"></i>
                   </button>
-                  <button class="btn btn-default"
+                  <button class="btn btn-light"
                           type="button"
                           [disabled]="editing"
                           (click)="addErasureCodeProfile()">
                     <i [ngClass]="[icons.add]"
                        aria-hidden="true"></i>
                   </button>
-                  <button class="btn btn-default"
+                  <button class="btn btn-light"
                           type="button"
                           (click)="deleteErasureCodeProfile()"
                           [disabled]="editing || ecProfiles.length < 1">
                   </button>
                 </span>
               </div>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     id="ecp-info-block"
                     *ngIf="data.erasureInfo && form.getValue('erasureProfile')">
                 <cd-table-key-value [renderObjects]="true"
           </div>
 
           <!-- Flags -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="info.is_all_bluestore && form.getValue('poolType') === 'erasure'">
             <label i18n
-                   class="control-label col-sm-3">Flags</label>
+                   class="col-form-label col-sm-3">Flags</label>
             <div class="col-sm-9">
-              <div class="input-group">
-                <div class="checkbox checkbox-primary">
-                  <input id="ec-overwrites"
-                         type="checkbox"
-                         formControlName="ecOverwrites">
-                  <label for="ec-overwrites"
-                         i18n>EC Overwrites</label>
-                </div>
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="ec-overwrites"
+                       type="checkbox"
+                       formControlName="ecOverwrites">
+                <label class="form-check-label"
+                       for="ec-overwrites"
+                       i18n>EC Overwrites</label>
               </div>
             </div>
           </div>
 
         </div>
         <!-- Applications -->
-        <div class="form-group">
+        <div class="form-group row">
           <label i18n
-                 class="col-sm-3 control-label"
+                 class="col-sm-3 col-form-label"
                  for="applications">Applications</label>
           <div class="col-sm-9">
-            <span class="form-control no-border full-height">
-              <cd-select-badges id="applications"
-                                [customBadges]="true"
-                                [customBadgeValidators]="data.applications.validators"
-                                [messages]="data.applications.messages"
-                                [data]="data.applications.selected"
-                                [options]="data.applications.available"
-                                [selectionLimit]="4"
-                                (selection)="appSelection()">
-              </cd-select-badges>
-            </span>
+            <cd-select-badges id="applications"
+                              [customBadges]="true"
+                              [customBadgeValidators]="data.applications.validators"
+                              [messages]="data.applications.messages"
+                              [data]="data.applications.selected"
+                              [options]="data.applications.available"
+                              [selectionLimit]="4"
+                              (selection)="appSelection()">
+            </cd-select-badges>
           </div>
         </div>
 
             <legend i18n>Compression</legend>
 
             <!-- Compression Mode -->
-            <div class="form-group">
+            <div class="form-group row">
               <label i18n
-                     class="control-label col-sm-3"
+                     class="col-form-label col-sm-3"
                      for="mode">Mode</label>
               <div class="col-sm-9">
                 <select class="form-control"
             </div>
             <div *ngIf="hasCompressionEnabled()">
               <!-- Compression algorithm selection -->
-              <div class="form-group"
-                   [ngClass]="{'has-error': form.showError('algorithm', formDir)}">
+              <div class="form-group row"
+                   [ngClass]="{':invalid': form.showError('algorithm', formDir)}">
                 <label i18n
-                       class="control-label col-sm-3"
+                       class="col-form-label col-sm-3"
                        for="algorithm">Algorithm</label>
                 <div class="col-sm-9">
                   <select class="form-control"
               </div>
 
               <!-- Compression min blob size -->
-              <div class="form-group"
-                   [ngClass]="{'has-error': form.showError('minBlobSize', formDir)}">
+              <div class="form-group row"
+                   [ngClass]="{':invalid': form.showError('minBlobSize', formDir)}">
                 <label i18n
-                       class="control-label col-sm-3"
+                       class="col-form-label col-sm-3"
                        for="minBlobSize">Minimum blob size</label>
                 <div class="col-sm-9">
                   <input id="minBlobSize"
                          placeholder="e.g., 128KiB"
                          defaultUnit="KiB"
                          cdDimlessBinary>
-                  <span class="help-block"
+                  <span class="form-text text-muted"
                         *ngIf="form.showError('minBlobSize', formDir, 'min')"
                         i18n>Value should be greater than 0</span>
-                  <span class="help-block"
+                  <span class="form-text text-muted"
                         *ngIf="form.showError('minBlobSize', formDir, 'maximum')"
                         i18n>Value should be less than the maximum blob size</span>
                 </div>
               </div>
 
               <!-- Compression max blob size -->
-              <div class="form-group"
-                   [ngClass]="{'has-error': form.showError('maxBlobSize', formDir)}">
+              <div class="form-group row"
+                   [ngClass]="{':invalid': form.showError('maxBlobSize', formDir)}">
                 <label i18n
-                       class="control-label col-sm-3"
+                       class="col-form-label col-sm-3"
                        for="maxBlobSize">Maximum blob size</label>
                 <div class="col-sm-9">
                   <input id="maxBlobSize"
                          placeholder="e.g., 512KiB"
                          defaultUnit="KiB"
                          cdDimlessBinary>
-                  <span class="help-block"
+                  <span class="form-text text-muted"
                         *ngIf="form.showError('maxBlobSize', formDir, 'min')"
                         i18n>Value should be greater than 0</span>
-                  <span class="help-block"
+                  <span class="form-text text-muted"
                         *ngIf="form.showError('maxBlobSize', formDir, 'minimum')"
                         i18n>Value should be greater than the minimum blob size</span>
                 </div>
               </div>
 
               <!-- Compression ratio -->
-              <div class="form-group"
-                   [ngClass]="{'has-error': form.showError('ratio', formDir)}">
+              <div class="form-group row"
+                   [ngClass]="{':invalid': form.showError('ratio', formDir)}">
                 <label i18n
-                       class="control-label col-sm-3"
+                       class="col-form-label col-sm-3"
                        for="ratio">Ratio</label>
                 <div class="col-sm-9">
                   <input id="ratio"
                          class="form-control"
                          i18n-placeholder
                          placeholder="Compression ratio">
-                  <span class="help-block"
+                  <span class="form-text text-muted"
                         *ngIf="form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')"
                         i18n>Value should be between 0.0 and 1.0</span>
                 </div>
           <legend i18n>Quotas</legend>
 
           <!-- Max Bytes -->
-          <div class="form-group"
-               [ngClass]="{'has-error': form.showError('max_bytes', formDir)}">
-            <label class="control-label col-sm-3"
+          <div class="form-group row">
+            <label class="col-form-label col-sm-3"
                    for="max_bytes">
               <ng-container i18n>Max bytes</ng-container>
               <cd-helper>
           </div>
 
           <!-- Max Objects -->
-          <div class="form-group"
-               [ngClass]="{'has-error': form.showError('max_objects', formDir)}">
-            <label class="control-label col-sm-3"
+          <div class="form-group row">
+            <label class="col-form-label col-sm-3"
                    for="max_objects">
               <ng-container i18n>Max objects</ng-container>
               <cd-helper>
                      name="max_objects"
                      type="number"
                      formControlName="max_objects">
-              <span class="help-block"
+              <span class="invalid-feedback"
                     *ngIf="form.showError('max_objects', formDir, 'min')"
                     i18n>The value should be greater or equal to 0</span>
             </div>
           </cd-rbd-configuration-form>
         </div>
 
-        <div class="form-group has-error">
-          <div class="col-sm-offset-3 col-sm-9"
+        <div class="form-group :invalid">
+          <div class="offset-sm-3 col-sm-9"
                *ngIf="form.hasError('rbdPool')">
             <br>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   i18n>It's not possible to create an RBD pool with '/' in the name.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   i18n>Please change the name or remove 'rbd' from the applications list.</span>
           </div>
         </div>
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            [form]="formDir"
-            type="button"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            (submitAction)="submit()">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button [form]="formDir"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            (submitAction)="submit()">{{ action | titlecase }} {{ resource | upperFirst }}
+          </cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 40a8a25603fbb19d7b0212390f8e332fbed7da56..d7b40d6f1ad6071edb84152edd46a6d86768ad2e 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 ::ng-deep .pg-clean {
   color: $color-bright-green;
index d6d2068a575d1e4e74f7e5c168013d915615dfc4..f54277de110338186d586343851fd34e64e3cedc 100644 (file)
@@ -1,61 +1,62 @@
 <tabset *ngIf="selection.hasSingleSelection">
-  <tab i18n-heading heading="Details">
+  <tab i18n-heading
+       heading="Details">
     <div *ngIf="bucket">
       <table class="table table-striped table-bordered">
         <tbody>
           <tr>
             <td i18n
-                class="bold col-sm-1">Name</td>
-            <td class="col-sm-3">{{ bucket.bid }}</td>
+                class="bold w-25">Name</td>
+            <td class="w-75">{{ bucket.bid }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">ID</td>
+                class="bold">ID</td>
             <td>{{ bucket.id }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Owner</td>
+                class="bold">Owner</td>
             <td>{{ bucket.owner }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Index type</td>
+                class="bold">Index type</td>
             <td>{{ bucket.index_type }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Placement rule</td>
+                class="bold">Placement rule</td>
             <td>{{ bucket.placement_rule }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Marker</td>
+                class="bold">Marker</td>
             <td>{{ bucket.marker }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Maximum marker</td>
+                class="bold">Maximum marker</td>
             <td>{{ bucket.max_marker }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Version</td>
+                class="bold">Version</td>
             <td>{{ bucket.ver }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Master version</td>
+                class="bold">Master version</td>
             <td>{{ bucket.master_ver }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Modification time</td>
+                class="bold">Modification time</td>
             <td>{{ bucket.mtime | cdDate }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Zonegroup</td>
+                class="bold">Zonegroup</td>
             <td>{{ bucket.zonegroup }}</td>
           </tr>
         </tbody>
           <tbody>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Enabled</td>
-              <td class="col-sm-3">{{ bucket.bucket_quota.enabled | booleanText }}</td>
+                  class="bold w-25">Enabled</td>
+              <td class="w-75">{{ bucket.bucket_quota.enabled | booleanText }}</td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum size</td>
+                  class="bold">Maximum size</td>
               <td *ngIf="bucket.bucket_quota.max_size <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="bucket.bucket_quota.max_size > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="bucket.bucket_quota.max_size > -1">
                 {{ bucket.bucket_quota.max_size | dimless }}
               </td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum objects</td>
+                  class="bold">Maximum objects</td>
               <td *ngIf="bucket.bucket_quota.max_objects <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="bucket.bucket_quota.max_objects > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="bucket.bucket_quota.max_objects > -1">
                 {{ bucket.bucket_quota.max_objects }}
               </td>
             </tr>
index 1be3e0f9a25b198e651a13b83809e581f10a3d0a..f4d209d6f670bfee109aed0c26beb9193614f5c4 100644 (file)
@@ -7,22 +7,19 @@
 <div class="col-sm-12 col-lg-6"
      *ngIf="!loading && !error">
   <form name="bucketForm"
-        class="form-horizontal"
         #frm="ngForm"
         [formGroup]="bucketForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
 
+      <div class="card-body">
         <!-- Id -->
-        <div class="form-group"
+        <div class="form-group row"
              *ngIf="editing">
           <label i18n
-                 class="col-sm-3 control-label"
+                 class="col-sm-3 col-form-label"
                  for="id">Id</label>
           <div class="col-sm-9">
             <input id="id"
@@ -35,9 +32,9 @@
         </div>
 
         <!-- Name -->
-        <div class="form-group"
-             [ngClass]="{'has-error': bucketForm.showError('bid', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': bucketForm.showError('bid', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="bid">
             <ng-container i18n>Name</ng-container>
             <span class="required"
                    formControlName="bid"
                    [readonly]="editing"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="bucketForm.showError('bid', frm, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="bucketForm.showError('bid', frm, 'bucketNameInvalid')"
                   i18n>The value is not valid.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="bucketForm.showError('bid', frm, 'bucketNameExists')"
                   i18n>The chosen name is already in use.</span>
           </div>
         </div>
 
         <!-- Owner -->
-        <div class="form-group"
-             [ngClass]="{'has-error': bucketForm.showError('owner', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': bucketForm.showError('owner', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="owner">
             <ng-container i18n>Owner</ng-container>
             <span class="required"></span>
               <option *ngFor="let owner of owners"
                       [value]="owner">{{ owner }}</option>
             </select>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="bucketForm.showError('owner', frm, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            (submitAction)="submit()" [form]="bucketForm"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="submit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="bucketForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 5dc0cfbb8d702b9bd26d5f52e838b38c05ab4624..aa88e5be78c2696440458eb243285c468290c723 100644 (file)
@@ -1,23 +1,23 @@
 <div class="modal-header">
   <h4 i18n="form title|Example: Create Pool@@formTitle"
-      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+      class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="bsModalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
-<form class="form-horizontal"
-      #frm="ngForm"
+<form #frm="ngForm"
       [formGroup]="formGroup"
       novalidate>
   <div class="modal-body">
 
     <!-- Type -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('type', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('type', frm)}">
+      <label class="col-form-label col-sm-3"
              for="type">
         <ng-container i18n>Type</ng-container>
         <span class="required"
           <option *ngFor="let type of types"
                   [value]="type">{{ type }}</option>
         </select>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('type', frm, 'required')"
               i18n>This field is required.</span>
       </div>
     </div>
 
     <!-- Permission -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('perm', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('perm', frm)}">
+      <label class="col-form-label col-sm-3"
              for="perm">
         <ng-container i18n>Permission</ng-container>
         <span class="required"></span>
@@ -67,7 +67,7 @@
             {{ perm }}
           </option>
         </select>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('perm', frm, 'required')"
               i18n>This field is required.</span>
       </div>
 
   </div>
   <div class="modal-footer">
-    <cd-submit-button
-      (submitAction)="onSubmit()"
-      i18n="form action button|Example: Create Pool@@formActionButton"
-      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+    <cd-submit-button (submitAction)="onSubmit()"
+                      i18n="form action button|Example: Create Pool@@formActionButton"
+                      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
     <cd-back-button [back]="bsModalRef.hide"></cd-back-button>
   </div>
 </form>
index da3de2e77de8436a5801191ea682cc40a8e09140..573c53770624cb7ddd959f4509569befa0efd94a 100644 (file)
@@ -6,38 +6,38 @@
         <tbody>
           <tr>
             <td i18n
-                class="bold col-sm-1">Username</td>
-            <td class="col-sm-3">{{ user.uid }}</td>
+                class="bold w-25">Username</td>
+            <td class="w-75">{{ user.uid }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Full name</td>
-            <td class="col-sm-3">{{ user.display_name }}</td>
+                class="bold">Full name</td>
+            <td>{{ user.display_name }}</td>
           </tr>
           <tr *ngIf="user.email.length">
             <td i18n
-                class="bold col-sm-1">Email address</td>
-            <td class="col-sm-3">{{ user.email }}</td>
+                class="bold">Email address</td>
+            <td>{{ user.email }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Suspended</td>
-            <td class="col-sm-3">{{ user.suspended | booleanText }}</td>
+                class="bold">Suspended</td>
+            <td>{{ user.suspended | booleanText }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">System</td>
-            <td class="col-sm-3">{{ user.system | booleanText }}</td>
+                class="bold">System</td>
+            <td>{{ user.system | booleanText }}</td>
           </tr>
           <tr>
             <td i18n
-                class="bold col-sm-1">Maximum buckets</td>
-            <td class="col-sm-3">{{ user.max_buckets }}</td>
+                class="bold">Maximum buckets</td>
+            <td>{{ user.max_buckets }}</td>
           </tr>
           <tr *ngIf="user.subusers && user.subusers.length">
             <td i18n
-                class="bold col-sm-1">Subusers</td>
-            <td class="col-sm-3">
+                class="bold">Subusers</td>
+            <td>
               <div *ngFor="let subuser of user.subusers">
                 {{ subuser.id }} ({{ subuser.permissions }})
               </div>
@@ -45,8 +45,8 @@
           </tr>
           <tr *ngIf="user.caps && user.caps.length">
             <td i18n
-                class="bold col-sm-1">Capabilities</td>
-            <td class="col-sm-3">
+                class="bold">Capabilities</td>
+            <td>
               <div *ngFor="let cap of user.caps">
                 {{ cap.type }} ({{ cap.perm }})
               </div>
           <tbody>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Enabled</td>
-              <td class="col-sm-3">{{ user.user_quota.enabled | booleanText }}</td>
+                  class="bold w-25">Enabled</td>
+              <td class="w-75">{{ user.user_quota.enabled | booleanText }}</td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum size</td>
-              <td *ngIf="!user.user_quota.enabled"
-                  class="col-sm-3">-</td>
+                  class="bold">Maximum size</td>
+              <td *ngIf="!user.user_quota.enabled">-</td>
               <td *ngIf="user.user_quota.enabled && user.user_quota.max_size <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="user.user_quota.enabled && user.user_quota.max_size > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="user.user_quota.enabled && user.user_quota.max_size > -1">
                 {{ user.user_quota.max_size | dimlessBinary }}
               </td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum objects</td>
-              <td *ngIf="!user.user_quota.enabled"
-                  class="col-sm-3">-</td>
+                  class="bold">Maximum objects</td>
+              <td *ngIf="!user.user_quota.enabled">-</td>
               <td *ngIf="user.user_quota.enabled && user.user_quota.max_objects <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="user.user_quota.enabled && user.user_quota.max_objects > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="user.user_quota.enabled && user.user_quota.max_objects > -1">
                 {{ user.user_quota.max_objects }}
               </td>
             </tr>
           <tbody>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Enabled</td>
-              <td class="col-sm-3">{{ user.bucket_quota.enabled | booleanText }}</td>
+                  class="bold w-25">Enabled</td>
+              <td class="w-75">{{ user.bucket_quota.enabled | booleanText }}</td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum size</td>
-              <td *ngIf="!user.bucket_quota.enabled"
-                  class="col-sm-3">-</td>
+                  class="bold">Maximum size</td>
+              <td *ngIf="!user.bucket_quota.enabled">-</td>
               <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size > -1">
                 {{ user.bucket_quota.max_size | dimlessBinary }}
               </td>
             </tr>
             <tr>
               <td i18n
-                  class="bold col-sm-1">Maximum objects</td>
-              <td *ngIf="!user.bucket_quota.enabled"
-                  class="col-sm-3">-</td>
+                  class="bold">Maximum objects</td>
+              <td *ngIf="!user.bucket_quota.enabled">-</td>
               <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects <= -1"
-                  i18n
-                  class="col-sm-3">Unlimited</td>
-              <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects > -1"
-                  class="col-sm-3">
+                  i18n>Unlimited</td>
+              <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects > -1">
                 {{ user.bucket_quota.max_objects }}
               </td>
             </tr>
         <div class="btn-group"
              dropdown>
           <button type="button"
-                  class="btn btn-sm btn-primary"
+                  class="btn btn-secondary"
                   [disabled]="!keysSelection.hasSingleSelection"
                   (click)="showKeyModal()">
             <i [ngClass]="[icons.show]"></i>
index b7dda481c5158cdd195b43c210f2060f42a0971e..2c191a72e4c5be21ab07a6032d73badd766d413f 100644 (file)
@@ -6,21 +6,18 @@
 
 <div class="col-sm-12 col-lg-6"
      *ngIf="!loading && !error">
-  <form class="form-horizontal"
-        #frm="ngForm"
+  <form #frm="ngForm"
         [formGroup]="userForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
 
+      <div class="card-body">
         <!-- Username -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('uid', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('uid', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="uid">
             <ng-container i18n>Username</ng-container>
             <span class="required"
                    formControlName="uid"
                    [readonly]="editing"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('uid', frm, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('uid', frm, 'notUnique')"
                   i18n>The chosen user ID is already in use.</span>
           </div>
         </div>
 
         <!-- Full name -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('display_name', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('display_name', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="display_name">
             <ng-container i18n>Full name</ng-container>
             <span class="required"
                    class="form-control"
                    type="text"
                    formControlName="display_name">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('display_name', frm, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Email address -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('email', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('email', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="email"
                  i18n>Email address</label>
           <div class="col-sm-9">
                    class="form-control"
                    type="text"
                    formControlName="email">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('email', frm, 'email')"
                   i18n>This is not a valid email address.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('email', frm, 'notUnique')"
                   i18n>The chosen email address is already in use.</span>
           </div>
         </div>
 
         <!-- Max. buckets -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('max_buckets', frm)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('max_buckets', frm)}">
+          <label class="col-form-label col-sm-3"
                  for="max_buckets">
             <ng-container i18n>Max. buckets</ng-container>
             <span class="required"></span>
                    class="form-control"
                    type="number"
                    formControlName="max_buckets">
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('max_buckets', frm, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('max_buckets', frm, 'min')"
                   i18n>The entered value must be >= 0.</span>
           </div>
         </div>
 
         <!-- Suspended -->
-        <div class="form-group">
-          <div class="col-sm-offset-3 col-sm-9">
-            <div class="checkbox checkbox-primary">
-              <input id="suspended"
+        <div class="form-group row">
+          <div class="offset-sm-3 col-sm-9">
+            <div class="form-check abc-checkbox abc-checkbox-primary">
+              <input class="form-check-input"
+                     id="suspended"
                      type="checkbox"
                      formControlName="suspended">
-              <label for="suspended"
+              <label class="form-check-label"
+                     for="suspended"
                      i18n>Suspended</label>
             </div>
           </div>
           <legend i18n>S3 key</legend>
 
           <!-- Auto-generate key -->
-          <div class="form-group">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="generate_key"
+          <div class="form-group row">
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="generate_key"
                        type="checkbox"
                        formControlName="generate_key">
-                <label for="generate_key"
+                <label class="form-check-label"
+                       for="generate_key"
                        i18n>Auto-generate key</label>
               </div>
             </div>
           </div>
 
           <!-- Access key -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('access_key', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('access_key', frm)}"
                *ngIf="!editing && !userForm.getValue('generate_key')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="access_key">
               <ng-container i18n>Access key</ng-container>
               <span class="required"></span>
                        class="form-control"
                        type="password"
                        formControlName="access_key">
-                <span class="input-group-btn">
+                <span class="input-group-append">
                   <button type="button"
-                          class="btn btn-default"
+                          class="btn btn-light"
                           cdPasswordButton="access_key">
                   </button>
                   <button type="button"
-                          class="btn btn-default"
+                          class="btn btn-light"
                           cdCopy2ClipboardButton="access_key">
                   </button>
                 </span>
               </div>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('access_key', frm, 'required')"
                     i18n>This field is required.</span>
             </div>
           </div>
 
           <!-- Secret key -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('secret_key', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('secret_key', frm)}"
                *ngIf="!editing && !userForm.getValue('generate_key')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="secret_key">
               <ng-container i18n>Secret key</ng-container>
               <span class="required"></span>
                        class="form-control"
                        type="password"
                        formControlName="secret_key">
-                <span class="input-group-btn">
+                <span class="input-group-append">
                   <button type="button"
-                          class="btn btn-default"
+                          class="btn btn-light"
                           cdPasswordButton="secret_key">
                   </button>
                   <button type="button"
-                          class="btn btn-default"
+                          class="btn btn-light"
                           cdCopy2ClipboardButton="secret_key">
                   </button>
                 </span>
               </div>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('secret_key', frm, 'required')"
                     i18n>This field is required.</span>
             </div>
         <!-- Subusers -->
         <fieldset *ngIf="editing">
           <legend i18n>Subusers</legend>
-
-          <div class="col-sm-offset-3 col-sm-9">
-            <span *ngIf="subusers.length === 0"
-                  class="form-control no-border">
-              <span class="text-muted"
-                    i18n>There are no subusers.</span>
-            </span>
-
-            <span *ngFor="let subuser of subusers; let i=index;">
-              <div class="input-group">
-                <span class="input-group-addon">
-                  <i class="icon-prepend {{ icons.user }}"></i>
-                </span>
-                <input type="text"
-                       class="form-control"
-                       value="{{ subuser.id }}"
-                       readonly>
-                <span class="input-group-addon"
-                      style="border-left: 0; border-right: 0;">
-                  <i class="icon-prepend {{ icons.share }}"></i>
-                </span>
-                <input type="text"
-                       class="form-control"
-                       value="{{ ('full-control' === subuser.permissions) ? 'full' : subuser.permissions }}"
-                       readonly>
-                <span class="input-group-btn">
-                  <button type="button"
-                          class="btn btn-default tc_showSubuserButton"
-                          i18n-tooltip
-                          tooltip="Edit"
-                          (click)="showSubuserModal(i)">
-                    <i [ngClass]="[icons.edit]"></i>
-                  </button>
+          <div class="row">
+            <div class="offset-sm-3 col-sm-9">
+              <span *ngIf="subusers.length === 0"
+                    class="form-control no-border">
+                <span class="form-text text-muted"
+                      i18n>There are no subusers.</span>
+              </span>
+
+              <span *ngFor="let subuser of subusers; let i=index;">
+                <div class="input-group">
+                  <div class="input-group-prepend">
+                    <span class="input-group-text">
+                      <i class="{{ icons.user }}"></i>
+                    </span>
+                  </div>
+                  <input type="text"
+                         class="form-control"
+                         value="{{ subuser.id }}"
+                         readonly>
+                  <div class="input-group-prepend"
+                       style="border-left: 0; border-right: 0;">
+                    <span class="input-group-text">
+                      <i class="{{ icons.share }}"></i>
+                    </span>
+                  </div>
+                  <input type="text"
+                         class="form-control"
+                         value="{{ ('full-control' === subuser.permissions) ? 'full' : subuser.permissions }}"
+                         readonly>
+                  <span class="input-group-append">
+                    <button type="button"
+                            class="btn btn-light tc_showSubuserButton"
+                            i18n-tooltip
+                            tooltip="Edit"
+                            (click)="showSubuserModal(i)">
+                      <i [ngClass]="[icons.edit]"></i>
+                    </button>
+                    <button type="button"
+                            class="btn btn-light tc_deleteSubuserButton"
+                            i18n-tooltip
+                            tooltip="Delete"
+                            (click)="deleteSubuser(i)">
+                      <i [ngClass]="[icons.destroy]"></i>
+                    </button>
+                  </span>
+                </div>
+                <span class="form-text text-muted"></span>
+              </span>
+
+              <div class="row">
+                <div class="col-12">
                   <button type="button"
-                          class="btn btn-default tc_deleteSubuserButton"
-                          i18n-tooltip
-                          tooltip="Delete"
-                          (click)="deleteSubuser(i)">
-                    <i [ngClass]="[icons.destroy]"></i>
+                          class="btn btn-light float-right tc_addSubuserButton"
+                          (click)="showSubuserModal()">
+                    <i [ngClass]="[icons.add]"></i>
+                    <ng-container i18n>{{ actionLabels.CREATE | titlecase }}
+                      {{ subuserLabel | upperFirst }}</ng-container>
                   </button>
-                </span>
+                </div>
               </div>
               <span class="help-block"></span>
-            </span>
-
-            <span class="form-control no-border">
-              <button type="button"
-                      class="btn btn-sm btn-default btn-label pull-right tc_addSubuserButton"
-                      (click)="showSubuserModal()">
-                <i [ngClass]="[icons.add, icons.width]"></i>
-                <ng-container i18n>{{ actionLabels.CREATE | titlecase }} {{ subuserLabel | upperFirst }}</ng-container>
-              </button>
-            </span>
+            </div>
           </div>
         </fieldset>
 
           <legend i18n>Keys</legend>
 
           <!-- S3 keys -->
-          <label class="col-sm-3 control-label"
-                 i18n>S3</label>
-          <div class="col-sm-9">
-            <span *ngIf="s3Keys.length === 0"
-                  class="form-control no-border">
-              <span class="text-muted"
-                    i18n>There are no keys.</span>
-            </span>
-
-            <span *ngFor="let key of s3Keys; let i=index;">
-              <div class="input-group">
-                <span class="input-group-addon">
-                  <i class="icon-prepend {{ icons.key }}"></i>
-                </span>
-                <input type="text"
-                       class="form-control"
-                       value="{{ key.user }}"
-                       readonly>
-                <span class="input-group-btn">
-                  <button type="button"
-                          class="btn btn-default tc_showS3KeyButton"
-                          i18n-tooltip
-                          tooltip="Show"
-                          (click)="showS3KeyModal(i)">
-                    <i [ngClass]="[icons.show]"></i>
-                  </button>
+          <div class="form-group row">
+            <label class="col-sm-3 col-form-label"
+                   i18n>S3</label>
+            <div class="col-sm-9">
+              <span *ngIf="s3Keys.length === 0"
+                    class="form-control no-border">
+                <span class="form-text text-muted"
+                      i18n>There are no keys.</span>
+              </span>
+
+              <span *ngFor="let key of s3Keys; let i=index;">
+                <div class="input-group">
+                  <div class="input-group-prepend">
+                    <div class="input-group-text">
+                      <i class="{{ icons.key }}"></i>
+                    </div>
+                  </div>
+                  <input type="text"
+                         class="form-control"
+                         value="{{ key.user }}"
+                         readonly>
+                  <span class="input-group-append">
+                    <button type="button"
+                            class="btn btn-light tc_showS3KeyButton"
+                            i18n-tooltip
+                            tooltip="Show"
+                            (click)="showS3KeyModal(i)">
+                      <i [ngClass]="[icons.show]"></i>
+                    </button>
+                    <button type="button"
+                            class="btn btn-light tc_deleteS3KeyButton"
+                            i18n-tooltip
+                            tooltip="Delete"
+                            (click)="deleteS3Key(i)">
+                      <i [ngClass]="[icons.destroy]"></i>
+                    </button>
+                  </span>
+                </div>
+                <span class="form-text text-muted"></span>
+              </span>
+
+              <div class="row">
+                <div class="col-12">
                   <button type="button"
-                          class="btn btn-default tc_deleteS3KeyButton"
-                          i18n-tooltip
-                          tooltip="Delete"
-                          (click)="deleteS3Key(i)">
-                    <i [ngClass]="[icons.destroy]"></i>
+                          class="btn btn-light float-right tc_addS3KeyButton"
+                          (click)="showS3KeyModal()">
+                    <i [ngClass]="[icons.add]"></i>
+                    <ng-container i18n>{{ actionLabels.CREATE | titlecase }}
+                      {{ s3keyLabel | upperFirst }}</ng-container>
                   </button>
-                </span>
+                </div>
               </div>
+
               <span class="help-block"></span>
-            </span>
+            </div>
 
-            <span class="form-control no-border">
-              <button type="button"
-                      class="btn btn-sm btn-default btn-label pull-right tc_addS3KeyButton"
-                      (click)="showS3KeyModal()">
-                <i [ngClass]="[icons.add, icons.width]"></i>
-                <ng-container i18n>{{ actionLabels.CREATE | titlecase }} {{ s3keyLabel | upperFirst }}</ng-container>
-              </button>
-            </span>
             <hr>
           </div>
 
           <!-- Swift keys -->
-          <label class="col-sm-3 control-label"
-                 i18n>Swift</label>
-          <div class="col-sm-9">
-            <span *ngIf="swiftKeys.length === 0"
-                  class="form-control no-border">
-              <span class="text-muted"
-                    i18n>There are no keys.</span>
-            </span>
+          <div class="form-group row">
+            <label class="col-sm-3 col-form-label"
+                   i18n>Swift</label>
 
-            <span *ngFor="let key of swiftKeys; let i=index;">
-              <div class="input-group">
-                <span class="input-group-addon">
-                  <i class="icon-prepend {{ icons.key }}"></i>
-                </span>
-                <input type="text"
-                       class="form-control"
-                       value="{{ key.user }}"
-                       readonly>
-                <span class="input-group-btn">
-                  <button type="button"
-                          class="btn btn-default tc_showSwiftKeyButton"
-                          i18n-tooltip
-                          tooltip="Show"
-                          (click)="showSwiftKeyModal(i)">
-                    <i [ngClass]="[icons.show]"></i>
-                  </button>
-                </span>
-              </div>
-              <span class="help-block"></span>
-            </span>
+            <div class="col-sm-9">
+              <span *ngIf="swiftKeys.length === 0"
+                    class="form-control no-border">
+                <span class="form-text text-muted"
+                      i18n>There are no keys.</span>
+              </span>
+
+              <span *ngFor="let key of swiftKeys; let i=index;">
+                <div class="input-group">
+                  <div class="input-group-prepend">
+                    <span class="input-group-text">
+                      <i class="{{ icons.key }}"></i>
+                    </span>
+                  </div>
+                  <input type="text"
+                         class="form-control"
+                         value="{{ key.user }}"
+                         readonly>
+                  <span class="input-group-append">
+                    <button type="button"
+                            class="btn btn-light tc_showSwiftKeyButton"
+                            i18n-tooltip
+                            tooltip="Show"
+                            (click)="showSwiftKeyModal(i)">
+                      <i [ngClass]="[icons.show]"></i>
+                    </button>
+                  </span>
+                </div>
+                <span class="form-text text-muted"></span>
+              </span>
+            </div>
           </div>
         </fieldset>
 
         <fieldset *ngIf="editing">
           <legend i18n>Capabilities</legend>
 
-          <div class="col-sm-offset-3 col-sm-9">
-            <span *ngIf="capabilities.length === 0"
-                  class="form-control no-border">
-              <span class="text-muted"
-                    i18n>There are no capabilities.</span>
-            </span>
-
-            <span *ngFor="let cap of capabilities; let i=index;">
-              <div class="input-group">
-                <span class="input-group-addon">
-                  <i class="icon-prepend {{ icons.share }}"></i>
-                </span>
-                <input type="text"
-                       class="form-control"
-                       value="{{ cap.type }}:{{ cap.perm }}"
-                       readonly>
-                <span class="input-group-btn">
+          <div class="form-group row">
+            <div class="offset-sm-3 col-sm-9">
+              <span *ngIf="capabilities.length === 0"
+                    class="form-control no-border">
+                <span class="form-text text-muted"
+                      i18n>There are no capabilities.</span>
+              </span>
+
+              <span *ngFor="let cap of capabilities; let i=index;">
+                <div class="input-group">
+                  <span class="input-group-prepend">
+                    <div class="input-group-text">
+                      <i class="{{ icons.share }}"></i>
+                    </div>
+                  </span>
+                  <input type="text"
+                         class="form-control"
+                         value="{{ cap.type }}:{{ cap.perm }}"
+                         readonly>
+                  <span class="input-group-append">
+                    <button type="button"
+                            class="btn btn-light tc_editCapButton"
+                            i18n-tooltip
+                            tooltip="Edit"
+                            (click)="showCapabilityModal(i)">
+                      <i [ngClass]="[icons.edit]"></i>
+                    </button>
+                    <button type="button"
+                            class="btn btn-light tc_deleteCapButton"
+                            i18n-tooltip
+                            tooltip="Delete"
+                            (click)="deleteCapability(i)">
+                      <i [ngClass]="[icons.destroy]"></i>
+                    </button>
+                  </span>
+                </div>
+                <span class="form-text text-muted"></span>
+              </span>
+
+              <div class="row">
+                <div class="col-12">
                   <button type="button"
-                          class="btn btn-default tc_editCapButton"
-                          i18n-tooltip
-                          tooltip="Edit"
-                          (click)="showCapabilityModal(i)">
-                    <i [ngClass]="[icons.edit]"></i>
+                          class="btn btn-light float-right tc_addCapButton"
+                          (click)="showCapabilityModal()">
+                    <i [ngClass]="[icons.add]"></i>
+                    <ng-container i18n>{{ actionLabels.ADD | titlecase }}
+                      {{ capabilityLabel | upperFirst }}</ng-container>
                   </button>
-                  <button type="button"
-                          class="btn btn-default tc_deleteCapButton"
-                          i18n-tooltip
-                          tooltip="Delete"
-                          (click)="deleteCapability(i)">
-                    <i [ngClass]="[icons.destroy]"></i>
-                  </button>
-                </span>
+                </div>
               </div>
               <span class="help-block"></span>
-            </span>
-
-            <span class="form-control no-border">
-              <button type="button"
-                      class="btn btn-sm btn-default btn-label pull-right tc_addCapButton"
-                      (click)="showCapabilityModal()">
-                <i [ngClass]="[icons.add, icons.width]"></i>
-                <ng-container i18n>{{ actionLabels.ADD | titlecase }} {{ capabilityLabel | upperFirst }}</ng-container>
-              </button>
-            </span>
+            </div>
           </div>
         </fieldset>
 
           <legend i18n>User quota</legend>
 
           <!-- Enabled -->
-          <div class="form-group">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="user_quota_enabled"
+          <div class="form-group row">
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="user_quota_enabled"
                        type="checkbox"
                        formControlName="user_quota_enabled">
-                <label for="user_quota_enabled"
+                <label class="form-check-label"
+                       for="user_quota_enabled"
                        i18n>Enabled</label>
               </div>
             </div>
           </div>
 
           <!-- Unlimited size -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="userForm.controls.user_quota_enabled.value">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="user_quota_max_size_unlimited"
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="user_quota_max_size_unlimited"
                        type="checkbox"
                        formControlName="user_quota_max_size_unlimited">
-                <label for="user_quota_max_size_unlimited"
+                <label class="form-check-label"
+                       for="user_quota_max_size_unlimited"
                        i18n>Unlimited size</label>
               </div>
             </div>
           </div>
 
           <!-- Maximum size -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('user_quota_max_size', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('user_quota_max_size', frm)}"
                *ngIf="userForm.controls.user_quota_enabled.value && !userForm.getValue('user_quota_max_size_unlimited')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="user_quota_max_size">
               <ng-container i18n>Max. size</ng-container>
               <span class="required"></span>
                      type="text"
                      formControlName="user_quota_max_size"
                      cdDimlessBinary>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('user_quota_max_size', frm, 'required')"
                     i18n>This field is required.</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('user_quota_max_size', frm, 'quotaMaxSize')"
                     i18n>The value is not valid.</span>
             </div>
           </div>
 
           <!-- Unlimited objects -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="userForm.controls.user_quota_enabled.value">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="user_quota_max_objects_unlimited"
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="user_quota_max_objects_unlimited"
                        type="checkbox"
                        formControlName="user_quota_max_objects_unlimited">
-                <label for="user_quota_max_objects_unlimited"
+                <label class="form-check-label"
+                       for="user_quota_max_objects_unlimited"
                        i18n>Unlimited objects</label>
               </div>
             </div>
           </div>
 
           <!-- Maximum objects -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('user_quota_max_objects', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('user_quota_max_objects', frm)}"
                *ngIf="userForm.controls.user_quota_enabled.value && !userForm.getValue('user_quota_max_objects_unlimited')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="user_quota_max_objects">
               <ng-container i18n>Max. objects</ng-container>
               <span class="required"></span>
                      class="form-control"
                      type="number"
                      formControlName="user_quota_max_objects">
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('user_quota_max_objects', frm, 'required')"
                     i18n>This field is required.</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('user_quota_max_objects', frm, 'min')"
                     i18n>The entered value must be >= 0.</span>
             </div>
           <legend i18n>Bucket quota</legend>
 
           <!-- Enabled -->
-          <div class="form-group">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="bucket_quota_enabled"
+          <div class="form-group row">
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="bucket_quota_enabled"
                        type="checkbox"
                        formControlName="bucket_quota_enabled">
-                <label for="bucket_quota_enabled"
+                <label class="form-check-label"
+                       for="bucket_quota_enabled"
                        i18n>Enabled</label>
               </div>
             </div>
           </div>
 
           <!-- Unlimited size -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="userForm.controls.bucket_quota_enabled.value">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="bucket_quota_max_size_unlimited"
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="bucket_quota_max_size_unlimited"
                        type="checkbox"
                        formControlName="bucket_quota_max_size_unlimited">
-                <label for="bucket_quota_max_size_unlimited"
+                <label class="form-check-label"
+                       for="bucket_quota_max_size_unlimited"
                        i18n>Unlimited size</label>
               </div>
             </div>
           </div>
 
           <!-- Maximum size -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('bucket_quota_max_size', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('bucket_quota_max_size', frm)}"
                *ngIf="userForm.controls.bucket_quota_enabled.value && !userForm.getValue('bucket_quota_max_size_unlimited')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="bucket_quota_max_size">
               <ng-container i18n>Max. size</ng-container>
               <span class="required"></span>
                      type="text"
                      formControlName="bucket_quota_max_size"
                      cdDimlessBinary>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('bucket_quota_max_size', frm, 'required')"
                     i18n>This field is required.</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('bucket_quota_max_size', frm, 'quotaMaxSize')"
                     i18n>The value is not valid.</span>
             </div>
           </div>
 
           <!-- Unlimited objects -->
-          <div class="form-group"
+          <div class="form-group row"
                *ngIf="userForm.controls.bucket_quota_enabled.value">
-            <div class="col-sm-offset-3 col-sm-9">
-              <div class="checkbox checkbox-primary">
-                <input id="bucket_quota_max_objects_unlimited"
+            <div class="offset-sm-3 col-sm-9">
+              <div class="form-check abc-checkbox abc-checkbox-primary">
+                <input class="form-check-input"
+                       id="bucket_quota_max_objects_unlimited"
                        type="checkbox"
                        formControlName="bucket_quota_max_objects_unlimited">
-                <label for="bucket_quota_max_objects_unlimited"
+                <label class="form-check-label"
+                       for="bucket_quota_max_objects_unlimited"
                        i18n>Unlimited objects</label>
               </div>
             </div>
           </div>
 
           <!-- Maximum objects -->
-          <div class="form-group"
-               [ngClass]="{'has-error': userForm.showError('bucket_quota_max_objects', frm)}"
+          <div class="form-group row"
+               [ngClass]="{':invalid': userForm.showError('bucket_quota_max_objects', frm)}"
                *ngIf="userForm.controls.bucket_quota_enabled.value && !userForm.getValue('bucket_quota_max_objects_unlimited')">
-            <label class="control-label col-sm-3"
+            <label class="col-form-label col-sm-3"
                    for="bucket_quota_max_objects">
               <ng-container i18n>Max. objects</ng-container>
               <span class="required"></span>
                      class="form-control"
                      type="number"
                      formControlName="bucket_quota_max_objects">
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'required')"
                     i18n>This field is required.</span>
-              <span class="help-block"
+              <span class="form-text text-muted"
                     *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'min')"
                     i18n>The entered value must be >= 0.</span>
             </div>
         </fieldset>
       </div>
 
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            (submitAction)="onSubmit()"
-            [form]="userForm"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="onSubmit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="userForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 7ac12c1fea7a3284dcc60eb57e2eb385a4c1e9c4..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,6 +0,0 @@
-@import '../../../../defaults';
-
-form .input-group-addon {
-  color: $color-rgw-icon !important;
-  background-color: transparent;
-}
index 0805c5e8711870cb0474e9e34fc9c71c5d2bd210..f9cecf0bada62643f39947ca69a12a9e81db0be8 100644 (file)
@@ -1,23 +1,23 @@
 <div class="modal-header">
   <h4 i18n="form title|Example: Create Pool@@formTitle"
-      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+      class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="bsModalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
-<form class="form-horizontal"
-      #frm="ngForm"
+<form #frm="ngForm"
       [formGroup]="formGroup"
       novalidate>
   <div class="modal-body">
 
     <!-- Username -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('user', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('user', frm)}">
+      <label class="col-form-label col-sm-3"
              for="user">
         <ng-container i18n>Username</ng-container>
         <span class="required"
           <option *ngFor="let userCandidate of userCandidates"
                   [value]="userCandidate">{{ userCandidate }}</option>
         </select>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('user', frm, 'required')"
               i18n>This field is required.</span>
       </div>
     </div>
 
     <!-- Auto-generate key -->
-    <div class="form-group"
+    <div class="form-group row"
          *ngIf="!viewing">
-      <div class="col-sm-offset-3 col-sm-9">
-        <div class="checkbox checkbox-primary">
-          <input id="generate_key"
+      <div class="offset-sm-3 col-sm-9">
+        <div class="form-check abc-checkbox abc-checkbox-primary">
+          <input class="form-check-input"
+                 id="generate_key"
                  type="checkbox"
                  formControlName="generate_key">
-          <label for="generate_key"
+          <label class="form-check-label"
+                 for="generate_key"
                  i18n>Auto-generate key</label>
         </div>
       </div>
     </div>
 
     <!-- Access key -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('access_key', frm)}"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('access_key', frm)}"
          *ngIf="!formGroup.getValue('generate_key')">
-      <label class="control-label col-sm-3"
+      <label class="col-form-label col-sm-3"
              for="access_key">
         <ng-container i18n>Access key</ng-container>
         <span class="required"
                  type="password"
                  [readonly]="viewing"
                  formControlName="access_key">
-          <span class="input-group-btn">
+          <span class="input-group-append">
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdPasswordButton="access_key">
             </button>
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdCopy2ClipboardButton="access_key">
             </button>
           </span>
         </div>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('access_key', frm, 'required')"
               i18n>This field is required.</span>
       </div>
     </div>
 
     <!-- Secret key -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('secret_key', frm)}"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('secret_key', frm)}"
          *ngIf="!formGroup.getValue('generate_key')">
-      <label class="control-label col-sm-3"
+      <label class="col-form-label col-sm-3"
              for="secret_key">
         <ng-container i18n>Secret key</ng-container>
         <span class="required"
                  type="password"
                  [readonly]="viewing"
                  formControlName="secret_key">
-          <span class="input-group-btn">
+          <span class="input-group-append">
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdPasswordButton="secret_key">
             </button>
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdCopy2ClipboardButton="secret_key">
             </button>
           </span>
         </div>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('secret_key', frm, 'required')"
               i18n>This field is required.</span>
       </div>
 
   </div>
   <div class="modal-footer">
-    <cd-submit-button
-      *ngIf="!viewing"
-      (submitAction)="onSubmit()"
-      i18n="form action button|Example: Create Pool@@formActionButton"
-      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+    <cd-submit-button *ngIf="!viewing"
+                      (submitAction)="onSubmit()"
+                      i18n="form action button|Example: Create Pool@@formActionButton"
+                      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
     <cd-back-button [back]="bsModalRef.hide"></cd-back-button>
   </div>
 </form>
index 2f9a7d69680de675423cc225a3780ed5da3fc100..c6be54f62cf58b37e1aa50d45f5c3c386a0963f7 100644 (file)
@@ -1,23 +1,22 @@
 <div class="modal-header">
   <h4 i18n="form title|Example: Create Pool@@formTitle"
-      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+      class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="bsModalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
-<form class="form-horizontal"
-      #frm="ngForm"
+<form #frm="ngForm"
       [formGroup]="formGroup"
       novalidate>
   <div class="modal-body">
 
     <!-- Username -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('uid', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('uid', frm)}">
+      <label class="col-form-label col-sm-3"
              for="uid"
              i18n>Username</label>
       <div class="col-sm-9">
@@ -30,9 +29,9 @@
     </div>
 
     <!-- Subuser -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('subuid', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('subuid', frm)}">
+      <label class="col-form-label col-sm-3"
              for="subuid">
         <ng-container i18n>Subuser</ng-container>
         <span class="required"
                formControlName="subuid"
                [readonly]="editing"
                autofocus>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('subuid', frm, 'required')"
               i18n>This field is required.</span>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('subuid', frm, 'subuserIdExists')"
               i18n>The chosen subuser ID is already in use.</span>
       </div>
     </div>
 
     <!-- Permission -->
-    <div class="form-group"
-         [ngClass]="{'has-error': formGroup.showError('perm', frm)}">
-      <label class="control-label col-sm-3"
+    <div class="form-group row"
+         [ngClass]="{':invalid': formGroup.showError('perm', frm)}">
+      <label class="col-form-label col-sm-3"
              for="perm">
         <ng-container i18n>Permission</ng-container>
         <span class="required"></span>
@@ -78,7 +77,7 @@
           <option i18n
                   value="full-control">full</option>
         </select>
-        <span class="help-block"
+        <span class="form-text text-muted"
               *ngIf="formGroup.showError('perm', frm, 'required')"
               i18n>This field is required.</span>
       </div>
       <legend i18n>Swift key</legend>
 
       <!-- Auto-generate key -->
-      <div class="form-group">
-        <div class="col-sm-offset-3 col-sm-9">
-          <div class="checkbox checkbox-primary">
-            <input id="generate_secret"
+      <div class="form-group row">
+        <div class="offset-sm-3 col-sm-9">
+          <div class="form-check abc-checkbox abc-checkbox-primary">
+            <input class="form-check-input"
+                   id="generate_secret"
                    type="checkbox"
                    formControlName="generate_secret">
-            <label for="generate_secret"
+            <label class="form-check-label"
+                   for="generate_secret"
                    i18n>Auto-generate secret</label>
           </div>
         </div>
       </div>
 
       <!-- Secret key -->
-      <div class="form-group"
-           [ngClass]="{'has-error': formGroup.showError('secret_key', frm)}"
+      <div class="form-group row"
+           [ngClass]="{':invalid': formGroup.showError('secret_key', frm)}"
            *ngIf="!editing && !formGroup.getValue('generate_secret')">
-        <label class="control-label col-sm-3"
+        <label class="col-form-label col-sm-3"
                for="secret_key">
           <ng-container i18n>Secret key</ng-container>
           <span class="required"></span>
                    class="form-control"
                    type="password"
                    formControlName="secret_key">
-            <span class="input-group-btn">
+            <span class="input-group-append">
               <button type="button"
-                      class="btn btn-default"
+                      class="btn btn-light"
                       cdPasswordButton="secret_key">
               </button>
               <button type="button"
-                      class="btn btn-default"
+                      class="btn btn-light"
                       cdCopy2ClipboardButton="secret_key">
               </button>
             </span>
           </div>
-          <span class="help-block"
+          <span class="form-text text-muted"
                 *ngIf="formGroup.showError('secret_key', frm, 'required')"
                 i18n>This field is required.</span>
         </div>
 
   </div>
   <div class="modal-footer">
-    <cd-submit-button
-      (submitAction)="onSubmit()"
-      i18n="form action button|Example: Create Pool@@formActionButton"
-      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+    <cd-submit-button (submitAction)="onSubmit()"
+                      i18n="form action button|Example: Create Pool@@formActionButton"
+                      [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
     <cd-back-button [back]="bsModalRef.hide"></cd-back-button>
   </div>
 </form>
index ce973cbd819c9d3445e77c9d0e6091ee875c7408..284b20328dfe74395eff06412cb1d8f85ed9873d 100644 (file)
@@ -1,20 +1,20 @@
 <div class="modal-header">
   <h4 i18n="form title|Example: Create Pool@@formTitle"
-      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+      class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
+
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="bsModalRef.hide()">
     <span aria-hidden="true">&times;</span>
   </button>
 </div>
 <div class="modal-body">
-  <form class="form-horizontal"
-        novalidate>
+  <form novalidate>
 
     <!-- Username -->
-    <div class="form-group">
-      <label class="control-label col-sm-3"
+    <div class="form-group row">
+      <label class="col-form-label col-sm-3"
              for="user"
              i18n>Username</label>
       <div class="col-sm-9">
@@ -28,8 +28,8 @@
     </div>
 
     <!-- Secret key -->
-    <div class="form-group">
-      <label class="control-label col-sm-3"
+    <div class="form-group row">
+      <label class="col-form-label col-sm-3"
              for="secret_key"
              i18n>Secret key</label>
       <div class="col-sm-9">
                  type="password"
                  [(ngModel)]="secret_key"
                  [readonly]="true">
-          <span class="input-group-btn">
+          <span class="input-group-append">
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdPasswordButton="secret_key">
             </button>
             <button type="button"
-                    class="btn btn-default"
+                    class="btn btn-light"
                     cdCopy2ClipboardButton="secret_key">
             </button>
           </span>
index 8850fc71f93cf6f0c9a8627d8d8ec4f69b76739b..38d9bde31a3ef9b61267feefca5649b68f97e0c3 100644 (file)
@@ -2,8 +2,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { FormsModule } from '@angular/forms';
 import { RouterTestingModule } from '@angular/router/testing';
 
-import { ToastModule } from 'ng2-toastr';
 import { BsModalRef } from 'ngx-bootstrap/modal';
+import { ToastrModule } from 'ngx-toastr';
 
 import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
 import { SharedModule } from '../../../shared/shared.module';
@@ -15,7 +15,7 @@ describe('RgwUserSwiftKeyModalComponent', () => {
 
   configureTestBed({
     declarations: [RgwUserSwiftKeyModalComponent],
-    imports: [ToastModule.forRoot(), FormsModule, SharedModule, RouterTestingModule],
+    imports: [ToastrModule.forRoot(), FormsModule, SharedModule, RouterTestingModule],
     providers: [BsModalRef, i18nProviders]
   });
 
index d0b9196032fb105ab3fb579ce0f4c0829578a1e3..863ff2d78c9fd3858e7b27453ffef17af2a345f2 100644 (file)
@@ -4,9 +4,9 @@
     <div class="col-sm-6 hidden-xs">
       <img src="assets/Ceph_Logo_Stacked_RGB_White_120411_fa_256x256.png"
            alt="Ceph"
-           class="pull-right">
+           class="float-right">
     </div>
-    <div class="col-xs-10 col-sm-4 col-lg-3 col-xs-offset-1 col-sm-offset-0 col-md-offset-0 col-lg-offset-0">
+    <div class="col-10 col-sm-4 col-lg-3 offset-1 offset-sm-0 offset-md-0 offset-lg-0">
       <h1 i18n="The welcome message on the login page">Welcome to Ceph!</h1>
       <form name="loginForm"
             (ngSubmit)="login()"
@@ -20,7 +20,7 @@
 
         <!-- Username -->
         <div class="form-group has-feedback"
-             [ngClass]="{'has-error': (loginForm.submitted || username.dirty) && username.invalid}">
+             [ngClass]="{':invalid': (loginForm.submitted || username.dirty) && username.invalid}">
           <input name="username"
                  [(ngModel)]="model.username"
                  #username="ngModel"
                  class="form-control"
                  required
                  autofocus>
-          <div class="help-block"
+          <div class="form-text text-muted"
                *ngIf="(loginForm.submitted || username.dirty) && username.invalid"
                i18n>Username is required</div>
         </div>
 
         <!-- Password -->
         <div class="form-group has-feedback"
-             [ngClass]="{'has-error': (loginForm.submitted || password.dirty) && password.invalid}">
+             [ngClass]="{':invalid': (loginForm.submitted || password.dirty) && password.invalid}">
           <div class="input-group">
             <input id="password"
                    name="password"
                    placeholder="Enter your password..."
                    class="form-control"
                    required>
-            <span class="input-group-btn">
+            <span class="input-group-append">
               <button type="button"
-                      class="btn btn-default btn-password"
+                      class="btn btn-outline-light btn-password"
                       cdPasswordButton="password">
               </button>
             </span>
           </div>
-          <div class="help-block"
+          <div class="form-text text-muted"
                *ngIf="(loginForm.submitted || password.dirty) && password.invalid"
                i18n>Password is required</div>
         </div>
 
         <input type="submit"
-               class="btn btn-primary btn-block"
+               class="btn btn-secondary btn-block"
                [disabled]="loginForm.invalid"
                value="Login"
                i18n-value>
index 2422497349ecfac77bca9af2fb76f175bd9dbb45..f472d934c26ac700d234bbe05aa0277aa970423b 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 ::ng-deep .login {
   height: 100%;
   .btn-password:focus {
     outline-color: $color-password-toggle-focus;
   }
+}
 
-  .checkbox-primary input[type='checkbox']:checked + label::before,
-  .checkbox-primary input[type='radio']:checked + label::before {
-    background-color: $color-login-checkbox-bg;
-    border-color: $color-login-checkbox-border;
+// This will override the colors applied by chrome
+@keyframes autofill {
+  to {
+    color: $color-password-toggle-text;
+    background-color: $color-password-toggle-bg;
   }
 }
+
+input:-webkit-autofill {
+  animation-name: autofill;
+  animation-fill-mode: both;
+}
index f9c5b87572aaa399c8e68f5efb9e2cc3ce1b36a5..96a29d72339bfd8d9c2fd7879a3b991102bcfe39 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 thead {
   background-color: $color-table-header-bg;
index 2f9eefa9dcbbc1a3a4ef5bdd1d6440250db30130..1a80d2a0b5cd44adf34266cad7ffc84adbb5d6f2 100644 (file)
@@ -1,20 +1,17 @@
 <div class="col-sm-12 col-lg-6">
   <form name="roleForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="roleForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+      <div class="card-body">
 
         <!-- Name -->
-        <div class="form-group"
-             [ngClass]="{'has-error': roleForm.showError('name', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': roleForm.showError('name', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="name">
             <ng-container i18n>Name</ng-container>
             <span class="required"
                    name="name"
                    formControlName="name"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="roleForm.showError('name', formDir, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="roleForm.showError('name', formDir, 'notUnique')"
                   i18n>The chosen name is already in use.</span>
           </div>
         </div>
 
         <!-- Description -->
-        <div class="form-group"
-             [ngClass]="{'has-error': roleForm.showError('description', formDir)}">
+        <div class="form-group row"
+             [ngClass]="{':invalid': roleForm.showError('description', formDir)}">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="description">Description</label>
           <div class="col-sm-9">
             <input class="form-control"
@@ -56,9 +53,9 @@
         </div>
 
         <!-- Permissions -->
-        <div class="form-group">
+        <div class="form-group row">
           <label i18n
-                 class="control-label col-sm-3">Permissions</label>
+                 class="col-form-label col-sm-3">Permissions</label>
           <div class="col-sm-9">
             <cd-table [data]="scopes_permissions"
                       [columns]="columns"
         </div>
 
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            [form]="formDir" (submitAction)="submit()"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="submit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
              let-column="column"
              let-row="row"
              let-value="value">
-  <div class="checkbox checkbox-primary">
-    <input id="scope_{{ row.scope }}"
+  <div class="form-check abc-checkbox abc-checkbox-primary">
+    <input class="form-check-input"
+           id="scope_{{ row.scope }}"
            type="checkbox"
            [checked]="isRowChecked(row.scope)"
            (change)="onClickCellCheckbox(row.scope, column.prop, $event)">
-    <label class="datatable-permissions-scope-cell-label"
+    <label class="datatable-permissions-scope-cell-label form-check-label"
            for="scope_{{ row.scope }}">{{ value }}</label>
   </div>
 </ng-template>
              let-column="column"
              let-row="row"
              let-value="value">
-  <div class="checkbox checkbox-primary">
-    <input type="checkbox"
+  <div class="form-check abc-checkbox abc-checkbox-primary">
+    <input class="form-check-input"
+           type="checkbox"
            [checked]="value"
+           [id]="row.scope + '-' + column.prop"
            (change)="onClickCellCheckbox(row.scope, column.prop, $event)">
-    <label></label>
+    <label class="form-check-label"
+           [for]="row.scope + '-' + column.prop"></label>
   </div>
 </ng-template>
 
 <ng-template #headerPermissionCheckboxTpl
              let-column="column">
-  <div class="checkbox checkbox-primary">
-    <input id="header_{{ column.prop }}"
+  <div class="form-check abc-checkbox abc-checkbox-primary">
+    <input class="form-check-input"
+           id="header_{{ column.prop }}"
            type="checkbox"
            [checked]="isHeaderChecked(column.prop)"
            (change)="onClickHeaderCheckbox(column.prop, $event)">
-    <label class="datatable-permissions-header-cell-label"
+    <label class="datatable-permissions-header-cell-label form-check-label"
            for="header_{{ column.prop }}">{{ column.name }}</label>
   </div>
 </ng-template>
index b9284bfdcd6ac1406d88b4feb103105b4d9d74b5..59c6889e8a1758016a9dcd9b1bb309e841b3ab53 100644 (file)
@@ -3,7 +3,7 @@
     <h1 i18n>Sorry, the user does not exist in Ceph.</h1>
     <h4 i18n>Return to <a class="sso-logout" [href]="logoutUrl">Login Page</a>. You'll be logged out from the Identity Provider when you retry logging in.</h4>
 
-    <img class="img-responsive center-block img-rounded"
+    <img class="img-fluid mx-auto rounded"
          src="/assets/1280px-Nautilus_Octopus.jpg">
     <span>
       "<a href="https://www.flickr.com/photos/146401137@N06/40335060661">Nautilus Octopus</a>" by Jin Kemoole is licensed under
index 73e148dd8bc4be4fe69e22c42b364f3f7007779e..990aaeed904a8ae8a893091a1b484f3e5ac0c3d9 100644 (file)
@@ -1,20 +1,17 @@
 <div class="col-sm-12 col-lg-6">
   <form name="userForm"
-        class="form-horizontal"
         #formDir="ngForm"
         [formGroup]="userForm"
         novalidate>
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 i18n="form title|Example: Create Pool@@formTitle"
-            class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
-      </div>
-      <div class="panel-body">
+    <div class="card">
+      <div i18n="form title|Example: Create Pool@@formTitle"
+           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+      <div class="card-body">
 
         <!-- Username -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('username', formDir)}">
-          <label class="control-label col-sm-3"
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('username', formDir)}">
+          <label class="col-form-label col-sm-3"
                  for="username">
             <ng-container i18n>Username</ng-container>
             <span class="required"
                    name="username"
                    formControlName="username"
                    autofocus>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('username', formDir, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Password -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('password', formDir)}">
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('password', formDir)}">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="password">Password</label>
           <div class="col-sm-9">
             <div class="input-group">
                      name="password"
                      autocomplete="new-password"
                      formControlName="password">
-              <span class="input-group-btn">
+              <span class="input-group-append">
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdPasswordButton="password">
                 </button>
               </span>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('password', formDir, 'required')"
                   i18n>This field is required.</span>
           </div>
         </div>
 
         <!-- Confirm password -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('confirmpassword', formDir)}">
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('confirmpassword', formDir)}">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="confirmpassword">Confirm password</label>
           <div class="col-sm-9">
             <div class="input-group">
                      id="confirmpassword"
                      name="confirmpassword"
                      formControlName="confirmpassword">
-              <span class="input-group-btn">
+              <span class="input-group-append">
                 <button type="button"
-                        class="btn btn-default"
+                        class="btn btn-light"
                         cdPasswordButton="confirmpassword">
                 </button>
               </span>
             </div>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('confirmpassword', formDir, 'required')"
                   i18n>This field is required.</span>
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('confirmpassword', formDir, 'match')"
                   i18n>Password confirmation doesn't match the password.</span>
           </div>
         </div>
 
         <!-- Name -->
-        <div class="form-group">
+        <div class="form-group row">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="name">Full name</label>
           <div class="col-sm-9">
             <input class="form-control"
         </div>
 
         <!-- Email -->
-        <div class="form-group"
-             [ngClass]="{'has-error': userForm.showError('email', formDir)}">
+        <div class="form-group row"
+             [ngClass]="{':invalid': userForm.showError('email', formDir)}">
           <label i18n
-                 class="control-label col-sm-3"
+                 class="col-form-label col-sm-3"
                  for="email">Email</label>
           <div class="col-sm-9">
             <input class="form-control"
                    name="email"
                    formControlName="email">
 
-            <span class="help-block"
+            <span class="form-text text-muted"
                   *ngIf="userForm.showError('email', formDir, 'email')"
                   i18n>Invalid email.</span>
           </div>
         </div>
 
         <!-- Roles -->
-        <label class="col-sm-3 control-label"
-               i18n>Roles</label>
-        <div class="col-sm-9">
-          <span class="form-control no-border full-height"
-                *ngIf="allRoles">
-            <cd-select-badges [data]="userForm.controls.roles.value"
-                              [options]="allRoles"
-                              [messages]="messages"></cd-select-badges>
-          </span>
+        <div class="form-group row">
+          <label class="col-sm-3 col-form-label"
+                 i18n>Roles</label>
+          <div class="col-sm-9">
+            <span class="no-border full-height"
+                  *ngIf="allRoles">
+              <cd-select-badges [data]="userForm.controls.roles.value"
+                                [options]="allRoles"
+                                [messages]="messages"></cd-select-badges>
+            </span>
+          </div>
+
         </div>
 
       </div>
-      <div class="panel-footer">
+      <div class="card-footer">
         <div class="button-group text-right">
-          <cd-submit-button
-            [form]="formDir"
-            (submitAction)="submit()"
-            i18n="form action button|Example: Create Pool@@formActionButton"
-            type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
+          <cd-submit-button (submitAction)="submit()"
+                            i18n="form action button|Example: Create Pool@@formActionButton"
+                            [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
           <cd-back-button></cd-back-button>
         </div>
       </div>
index 4e0684d93d3baa78dff672f89284483131a1a0ee..b707992a9635da516b7985259d42708b5bd0729c 100644 (file)
@@ -2,11 +2,11 @@
   <tab heading="Users"
        i18n-heading
        [active]="url === '/user-management/users'"
-       (select)="navigateTo('/user-management/users')">
+       (selectTab)="navigateTo('/user-management/users')">
   </tab>
   <tab heading="Roles"
        i18n-heading
        [active]="url === '/user-management/roles'"
-       (select)="navigateTo('/user-management/roles')">
+       (selectTab)="navigateTo('/user-management/roles')">
   </tab>
 </tabset>
index d76ca93910aa7c2894cea3dd9fef6a29016bac89..1a4fcd915ee6b826832a14453c792c05cd0c9f71 100644 (file)
@@ -1,6 +1,6 @@
 <div class="modal-header">
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="modalRef.hide()">
     <span aria-hidden="true">&times;</span>
   <br>
   <ul class="list-unstyled">
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">Ceph Manager</strong>
-      <span class="col-xs-4 col-sm-4">{{ hostAddr }}</span>
+      <strong class="col-6 col-sm-4">Ceph Manager</strong>
+      <span class="col-4 col-sm-4">{{ hostAddr }}</span>
     </li>
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">User</strong>
-      <span class="col-xs-4 col-sm-4">{{ modalVariables.user }}</span>
+      <strong class="col-6 col-sm-4">User</strong>
+      <span class="col-4 col-sm-4">{{ modalVariables.user }}</span>
     </li>
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">User Role</strong>
-      <span class="col-xs-4 col-sm-4">{{ modalVariables.role }}</span>
+      <strong class="col-6 col-sm-4">User Role</strong>
+      <span class="col-4 col-sm-4">{{ modalVariables.role }}</span>
     </li>
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">Browser</strong>
-      <span class="col-xs-4 col-sm-4">{{ modalVariables.browserName }}</span>
+      <strong class="col-6 col-sm-4">Browser</strong>
+      <span class="col-4 col-sm-4">{{ modalVariables.browserName }}</span>
     </li>
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">Browser Version</strong>
-      <span class="col-xs-4 col-sm-4">{{ modalVariables.browserVersion }}</span>
+      <strong class="col-6 col-sm-4">Browser Version</strong>
+      <span class="col-4 col-sm-4">{{ modalVariables.browserVersion }}</span>
     </li>
     <li class="row">
-      <strong class="col-xs-6 col-sm-4">Browser OS</strong>
-      <span class="col-xs-4 col-sm-4">{{ modalVariables.browserOS }}</span>
+      <strong class="col-6 col-sm-4">Browser OS</strong>
+      <span class="col-4 col-sm-4">{{ modalVariables.browserOS }}</span>
     </li>
   </ul>
 </div>
index 68a9e1085496bc9b9ce0a11bea958540eb45705f..6a64276137b05e8f9f1942e0cd2124a4f1b66410 100644 (file)
@@ -1,17 +1,17 @@
 <div dropdown
+     class="btn-group"
      *ngIf="userPermission.read">
   <a dropdownToggle
      class="dropdown-toggle"
-     data-toggle="dropdown"
      i18n-title
      title="Dashboard Settings">
-    <i [ngClass]="[icons.deepCheck, icons.width]"></i>
+    <i [ngClass]="[icons.deepCheck]"></i>
     <span i18n
-          class="visible-xs-inline-block">Dashboard Settings</span>
-    <span class="caret"></span>
+          class="d-md-none">Dashboard Settings</span>
   </a>
   <ul *dropdownMenu
-      class="dropdown-menu dropdown-menu-right">
+      class="dropdown-menu dropdown-menu-right"
+      role="menu">
     <li *ngIf="userPermission.read">
       <a i18n
          class="dropdown-item"
index 0cbfd5f7998b28b1d45519e76f8a1587700e30e5..122bcfd5943d273e85fdad3f76d3f6e2f900dee8 100644 (file)
@@ -1,20 +1,24 @@
-<form #docsForm action="/docs" target="_blank" method="post">
-  <input type="hidden" name="token"/>
+<form #docsForm
+      action="/docs"
+      target="_blank"
+      method="post">
+  <input type="hidden"
+         name="token" />
 </form>
 
-<div dropdown>
+<div class="btn-group"
+     dropdown>
   <a dropdownToggle
      class="dropdown-toggle"
-     data-toggle="dropdown"
      i18n-title
      title="Help">
-    <i [ngClass]="[icons.questionCircle, icons.width]"></i>
+    <i [ngClass]="[icons.questionCircle]"></i>
     <span i18n
-          class="visible-xs-inline-block">Help</span>
-    <span class="caret"></span>
+          class="d-md-none">Help</span>
   </a>
   <ul *dropdownMenu
-      class="dropdown-menu dropdown-menu-right">
+      class="dropdown-menu dropdown-menu-right"
+      role="menu">
     <li>
       <a i18n
          class="dropdown-item"
index 4478508190d8969f8580d5be5e672137b59b0fc0..477533028f4e86938076284f82c7dd7124b3d703 100644 (file)
@@ -44,6 +44,7 @@ export class DashboardHelpComponent implements OnInit {
 
   openAboutModal() {
     this.modalRef = this.modalService.show(AboutComponent);
+    this.modalRef.setClass('modal-lg');
   }
 
   goToApiDocs() {
index 1eda7d06f8301e3492bb0520a1066d1fbf5844cf..7b1ca8a33f30b9618a8986f8394884367a2a1e48 100644 (file)
@@ -1,13 +1,12 @@
-<div dropdown>
+<div dropdown
+     class="btn-group">
   <a dropdownToggle
      class="dropdown-toggle"
-     data-toggle="dropdown"
      i18n-title
      title="Logged in user">
-    <i [ngClass]="[icons.user, icons.width]"></i>
+    <i [ngClass]="[icons.user]"></i>
     <span i18n
-          class="visible-xs-inline-block">Logged in user</span>
-    <span class="caret"></span>
+          class="d-md-none">Logged in user</span>
   </a>
   <ul *dropdownMenu
       class="dropdown-menu dropdown-menu-right"
          href="#">Signed in as
       <strong>{{ username }}</strong></a>
     </li>
-    <li class="divider dropdown-divider"></li>
+    <li class="dropdown-divider"></li>
     <li role="menuitem">
       <a class="dropdown-item"
          (click)="logout()">
-        <i [ngClass]="[icons.signOut, icons.width]"></i>
+        <i [ngClass]="[icons.signOut]"></i>
         <span i18n>Sign out</span>
       </a>
     </li>
index f2dbbca4ef2aa611f1a913db2821c4998beda8d1..42db3ecb8d2b8b605fab183031678d80c2333fa1 100644 (file)
-<nav class="navbar navbar-default navbar-main">
-  <!-- Brand and toggle get grouped for better mobile display -->
-
-  <div class="navbar-header tc_logo_component">
-    <a class="navbar-brand"
+<div class="cd-navbar-top">
+  <nav class="navbar navbar-expand-md navbar-dark cd-navbar-brand">
+    <a class="navbar-brand mt-3 mb-2 ml-2"
        href="#">
       <img src="assets/Ceph_Logo_Standard_RGB_White_120411_fa.png"
-           alt="Ceph">
+           alt="Ceph" />
     </a>
 
     <button type="button"
-            class="navbar-toggle collapsed"
+            class="navbar-toggler"
             (click)="isCollapsed = !isCollapsed">
       <span i18n
             class="sr-only">Toggle navigation</span>
-      <span class="icon-bar"></span>
-      <span class="icon-bar"></span>
-      <span class="icon-bar"></span>
+      <span class="">
+        <i class="fa fa-navicon fa-lg"></i>
+      </span>
     </button>
-  </div>
 
-  <!-- Collect the nav links, forms, and other content for toggling -->
-  <div *ngIf="enabledFeature$ | async as enabledFeature"
-       class="collapse navbar-collapse"
-       id="bs-example-navbar-collapse-1"
-       [collapse]="isCollapsed">
-    <ul class="nav navbar-nav navbar-primary">
+    <div class="collapse navbar-collapse"
+         [collapse]="isCollapsed">
+      <ul class="navbar-nav mt-2 cd-navbar-primary d-block d-md-none">
+        <ng-container *ngTemplateOutlet="cd_menu"> </ng-container>
+      </ul>
+
+      <ul class="nav navbar-nav cd-navbar-utility my-2 my-md-0">
+        <ng-container *ngTemplateOutlet="cd_utilities"> </ng-container>
+      </ul>
+
+    </div>
+  </nav>
+
+  <nav class="navbar navbar-expand-md navbar-dark cd-navbar-main pb-0 pl-0 d-none d-md-flex">
+    <ul class="navbar-nav mr-auto my-0 cd-navbar-primary ">
+      <ng-container *ngTemplateOutlet="cd_menu"> </ng-container>
+    </ul>
+  </nav>
+</div>
+
+<ng-template #cd_utilities>
+  <li class="nav-item ">
+    <cd-language-selector class="cd-navbar"></cd-language-selector>
+  </li>
+  <li class="nav-item ">
+    <cd-task-manager class="cd-navbar"></cd-task-manager>
+  </li>
+  <li class="nav-item ">
+    <cd-notifications class="cd-navbar"></cd-notifications>
+  </li>
+  <li class="nav-item ">
+    <cd-dashboard-help class="cd-navbar"></cd-dashboard-help>
+  </li>
+  <li class="nav-item ">
+    <cd-administration class="cd-navbar"></cd-administration>
+  </li>
+  <li class="nav-item ">
+    <cd-identity class="cd-navbar"></cd-identity>
+  </li>
+</ng-template>
+
+<ng-template #cd_menu>
+  <!-- Dashboard -->
+  <li routerLinkActive="active"
+      class="nav-item tc_menuitem_dashboard">
+    <a routerLink="/dashboard"
+       class="nav-link">
+      <i [ngClass]="[icons.health]"
+         [ngStyle]="summaryData?.health_status | healthColor"></i>
+      <span i18n>Dashboard</span>
+    </a>
+  </li>
 
-      <!-- Dashboard -->
+  <!-- Cluster -->
+  <li dropdown
+      routerLinkActive="active"
+      class="nav-item dropdown tc_menuitem_cluster"
+      *ngIf="
+      permissions.hosts.read ||
+      permissions.monitor.read ||
+      permissions.osd.read ||
+      permissions.configOpt.read">
+    <a dropdownToggle
+       class="nav-link dropdown-toggle"
+       data-toggle="dropdown">
+      <ng-container i18n>Cluster</ng-container>
+    </a>
+    <ul *dropdownMenu
+        class="dropdown-menu">
       <li routerLinkActive="active"
-          class="tc_menuitem tc_menuitem_dashboard">
-        <a routerLink="/dashboard">
-          <i [ngClass]="[icons.health, icons.width]"
-             [ngStyle]="summaryData?.health_status | healthColor"></i>
-          <span i18n>Dashboard</span>
-        </a>
+          class="tc_submenuitem tc_submenuitem_hosts"
+          *ngIf="permissions.hosts.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/hosts">Hosts</a>
       </li>
-
-      <!-- Cluster -->
-      <li dropdown
-          routerLinkActive="active"
-          class="dropdown tc_menuitem tc_menuitem_cluster"
-          *ngIf="permissions.hosts.read || permissions.monitor.read || permissions.osd.read || permissions.configOpt.read">
-        <a dropdownToggle
-           class="dropdown-toggle"
-           data-toggle="dropdown">
-          <ng-container i18n>Cluster</ng-container>
-          <span class="caret"></span>
-        </a>
-        <ul *dropdownMenu
-            class="dropdown-menu">
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_hosts"
-              *ngIf="permissions.hosts.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/hosts">Hosts</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_cluster_monitor"
-              *ngIf="permissions.monitor.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/monitor/">Monitors</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_hosts"
-              *ngIf="permissions.osd.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/osd">OSDs</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_configuration"
-              *ngIf="permissions.configOpt.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/configuration">Configuration</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_crush"
-              *ngIf="permissions.hosts.read && permissions.osd.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/crush-map">CRUSH map</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_modules"
-              *ngIf="permissions.configOpt.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/mgr-modules">Manager modules</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_log"
-              *ngIf="permissions.log.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/logs">Logs</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_prometheus"
-              *ngIf="prometheusConfigured && permissions.prometheus.read">
-            <a i18n
-               routerLink="/alerts">Alerts</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_prometheus"
-              *ngIf="prometheusConfigured && permissions.prometheus.read">
-            <a i18n
-               routerLink="/silence">Silences</a>
-          </li>
-        </ul>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_cluster_monitor"
+          *ngIf="permissions.monitor.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/monitor/">Monitors</a>
       </li>
-
-      <!-- Pools -->
       <li routerLinkActive="active"
-          class="tc_menuitem tc_menuitem_pool"
-          *ngIf="permissions.pool.read">
+          class="tc_submenuitem tc_submenuitem_hosts"
+          *ngIf="permissions.osd.read">
         <a i18n
-           routerLink="/pool">Pools</a>
+           class="dropdown-item"
+           routerLink="/osd">OSDs</a>
       </li>
-
-      <!-- Block -->
-      <li dropdown
-          routerLinkActive="active"
-          class="dropdown tc_menuitem tc_menuitem_block"
-          *ngIf="
-          (enabledFeature.rbd || enabledFeature.mirroring || enabledFeature.iscsi) &&
-          (permissions.rbdImage.read || permissions.rbdMirroring.read || permissions.iscsi.read)">
-        <a dropdownToggle
-           class="dropdown-toggle"
-           data-toggle="dropdown"
-           [ngStyle]="blockHealthColor()">
-          <ng-container i18n>Block</ng-container>
-          <span class="caret"></span>
-        </a>
-
-        <ul class="dropdown-menu">
-          <li routerLinkActive="active"
-              *ngIf="enabledFeature.rbd && permissions.rbdImage.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/block/rbd">Images</a>
-          </li>
-
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_block_mirroring"
-              *ngIf="enabledFeature.mirroring && permissions.rbdMirroring.read">
-            <a class="dropdown-item"
-               routerLink="/block/mirroring">
-              <ng-container i18n>Mirroring</ng-container>
-              <small *ngIf="summaryData?.rbd_mirroring?.warnings !== 0"
-                     class="label label-warning">{{ summaryData?.rbd_mirroring?.warnings }}</small>
-              <small *ngIf="summaryData?.rbd_mirroring?.errors !== 0"
-                     class="label label-danger">{{ summaryData?.rbd_mirroring?.errors }}</small>
-            </a>
-          </li>
-
-          <li routerLinkActive="active"
-              *ngIf="enabledFeature.iscsi && permissions.iscsi.read">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/block/iscsi">iSCSI</a>
-          </li>
-        </ul>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_configuration"
+          *ngIf="permissions.configOpt.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/configuration">Configuration</a>
       </li>
-
-      <!-- NFS -->
       <li routerLinkActive="active"
-          class="tc_menuitem tc_menuitem_nfs"
-          *ngIf="permissions?.nfs?.read">
+          class="tc_submenuitem tc_submenuitem_crush"
+          *ngIf="permissions.hosts.read && permissions.osd.read">
         <a i18n
-           routerLink="/nfs">NFS</a>
+           class="dropdown-item"
+           routerLink="/crush-map">CRUSH map</a>
       </li>
-
-      <!-- Filesystem -->
       <li routerLinkActive="active"
-          class="tc_menuitem tc_menuitem_cephs"
-          *ngIf="enabledFeature.cephfs && permissions.cephfs.read">
+          class="tc_submenuitem tc_submenuitem_modules"
+          *ngIf="permissions.configOpt.read">
         <a i18n
-           routerLink="/cephfs">Filesystems</a>
+           class="dropdown-item"
+           routerLink="/mgr-modules">Manager modules</a>
       </li>
-
-      <!-- Object Gateway -->
-      <li dropdown
-          routerLinkActive="active"
-          class="dropdown tc_menuitem tc_menuitem_rgw"
-          *ngIf="enabledFeature.rgw && permissions.rgw.read">
-        <a dropdownToggle
-           class="dropdown-toggle"
-           data-toggle="dropdown">
-          <ng-container i18n>Object Gateway</ng-container>
-          <span class="caret"></span>
-        </a>
-        <ul *dropdownMenu
-            class="dropdown-menu">
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_rgw_daemons">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/rgw/daemon">Daemons</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_rgw_users">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/rgw/user">Users</a>
-          </li>
-          <li routerLinkActive="active"
-              class="tc_submenuitem tc_submenuitem_rgw_buckets">
-            <a i18n
-               class="dropdown-item"
-               routerLink="/rgw/bucket">Buckets</a>
-          </li>
-        </ul>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_log"
+          *ngIf="permissions.log.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/logs">Logs</a>
+      </li>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_prometheus"
+          *ngIf="prometheusConfigured && permissions.prometheus.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/alerts">Alerts</a>
+      </li>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_prometheus"
+          *ngIf="prometheusConfigured && permissions.prometheus.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/silence">Silences</a>
       </li>
     </ul>
-    <!-- /.navbar-primary -->
+  </li>
+
+  <!-- Pools -->
+  <li routerLinkActive="active"
+      class="nav-item tc_menuitem_pool"
+      *ngIf="permissions.pool.read">
+    <a class="nav-link"
+       i18n
+       routerLink="/pool">Pools</a>
+  </li>
+
+  <!-- Block -->
+  <li dropdown
+      routerLinkActive="active"
+      class="nav-item dropdown tc_menuitem_block"
+      *ngIf="permissions.rbdImage.read || permissions.rbdMirroring.read || permissions.iscsi.read">
+    <a dropdownToggle
+       class="nav-link dropdown-toggle"
+       data-toggle="dropdown"
+       [ngStyle]="blockHealthColor()">
+      <ng-container i18n>Block</ng-container>
+    </a>
 
-    <ul class="nav navbar-nav navbar-utility">
-      <li>
-        <cd-language-selector class="oa-navbar"></cd-language-selector>
+    <ul *dropdownMenu
+        class="dropdown-menu">
+      <li routerLinkActive="active"
+          *ngIf="permissions.rbdImage.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/block/rbd">Images</a>
       </li>
-      <li>
-        <cd-task-manager class="oa-navbar"></cd-task-manager>
+
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_block_mirroring"
+          *ngIf="permissions.rbdMirroring.read">
+        <a class="dropdown-item"
+           routerLink="/block/mirroring">
+          <ng-container i18n>Mirroring</ng-container>
+          <small *ngIf="summaryData?.rbd_mirroring?.warnings !== 0"
+                 class="badge badge-warning">{{ summaryData?.rbd_mirroring?.warnings }}</small>
+          <small *ngIf="summaryData?.rbd_mirroring?.errors !== 0"
+                 class="badge badge-danger">{{ summaryData?.rbd_mirroring?.errors }}</small>
+        </a>
       </li>
-      <li>
-        <cd-notifications class="oa-navbar"></cd-notifications>
+
+      <li routerLinkActive="active"
+          *ngIf="permissions.iscsi.read">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/block/iscsi">iSCSI</a>
       </li>
-      <li>
-        <cd-dashboard-help class="oa-navbar"></cd-dashboard-help>
+    </ul>
+  </li>
+
+  <!-- NFS -->
+  <li routerLinkActive="active"
+      class="item tc_menuitem_nfs"
+      *ngIf="permissions?.nfs?.read">
+    <a i18n
+       class="nav-link"
+       routerLink="/nfs">NFS</a>
+  </li>
+
+  <!-- Filesystem -->
+  <li routerLinkActive="active"
+      class="nav-item tc_menuitem_cephs"
+      *ngIf="permissions.cephfs.read">
+    <a i18n
+       class="nav-link"
+       routerLink="/cephfs">Filesystems</a>
+  </li>
+
+  <!-- Object Gateway -->
+  <li dropdown
+      routerLinkActive="active"
+      class="nav-item dropdown tc_menuitem_rgw"
+      *ngIf="permissions.rgw.read">
+    <a dropdownToggle
+       class="nav-link dropdown-toggle"
+       data-toggle="dropdown">
+      <ng-container i18n>Object Gateway</ng-container>
+    </a>
+    <ul *dropdownMenu
+        class="dropdown-menu">
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_rgw_daemons">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/rgw/daemon">Daemons</a>
       </li>
-      <li>
-        <cd-administration class="oa-navbar"></cd-administration>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_rgw_users">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/rgw/user">Users</a>
       </li>
-      <li>
-        <cd-identity class="oa-navbar"></cd-identity>
+      <li routerLinkActive="active"
+          class="tc_submenuitem tc_submenuitem_rgw_buckets">
+        <a i18n
+           class="dropdown-item"
+           routerLink="/rgw/bucket">Buckets</a>
       </li>
     </ul>
-    <!-- /.navbar-utility -->
-  </div>
-  <!-- /.navbar-collapse -->
-</nav>
+  </li>
+</ng-template>
index fcb4b0b5f5e81c5b560cdf8f1ea48cdb405466b7..c264712b08c47deb069c3a3a55c48f431984264f 100644 (file)
@@ -1,99 +1,87 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 /* Navbar */
-::ng-deep .navbar-main {
+::ng-deep .cd-navbar-top {
   margin-bottom: 0;
   background: $color-navbar-bg;
   border: 0;
   border-radius: 0;
-  border-top: 4px solid $color-nav-top-bar;
-  font-size: 1.2em;
 
-  .navbar-header {
-    display: flex;
-    float: none;
-  }
+  .cd-navbar-brand {
+    border-top: 4px solid $color-nav-top-bar;
 
-  .navbar-brand,
-  .navbar-brand:hover {
-    color: $color-navbar-brand;
-    height: auto;
-    margin: 15px 0 15px 20px;
-    padding: 0;
-    -webkit-align-self: flex-start;
-    align-self: flex-start;
-  }
+    .navbar-brand,
+    .navbar-brand:hover {
+      color: $color-navbar-brand;
+      height: auto;
+      padding: 0;
+    }
 
-  .navbar-brand > img {
-    height: 25px;
-  }
+    .navbar-brand > img {
+      height: 25px;
+    }
 
-  .navbar-toggle {
-    margin-left: auto;
-    border: 0;
-  }
+    .navbar-toggler {
+      border: 0;
 
-  .navbar-toggle:focus,
-  .navbar-toggle:hover {
-    background-color: transparent;
-    outline: 0;
-  }
+      &:focus,
+      &:hover {
+        outline: 0;
+      }
 
-  .navbar-toggle .icon-bar {
-    background-color: $color-nav-toggle-bar;
-  }
+      .fa-navicon {
+        color: $color-nav-toggle-bar;
+      }
+    }
 
-  .navbar-toggle:focus .icon-bar,
-  .navbar-toggle:hover .icon-bar {
-    -webkit-box-shadow: 0 0 3px $color-nav-toggle-shadow;
-    box-shadow: 0 0 3px $color-nav-toggle-shadow;
-  }
+    .navbar-collapse {
+      padding: 0;
+    }
 
-  .navbar-collapse {
-    padding: 0;
-  }
+    .cd-navbar-utility > .active > a {
+      color: $color-nav-links;
+      background-color: $color-nav-links-hover;
+    }
 
-  .navbar-nav > li > .oa-navbar > [dropdown] > ul > li > .dropdown-item {
-    font-size: 12px;
+    .cd-navbar-utility > li > .open > a,
+    .cd-navbar-utility > li > .open > a:focus,
+    .cd-navbar-utility > li > .open > a:hover {
+      color: $color-nav-links;
+      border-color: transparent;
+      background-color: transparent;
+    }
   }
 
-  .navbar-nav > li > .oa-navbar > [dropdown] > a,
-  .navbar-nav > li > .oa-navbar > a,
+  .navbar-nav > li > .cd-navbar > [dropdown] > a,
+  .navbar-nav > li > .cd-navbar > a,
   .navbar-nav > li > a {
     color: $color-nav-links;
     line-height: 1;
-    padding: 10px 18px;
+    padding: 10px 18px !important;
     position: relative;
     display: block;
     text-decoration: none;
   }
 
-  .navbar-nav > li > .oa-navbar > [dropdown] > a:focus,
-  .navbar-nav > li > .oa-navbar > [dropdown] > a:hover,
-  .navbar-nav > li > .oa-navbar > a:focus,
-  .navbar-nav > li > .oa-navbar > a:hover,
-  .navbar-nav > li > a:focus,
-  .navbar-nav > li > a:hover {
+  .navbar-nav .nav-link,
+  .navbar-nav .nav-link:hover {
     color: $color-nav-links;
   }
 
-  .navbar-nav > li > .oa-navbar > [dropdown] > a:hover,
-  .navbar-nav > li > .oa-navbar > [dropdown].open > a,
-  .navbar-nav > li > .oa-navbar > a:hover,
-  .navbar-nav > li > a:hover {
+  .navbar-nav > li > .cd-navbar > [dropdown] > a:hover,
+  .navbar-nav > li > .cd-navbar > [dropdown].open > a,
+  .navbar-nav > li > .cd-navbar > a:hover,
+  .navbar-nav > li > a:hover,
+  .navbar-nav > li:hover {
     background-color: $color-nav-links-hover;
   }
 
-  .navbar-nav > li a.dropdown-toggle span.caret {
-    margin-left: 5px;
-  }
-
-  .navbar-nav > .open > .oa-navbar > [dropdown] > a,
-  .navbar-nav > .open > .oa-navbar > [dropdown] > a:hover,
-  .navbar-nav > .open > .oa-navbar > a,
-  .navbar-nav > .open > .oa-navbar > a:focus,
-  .navbar-nav > .open > .oa-navbar > a:hover,
-  .navbar-nav > .open > .oa-navbar > li > a:focus,
+  .navbar-nav > .open > .cd-navbar > [dropdown] > a,
+  .navbar-nav > .open > .cd-navbar > [dropdown] > a:hover,
+  .navbar-nav > .open > .cd-navbar > a,
+  .navbar-nav > .open > .cd-navbar > a:focus,
+  .navbar-nav > .open > .cd-navbar > a:hover,
+  .navbar-nav > .open > .cd-navbar > li > a:focus,
   .navbar-nav > .open > a,
   .navbar-nav > .open > a:focus,
   .navbar-nav > .open > a:hover {
     background-color: transparent;
   }
 
-  .navbar-primary > li > a {
-    border: 0;
+  .cd-navbar-primary {
+    font-size: 1.2em;
   }
 
-  .navbar-primary > .active > a,
-  .navbar-primary > .active > a:focus,
-  .navbar-primary > .active > a:hover {
-    color: $color-nav-links;
-    background-color: $color-nav-links-hover;
+  .cd-navbar-primary > li > a {
     border: 0;
   }
 
-  .navbar-utility .fa,
-  .navbar-utility a {
-    font-size: 1.1em;
-  }
-
-  .navbar-utility > .active > a {
+  .cd-navbar-primary > .active > a,
+  .cd-navbar-primary > .active > a:focus,
+  .cd-navbar-primary > .active > a:hover {
     color: $color-nav-links;
     background-color: $color-nav-links-hover;
+    border: 0;
   }
 
-  .navbar-utility > li > .open > a,
-  .navbar-utility > li > .open > a:focus,
-  .navbar-utility > li > .open > a:hover {
-    color: $color-nav-links;
-    border-color: transparent;
-    background-color: transparent;
-  }
-  @media (min-width: $screen-sm-min) {
+  @media (min-width: $screen-md-min) {
     .navbar-primary > li > a {
       border-bottom: 4px solid transparent;
     }
 
-    .navbar-primary > .active > a,
-    .navbar-primary > .active > a:focus,
-    .navbar-primary > .active > a:hover {
+    .cd-navbar-primary > .active > a,
+    .cd-navbar-primary > .active > a:focus,
+    .cd-navbar-primary > .active > a:hover {
       background-color: transparent;
       border-bottom: 4px solid $color-nav-bottom-bar;
     }
 
-    .navbar-utility {
+    .cd-navbar-utility {
       border-bottom: 0;
-      font-size: 11px;
       position: absolute;
       right: 0;
       top: 0;
+      font-size: 1.1rem;
     }
   }
-  @media (max-width: $screen-xs-max) {
+
+  @media (max-width: $screen-sm-max) {
     .navbar-nav {
       margin: 0;
 
       .fa {
         margin-right: 0.5em;
       }
-    }
-
-    .navbar-collapse,
-    .navbar-form {
-      border-color: $color-nav-collapse-border;
-    }
-
-    .navbar-collapse {
-      padding: 0;
-    }
 
-    .navbar-nav .open .dropdown-menu {
-      padding-top: 0;
-      padding-bottom: 0;
-      background-color: $color-nav-open-bg;
-    }
+      .open .dropdown-menu {
+        border: 0;
+        padding-top: 0;
+        padding-bottom: 0;
+        background-color: $color-nav-open-bg;
+      }
 
-    .navbar-nav .open .dropdown-menu .dropdown-header,
-    .navbar-nav .open .dropdown-menu > li > a {
-      padding: 5px 15px 5px 35px;
-    }
+      .open .dropdown-menu > li > a {
+        padding: 5px 15px 5px 35px;
+        color: $color-nav-links;
+      }
 
-    .navbar-nav .open .dropdown-menu > li > a {
-      color: $color-nav-links;
-    }
+      .open .dropdown-menu > .active > a {
+        background-color: $color-nav-active-link-bg;
+      }
 
-    .navbar-nav .open .dropdown-menu > .active > a {
-      color: $color-nav-links;
-      background-color: $color-nav-active-link-bg;
+      & > li > a:hover {
+        background-color: $color-nav-active-link-bg;
+      }
     }
 
-    .navbar-nav > li > a:hover {
-      background-color: $color-nav-active-link-bg;
+    .cd-navbar-primary {
+      margin-top: 5px;
+      border-top: 1px solid $color-nav-border-top-collapse;
     }
 
-    .navbar-utility {
+    .cd-navbar-utility {
       border-top: 1px solid $color-nav-border-top-collapse;
+      font-size: 1.2em;
 
-      a {
-        font-size: 1em;
+      .btn-group {
+        display: block;
       }
     }
 
-    .navbar-primary > .active > a,
-    .navbar-primary > .active > a:focus,
-    .navbar-primary > .active > a:hover {
+    .cd-navbar-primary > .active > a,
+    .cd-navbar-primary > .active > a:focus,
+    .cd-navbar-primary > .active > a:hover {
       background-color: $color-nav-active-link-bg;
     }
   }
index 43d00cf818bc0637e90134c6c123c7925577df29..93024e67abe4560dcb272bb410e7192546ea478d 100644 (file)
@@ -1,6 +1,6 @@
 <ng-template #notificationsTpl>
   <div *ngIf="notifications.length > 0">
-    <button type="button" class="btn btn-default btn-sm btn-block" (click)="removeAll()">
+    <button type="button" class="btn btn-light btn-block" (click)="removeAll()">
       <i [ngClass]="[icons.trash]" aria-hidden="true"></i>
       &nbsp;
       <ng-container i18n>Remove all</ng-container>
@@ -34,9 +34,8 @@
 
 <ng-template #emptyTpl>
   <div *ngIf="notifications.length === 0">
-    <div class="message">
-      There are no notifications.
-    </div>
+    <div class="message"
+         i18n>There are no notifications.</div>
   </div>
 </ng-template>
 
@@ -51,7 +50,7 @@
    outsideClick="true"
    i18n-title
    title="Recent Notifications">
-  <i [ngClass]="[icons.bell, icons.width]"></i>
+  <i [ngClass]="[icons.bell]"></i>
   <span i18n
-        class="visible-xs-inline-block">Recent Notifications</span>
+        class="d-md-none">Recent Notifications</span>
 </a>
index 987c63c7de1d8223c813d2d24eef3d9f7ca437d8..59375a2068d63def8e99fdea0e26518b1fdd1f8a 100644 (file)
@@ -77,8 +77,8 @@
    outsideClick="true"
    i18n-title
    title="Background Tasks">
-  <i [ngClass]="[icon,icons.width]"></i>
+  <i [ngClass]="[icon]"></i>
   <span i18n
-        class="visible-xs-inline-block">Background Tasks</span>
+        class="d-md-none">Background Tasks</span>
   <span *ngIf="executingTasks.length > 0"> ({{ executingTasks.length }})</span>
 </a>
index e1839d520f0277175d2282cf4b11e45d6f6a53bb..4b394f17ee2490b9280b01393069d310d847cd06 100644 (file)
@@ -76,11 +76,11 @@ describe('TaskManagerComponent', () => {
 
   it('should get an empty hour glass with only finished tasks', () => {
     component._setIcon(0);
-    expect(component.icon).toBe('fa-hourglass-o');
+    expect(component.icon).toBe('fa fa-hourglass-o');
   });
 
   it('should get a nearly empty hour glass with executing tasks', () => {
     component._setIcon(10);
-    expect(component.icon).toBe('fa-hourglass-start');
+    expect(component.icon).toBe('fa fa-hourglass-start');
   });
 });
index c23bbcde119ce0e9ecfd6335cee349a2fa82bd5e..585a1222ba0f2d609503ba4d1cad1b3cb9d7e44c 100644 (file)
@@ -53,6 +53,6 @@ export class TaskManagerComponent implements OnInit {
   _setIcon(executingTasks: number) {
     const iconSuffix = ['o', 'start', 'half', 'end']; // TODO: Use all suffixes
     const iconIndex = executingTasks > 0 ? 1 : 0;
-    this.icon = 'fa-hourglass-' + iconSuffix[iconIndex];
+    this.icon = [Icons.filledHourglass, iconSuffix[iconIndex]].join('-');
   }
 }
index daeeaf54fd05f7a32c6d6442be7cf43924b6c22a..231047bef0634f69c6990aa91849ab2ac682745d 100644 (file)
@@ -2,7 +2,7 @@
   <div class="col-md-12 text-center">
     <h1 i18n>Sorry, we could not find what you were looking for</h1>
 
-    <img class="img-responsive center-block img-rounded"
+    <img class="img-fluid mx-auto rounded"
          src="/assets/1280px-Nautilus_Octopus.jpg">
     <span>
       "<a href="https://www.flickr.com/photos/146401137@N06/40335060661">Nautilus Octopus</a>" by Jin Kemoole is licensed under
index 0d5e50fd505ac615f4d039d6a181babb7fcd8788..21e3210fdc9d8d28211addcd1dd262eefeb7132d 100644 (file)
@@ -1,5 +1,5 @@
 &nbsp;
-<button class="btn btn-sm btn-default tc_backButton"
+<button class="btn btn btn-light tc_backButton"
         (click)="back()"
         type="button">
   {{ name }}
index 37c4663ec6a22011488623adfb313057e4d7bedb..8f7d28bc28ea7314707df843b88bc77f4ba44112 100644 (file)
@@ -1,11 +1,10 @@
 <div [formGroup]="optionsFormGroup">
   <div *ngFor="let option of options; let last = last">
-    <div class="form-group"
-         [ngClass]="{'has-error': optionsForm.showError(option.name, optionsFormDir)}"
+    <div class="form-group row pt-2"
          *ngIf="option.type === 'bool'">
-      <label class="col-sm-6 control-label"
+      <label class="control-label col-6"
              [for]="option.name">
-        {{ option.text }}
+        <b>{{ option.text }}</b>
         <br>
         <span class="text-muted">
           {{ option.desc }}
             {{ option.long_desc }}</cd-helper>
         </span>
       </label>
-      <div class="col-sm-6 checkbox-primary checkbox">
-        <input type="checkbox"
-               [id]="option.name"
-               [formControlName]="option.name">
-        <label></label>
+
+      <div class="col-6">
+        <div class="custom-control custom-checkbox">
+          <input class="custom-control-input"
+                 type="checkbox"
+                 [id]="option.name"
+                 [formControlName]="option.name">
+          <label class="custom-control-label"
+                 [for]="option.name"></label>
+        </div>
       </div>
     </div>
-    <div class="form-group"
-         [ngClass]="{'has-error': optionsForm.showError(option.name, optionsFormDir)}"
+
+    <div class="form-group row pt-2"
          *ngIf="option.type !== 'bool'">
-      <label class="col-sm-6 control-label"
+      <label class="col-6 control-label"
              [for]="option.name">{{ option.text }}
         <br>
         <span class="text-muted">
@@ -32,7 +36,7 @@
             {{ option.long_desc }}</cd-helper>
         </span>
       </label>
-      <div class="col-sm-6">
+      <div class="col-6">
         <div class="input-group">
           <input class="form-control"
                  [type]="option.additionalTypeInfo.inputType"
@@ -40,9 +44,9 @@
                  [placeholder]="option.additionalTypeInfo.humanReadable"
                  [formControlName]="option.name"
                  [step]="getStep(option.type, optionsForm.getValue(option.name))">
-          <span class="input-group-btn"
-                *ngIf="optionsFormShowReset">
-            <button class="btn btn-default"
+          <div class="input-group-append"
+               *ngIf="optionsFormShowReset">
+            <button class="btn btn-light"
                     type="button"
                     data-toggle="button"
                     title="Remove the custom configuration value. The default configuration will be inherited and used instead."
               <i [ngClass]="[icons.erase]"
                  aria-hidden="true"></i>
             </button>
-          </span>
+          </div>
         </div>
-        <span class="help-block"
+        <span class="invalid-feedback"
               *ngIf="optionsForm.showError(option.name, optionsFormDir, 'pattern')">
           {{ option.additionalTypeInfo.patternHelpText }}</span>
-        <span class="help-block"
+        <span class="invalid-feedback"
               *ngIf="optionsForm.showError(option.name, optionsFormDir, 'invalidUuid')">
           {{ option.additionalTypeInfo.patternHelpText }}</span>
-        <span class="help-block"
+        <span class="invalid-feedback"
               *ngIf="optionsForm.showError(option.name, optionsFormDir, 'max')"
               i18n>The entered value is too high! It must not be greater than {{ option.maxValue }}.</span>
-        <span class="help-block"
+        <span class="invalid-feedback"
               *ngIf="optionsForm.showError(option.name, optionsFormDir, 'min')"
               i18n>The entered value is too low! It must not be lower than {{ option.minValue }}.</span>
       </div>
     </div>
-    <hr *ngIf="!last">
+    <hr *ngIf="!last"
+        class="my-2">
   </div>
 </div>
index 7c1347efb6ff13a347bf7bfa4c249df600f661d6..89629245e1daa0fbd60304fb808f33c5154868ea 100644 (file)
@@ -1,30 +1,6 @@
-hr {
-  margin-top: 5px;
-  margin-bottom: 5px;
-}
-
-.control-label {
-  text-align: left;
-}
-
-.checkbox-primary {
+.custom-checkbox {
+  label,
   input {
-    width: 23px;
-    height: 15px;
-    margin-left: 0;
     cursor: pointer;
   }
-  label {
-    &:before,
-    &:after {
-      margin-left: 0;
-    }
-    cursor: auto;
-  }
-}
-
-.form-group {
-  .col-sm-6 {
-    padding-top: 7px;
-  }
 }
index 707e24e84d5c84eba464dec2ee0a73c21d02cb73..0060c93bee80080ead582ece0d8e37025891a1ac 100644 (file)
@@ -2,7 +2,6 @@
   <ng-container class="modal-title">{{ titleText }}</ng-container>
   <ng-container class="modal-content">
     <form name="confirmationForm"
-          class="form-horizontal"
           #formDir="ngForm"
           [formGroup]="confirmationForm"
           novalidate>
index 7f0d3d786ea3c5890105cd47e5b81e5643b34df8..40578d03c88192a2afd31cb66cab727a46289490 100644 (file)
       <div class="modal-body">
         <ng-container *ngTemplateOutlet="bodyTemplate; context: bodyContext"></ng-container>
         <div class="question">
-          <p i18n>Are you sure that you want to {{ actionDescription | lowercase }} the selected {{ itemDescription }}?</p>
+          <p i18n>Are you sure that you want to
+            {{ actionDescription | lowercase }} the selected {{ itemDescription }}?</p>
           <div class="form-group"
-               [ngClass]="{'has-error': deletionForm.showError('confirmation', formDir)}">
-            <div class="checkbox checkbox-primary">
-              <input type="checkbox"
+               [ngClass]="{':invalid': deletionForm.showError('confirmation', formDir)}">
+            <div class="form-check abc-checkbox abc-checkbox-primary">
+              <input class="form-check-input"
+                     type="checkbox"
                      name="confirmation"
                      id="confirmation"
                      formControlName="confirmation"
                      autofocus>
-              <label i18n
+              <label class="form-check-label"
+                     i18n
                      for="confirmation">Yes, I am sure.</label>
             </div>
           </div>
index 9602ad784c2fe42024f85ba986a13c72d9ab4390..391c5416440f07031b915f5a9aaa0c8ffc258753 100644 (file)
@@ -17,16 +17,16 @@ export class MockModule {}
 
 @Component({
   template: `
-    <button type="button" class="btn btn-sm btn-primary" (click)="openCtrlDriven()">
-      <i class="fa fa-fw fa-times"></i>Deletion Ctrl-Test
+    <button type="button" class="btn btn-secondary" (click)="openCtrlDriven()">
+      <i class="fa fa-times"></i>Deletion Ctrl-Test
       <ng-template #ctrlDescription>
         The spinner is handled by the controller if you have use the modal as ViewChild in order to
         use it's functions to stop the spinner or close the dialog.
       </ng-template>
     </button>
 
-    <button type="button" class="btn btn-sm btn-primary" (click)="openModalDriven()">
-      <i class="fa fa-fw fa-times"></i>Deletion Modal-Test
+    <button type="button" class="btn btn-secondary" (click)="openModalDriven()">
+      <i class="fa fa-times"></i>Deletion Modal-Test
       <ng-template #modalDescription>
         The spinner is handled by the modal if your given deletion function returns a Observable.
       </ng-template>
index b60ccc3e3068613fd872bb2fedd2a2c7249d8ff4..b94fe85689f1c6f49742cb270f88d9de851c648d 100644 (file)
@@ -20,7 +20,7 @@
 
 <div class="button-group text-right"
      *ngIf="backAction.observers.length > 0">
-  <button class="btn btn-sm btn-default tc_backButton"
+  <button class="btn btn-light tc_backButton"
           type="button"
           (click)="backAction.emit()"
           autofocus
index 51ecf44445a9c76c7b26403b5e9c3af5d612d9ab..c774a4a32e72f57d0ce48177dd90149163284d9c 100644 (file)
@@ -4,50 +4,56 @@
 
 <cd-info-panel *ngIf="!grafanaExist"
                i18n>Please consult the
-  <a href="{{ docsUrl }}" target="_blank">documentation</a> on how to
+  <a href="{{ docsUrl }}"
+     target="_blank">documentation</a> on how to
   configure and enable the monitoring functionality.</cd-info-panel>
 
 <cd-info-panel *ngIf="!dashboardExist"
                i18n>Grafana Dashboard doesn't exist. Please refer to
-  <a href="{{ docsUrl }}" target="_blank">documentation</a> on how to
+  <a href="{{ docsUrl }}"
+     target="_blank">documentation</a> on how to
   add dashboards to Grafana.</cd-info-panel>
 
-<div class="row"
-     *ngIf="grafanaExist && dashboardExist">
-  <div class="col-md-12 timepicker">
-    <label class="control-label col-sm-1"
-           for="timepicker-control">
-      <ng-container i18n>Grafana Time Picker</ng-container>
-    </label>
-    <div class="col-sm-9">
-      <select id="timepicker"
-              name="timepicker-control"
-              class="form-control "
-              [(ngModel)]="time"
-              (ngModelChange)="onTimepickerChange($event)">
-        <option *ngFor="let key of grafanaTimes"
-                [ngValue]="key.value">{{ key.name }}
-        </option>
-      </select>
+<ng-container *ngIf="grafanaExist && dashboardExist">
+  <div class="row">
+    <div class="col-12">
+      <div class="form-inline timepicker">
+        <label for="timepicker"
+               class="ml-1 my-1"
+               i18n>Grafana Time Picker</label>
+
+        <select id="timepicker"
+                name="timepicker"
+                class="custom-select my-1 mx-3"
+                [(ngModel)]="time"
+                (ngModelChange)="onTimepickerChange($event)">
+          <option *ngFor="let key of grafanaTimes"
+                  [ngValue]="key.value">{{ key.name }}
+          </option>
+        </select>
+
+        <button class="btn btn-light my-1"
+                i18n-title
+                title="Reset Settings"
+                (click)="reset()">
+          <i [ngClass]="[icons.undo]"></i>
+        </button>
+      </div>
     </div>
-    <button class="btn btn-sm"
-            i18n-title
-            title="Reset Settings"
-            (click)="reset()">
-      <i [ngClass]="[icons.undo]"></i>
-    </button>
-    <br>
   </div>
-  <div class="col-md-12">
-    <div class="grafana-container">
-      <iframe #iframe
-              id="iframe"
-              [src]="grafanaSrc"
-              class="grafana"
-              [ngClass]="panelStyle"
-              frameborder="0"
-              scrolling="no">
-      </iframe>
+
+  <div class="row">
+    <div class="col-12">
+      <div class="grafana-container">
+        <iframe #iframe
+                id="iframe"
+                [src]="grafanaSrc"
+                class="grafana"
+                [ngClass]="panelStyle"
+                frameborder="0"
+                scrolling="no">
+        </iframe>
+      </div>
     </div>
   </div>
-</div>
+</ng-container>
index fe30025c5b50b6d5bed4cc42aa6512375671d76c..9a095d7e9bad31c3370f4d0480539c930af9389f 100644 (file)
 }
 
 .timepicker {
-  select {
-    display: inline-block;
-  }
-
   label {
-    font-size: 1.05em;
-    padding: 5px !important;
-  }
-}
-
-button {
-  margin-bottom: 10px;
-  margin-left: 10px;
-  float: right;
-  i {
-    font-size: 14px;
-    padding: 2px;
+    font-weight: 700;
   }
 }
 
index 4fca0b72c2b677af6eca09c9670484e26e9d9137..46d3ceaa645160cc789b918bf7ee1c8c91dbbd8b 100644 (file)
@@ -1,4 +1,5 @@
 <div dropdown\r
+     class="btn-group"\r
      *ngIf="isDropdown">\r
   <a dropdownToggle\r
      class="dropdown-toggle"\r
@@ -6,7 +7,6 @@
      i18n-title\r
      title="Select a Language">\r
     {{ supportedLanguages[selectedLanguage] }}\r
-    <span class="caret"></span>\r
   </a>\r
   <ul *dropdownMenu\r
       class="dropdown-menu dropdown-menu-right">\r
index 651801c7e5548e4df0440fad78144b666b661bbc..a07b9f91f31654e3686e190eaaa64495d8c7053e 100644 (file)
@@ -1,6 +1,6 @@
 <alert type="info">
   <strong>
-    <i [ngClass]="[icons.spinner, icons.spin, icons.width]"
+    <i [ngClass]="[icons.spinner, icons.spin]"
        aria-hidden="true"></i>
   </strong>
   <ng-content></ng-content>
index 9f56f9efb993c9bd397111b9354162bf319e792e..5cbd4f58c52fa4515e72ce129db817d96abc5e48 100644 (file)
@@ -1,9 +1,9 @@
 <div class="modal-header">
-  <h4 class="modal-title pull-left">
+  <h4 class="modal-title float-left">
     <ng-content select=".modal-title"></ng-content>
   </h4>
   <button type="button"
-          class="close pull-right"
+          class="close float-right"
           aria-label="Close"
           (click)="close()">
     <span aria-hidden="true">&times;</span>
index ce90465370a2fbd1244a75bc2e88b2c22c4973cc..0f85c6d8379db618a498203f3570da0889663fce 100644 (file)
@@ -1,18 +1,17 @@
 <div class="row">
-  <div class="col-xs-5 col-sm-2 refresh-selector">
-    <label class="control-label col-xs-5 col-sm-5" 
-           for="refreshInterval">
-      <span i18n>Refresh</span>
-    </label>
-    <div class="col-xs-7 col-sm-7">
-      <select id="refreshInterval" 
-              name="refreshInterval" 
-              class="form-control" 
+  <div class="col-12">
+    <div class="float-right d-inline-flex">
+      <label for="refreshInterval"
+             class="m-2"
+             i18n>Refresh</label>
+      <select id="refreshInterval"
+              name="refreshInterval"
+              class="form-control"
               (change)="changeRefreshInterval($event.target.value)"
               [(ngModel)]="selectedInterval">
-        <option *ngFor="let key of intervalKeys" 
+        <option *ngFor="let key of intervalKeys"
                 [value]="intervalList[key]">{{ key }}</option>
       </select>
     </div>
   </div>
-</div>
\ No newline at end of file
+</div>
index 3440b87454923c8ebab1484800d4d09f792e10a0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,26 +0,0 @@
-.refresh-selector {
-  padding: 0;
-  float: right;
-  margin-right: 60px;
-
-  * {
-    padding: 0;
-    box-sizing: border-box;
-  }
-
-  label {
-    padding: 10px 10px 0 0;
-    text-align: right;
-    margin: 0;
-  }
-
-  @media (min-width: 500px) and (max-width: 767px) {
-    width: 24vw;
-  }
-  @media (min-width: 1200px) {
-    width: 12vw;
-  }
-  @media (min-width: 1400px) {
-    width: 10vw;
-  }
-}
index 02c5458f814441e5a4c024e3072e66af73e97bce..33eeb80ffc99b5653fa8066f355cff2d2caacc4b 100644 (file)
@@ -5,14 +5,14 @@
            [selectionLimit]="selectionLimit"
            [customBadges]="customBadges"
            [customBadgeValidators]="customBadgeValidators"
-           elemClass="margin-right-sm select-menu-edit"
+           elemClass="mr-2 select-menu-edit"
            (selection)="selection.emit($event)">
-  <i [ngClass]="[icons.edit, icons.width]"></i>
+  <i [ngClass]="[icons.edit]"></i>
 </cd-select>
 
 <span *ngFor="let dataItem of data">
-  <span class="badge badge-pill badge-primary margin-right-sm">
-    <span class="margin-right-sm">{{ dataItem }}</span>
+  <span class="badge badge-pill badge-dark mr-2">
+    <span class="mr-2">{{ dataItem }}</span>
     <a class="badge-remove"
        (click)="cdSelect.removeItem(dataItem)">
       <i [ngClass]="[icons.destroy]"
index d5f2a30d099ae3d6cb86ca1539359ef2f4a12607..9bda676bee6416d4ed733f586da3a9fd04c91d90 100644 (file)
@@ -1,8 +1,9 @@
-@import '../../../../defaults';
+@import 'defaults';
 
-::ng-deep .select-menu-edit {
-  margin-left: -20px;
-}
 .badge-remove {
   color: $color-solid-white;
 }
+
+i.fa-pencil {
+  font-size: 1.1rem;
+}
index 6a58995894ce83f1e35aaacd2fd7afa5bc6ce07c..a6e7102db786e22ebe4652344808a00c9abad82e 100644 (file)
@@ -3,7 +3,7 @@
         #formDir="ngForm"
         [formGroup]="form"
         novalidate>
-    <div [ngClass]="{'has-error': form.showError('filter', formDir)}">
+    <div [ngClass]="{':invalid': form.showError('filter', formDir)}">
       <input type="text"
              formControlName="filter"
              i18n-placeholder
@@ -11,7 +11,7 @@
              (keyup)="$event.keyCode == 13 ? selectOption() : updateFilter()"
              class="form-control text-center" />
       <ng-container *ngFor="let error of Object.keys(messages.customValidations)">
-        <span class="help-block text-center"
+        <span class="form-text text-muted text-center"
               *ngIf="form.showError('filter', formDir) && filter.hasError(error)">
           {{ messages.customValidations[error] }}
         </span>
@@ -32,7 +32,7 @@
       {{ option.name }}
       <ng-container *ngIf="option.description">
         <br>
-        <small class="text-muted">
+        <small class="form-text text-muted">
           {{ option.description }}&nbsp;
         </small>
       </ng-container>
@@ -50,9 +50,9 @@
       {{ messages.add }} '{{ filter.value }}'
     </div>
   </div>
-  <div class="has-warning"
+  <div class=":invalid"
        *ngIf="data.length === selectionLimit">
-    <span class="help-block text-center text-warning"
+    <span class="form-text text-muted text-center text-warning"
           [tooltip]="messages.selectionLimit.tooltip"
           *ngIf="data.length === selectionLimit">
       {{ messages.selectionLimit.text }}
    placement="bottom"
    container="body"
    outsideClick="true"
-   *ngIf="options.length > 0">
+   *ngIf="options.length > 0"
+   class="float-left">
   <ng-content></ng-content>
 </a>
-<span class="text-muted"
+
+<span class="form-text text-muted float-left"
       *ngIf="data.length === 0 && options.length > 0">
   {{ messages.empty }}
 </span>
-<span class="text-muted"
+
+<span class="form-text text-muted  float-left"
       *ngIf="options.length === 0">
   {{ messages.noOptions }}
 </span>
index 59f633f73b7e98305186abf031727a356eb86f0d..6145f0bf4c73410936896864f840634eec6e6574 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'defaults';
 
 .select-menu-item {
   display: block;
index 94604fefec11004edaec0f7ad06aa0e76efc0abc..4a517f39ef78efb229fbf46c1e118697c3ebd32e 100644 (file)
@@ -1,9 +1,9 @@
 <button [type]="type"
-        class="btn btn-sm btn-primary tc_submitButton"
+        class="btn btn-secondary tc_submitButton"
         [disabled]="loading || disabled"
         (click)="submit($event)">
   <ng-content></ng-content>
   <span *ngIf="loading">
-    <i [ngClass]="[icons.spinner, icons.spin, icons.width]"></i>
+    <i [ngClass]="[icons.spinner, icons.spin]"></i>
   </span>
 </button>
index 93348f16acb5eeaf2e94a6ea01fb15973b93e453..e75d09087843ece0bc4cb07495568dda8024b877 100644 (file)
   </table>
 </ng-template>
 
-<div class="progress oaprogress"
+<div class="progress"
      data-placement="left"
      [tooltip]="usageTooltipTpl">
-  <div class="progress-bar progress-bar-info"
+  <div class="progress-bar bg-info"
        role="progressbar"
        [style.width]="usedPercentage + '%'">
     <span>{{ usedPercentage }}%</span>
   </div>
-  <div class="progress-bar progress-bar-freespace"
+  <div class="progress-bar bg-freespace"
        role="progressbar"
        [style.width]="freePercentage + '%'">
   </div>
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6d178b4738efb5b321fb5f3f139f2b4e34fd4323 100644 (file)
@@ -0,0 +1,27 @@
+@import 'defaults';
+
+.bg-info {
+  background-color: $color-progress-bar-info-bg !important;
+}
+
+.bg-freespace {
+  background-color: $color-progress-bar-freespace-bg !important;
+}
+
+.progress {
+  height: 20px;
+  position: relative;
+  margin-bottom: 0;
+
+  div.progress-bar {
+    position: static;
+  }
+
+  span {
+    position: absolute;
+    display: block;
+    width: 100%;
+    color: $color-progress-text;
+    font-weight: normal;
+  }
+}
index 89e37e6f948cccd64927422fa96bbdbe01dcd8c7..dddbe4f6acc08fe61f19b0fc46c085fa3f5b8e5e 100644 (file)
@@ -2,19 +2,18 @@
      dropdown>
   <ng-container *ngIf="getCurrentButton() as action">
     <button type="button"
-            class="btn btn-sm btn-{{btnColor}}"
+            class="btn btn-{{btnColor}}"
             [ngClass]="{'disabled': disableSelectionAction(action)}"
             (click)="useClickAction(action)"
             [routerLink]="useRouterLink(action)">
-      <i [ngClass]="[action.icon, icons.width]"></i><span>{{ action.name }}</span>
+      <i [ngClass]="[action.icon]"></i><span>{{ action.name }}</span>
     </button>
   </ng-container>
   <button type="button"
           dropdownToggle
           *ngIf="showDropDownActions()"
-          class="btn btn-sm btn-{{btnColor}} dropdown-toggle dropdown-toggle-split">
+          class="btn btn-{{btnColor}} dropdown-toggle dropdown-toggle-split">
     <ng-container *ngIf="dropDownOnly">{{ dropDownOnly }} </ng-container>
-    <span class="caret"></span>
     <span *ngIf="!dropDownOnly"
           class="sr-only"></span>
   </button>
     <ng-container *ngFor="let action of dropDownActions">
       <li role="menuitem"
           class="{{ toClassName(action['name']) }}"
-          [ngClass]="{'disabled': disableSelectionAction(action)}"
           data-toggle="tooltip" title="{{ useDisableDesc(action) }}">
         <a class="dropdown-item"
            (click)="useClickAction(action)"
-           [routerLink]="useRouterLink(action)">
-          <i [ngClass]="[action.icon, icons.width]"></i><span>{{ action.name }}</span>
+           [routerLink]="useRouterLink(action)"
+           [ngClass]="{'disabled': disableSelectionAction(action)}">
+          <i [ngClass]="[action.icon]"></i><span>{{ action.name }}</span>
         </a>
       </li>
     </ng-container>
index e3c3492a403ea3d21017fd3a717b959a1338ab14..58ba9a31abd148c54b6038c33dfd8b6a16f32a3c 100644 (file)
@@ -1,4 +1,10 @@
+@import '~bootstrap/scss/bootstrap-grid';
+
 .dropdown-menu > .disabled > a {
   pointer-events: auto;
   cursor: default !important;
 }
+
+::ng-deep .btn-toolbar .btn-group {
+  @extend .mr-1;
+}
index 95216a4b19e61873c4f5e2fd65ad95472a0d990f..824c9b74edd0153d3253cd378e81fc046dbd1dd1 100644 (file)
@@ -20,7 +20,7 @@ export class TableActionsComponent implements OnInit {
   @Input()
   tableActions: CdTableAction[];
   @Input()
-  btnColor = 'primary';
+  btnColor = 'secondary';
 
   // Use this if you just want to display a drop down button,
   // labeled with the given text, with all actions in it.
index 35d0a87125d9d1c38dbfd2cb6501c3c75a1820b3..9bbf4fb0598cc258922edf735589ebbff6970afc 100644 (file)
@@ -3,6 +3,7 @@ import { FormsModule } from '@angular/forms';
 import { RouterTestingModule } from '@angular/router/testing';
 
 import { NgxDatatableModule } from '@swimlane/ngx-datatable';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
 
 import { configureTestBed } from '../../../../testing/unit-test-helper';
 import { ComponentsModule } from '../../components/components.module';
@@ -18,7 +19,13 @@ describe('TableKeyValueComponent', () => {
 
   configureTestBed({
     declarations: [TableComponent, TableKeyValueComponent],
-    imports: [FormsModule, NgxDatatableModule, ComponentsModule, RouterTestingModule]
+    imports: [
+      FormsModule,
+      NgxDatatableModule,
+      ComponentsModule,
+      RouterTestingModule,
+      BsDropdownModule.forRoot()
+    ]
   });
 
   beforeEach(() => {
index 940f989f9e3efb708546951d0ee8998ee1941d36..9e8443505cec363662e5fb3da1632fd0030f9ba9 100644 (file)
@@ -2,10 +2,10 @@
                 i18n>Failed to load data.</cd-error-panel>
 
 <div class="dataTables_wrapper">
-  <div class="dataTables_header clearfix form-inline"
+  <div class="dataTables_header clearfix"
        *ngIf="toolHeader">
     <!-- actions -->
-    <div class="oadatatableactions">
+    <div class="cd-datatable-actions">
       <ng-content select=".table-actions"></ng-content>
     </div>
     <!-- end actions -->
 
     <!-- search -->
     <div class="input-group">
-      <span class="input-group-addon">
+      <span class="input-group-prepend">
+        <span class="input-group-text">
         <i [ngClass]="[icons.search]"></i>
+        </span>
       </span>
       <input class="form-control"
              type="text"
              [(ngModel)]="search"
              (keyup)="updateFilter()">
-      <span class="input-group-btn">
+      <div class="input-group-append">
         <button type="button"
-                class="btn btn-default clear-input tc_clearInputBtn"
+                class="btn btn-light"
                 (click)="updateFilter(true)">
           <i class="icon-prepend {{ icons.destroy }}"></i>
         </button>
-      </span>
+      </div>
     </div>
     <!-- end search -->
 
     <!-- show hide columns -->
     <div class="widget-toolbar">
       <div dropdown
+           [autoClose]="false"
            class="dropdown tc_menuitem tc_menuitem_cluster">
         <a dropdownToggle
-           class="btn btn-sm btn-default dropdown-toggle tc_columnBtn"
+           class="btn btn-light dropdown-toggle tc_columnBtn"
            data-toggle="dropdown">
           <i [ngClass]="[icons.large, icons.table]"></i>
         </a>
         <ul *dropdownMenu
-            class="dropdown-menu">
+            class="dropdown-menu px-3">
           <li *ngFor="let column of columns">
-            <label>
-              <input type="checkbox"
+
+            <div class="form-check abc-checkbox abc-checkbox-primary">
+              <input class="form-check-input"
+                     type="checkbox"
                      (change)="toggleColumn($event)"
                      [name]="column.prop"
+                     [id]="column.prop"
                      [checked]="!column.isHidden">
-              <span>{{ column.name }}</span>
-            </label>
+              <label class="form-check-label"
+                     [for]="column.prop">{{ column.name }}</label>
+            </div>
           </li>
         </ul>
       </div>
     <!-- refresh button -->
     <div class="widget-toolbar tc_refreshBtn"
          *ngIf="fetchData.observers.length > 0">
-      <a (click)="refreshBtn()">
+
+      <button type="button"
+              class="btn btn-light"
+              (click)="refreshBtn()">
         <i [ngClass]="[icons.large, icons.refresh]"
            [class.fa-spin]="updating || loadingIndicator"></i>
-      </a>
+      </button>
     </div>
     <!-- end refresh button -->
   </div>
   <ngx-datatable #table
-                 class="bootstrap oadatatable"
+                 class="bootstrap cd-datatable"
                  [cssClasses]="paginationClasses"
                  [selectionType]="selectionType"
                  [selected]="selection.selected"
 
 <ng-template #checkIconTpl
              let-value="value">
-  <i [ngClass]="[icons.check, icons.width]"
+  <i [ngClass]="[icons.check]"
      [hidden]="!value"></i>
 </ng-template>
 
 <ng-template #executingTpl
              let-row="row"
              let-value="value">
-  <i [ngClass]="[icons.spinner, icons.width, icons.spin]"
+  <i [ngClass]="[icons.spinner, icons.spin]"
      *ngIf="row.cdExecuting"></i>
   {{ value }}
   <span *ngIf="row.cdExecuting"
index a2259c8278cc97aa45d451da431ec78baa078a31..5a6e0d4db77e518586fc58085271c6908b40017e 100644 (file)
@@ -1,4 +1,4 @@
-@import '../../../../defaults';
+@import 'styles';
 
 .dataTables_wrapper {
   margin-bottom: 25px;
     display: inline-block;
     vertical-align: middle;
   }
+
   .widget-toolbar {
-    display: inline-block;
     float: right;
-    width: auto;
-    height: 30px;
-    line-height: 28px;
-    position: relative;
+    // width: auto;
+    // height: 30px;
+    // line-height: 28px;
+    // position: relative;
     border-left: 1px solid $color-table-seperator-border;
-    cursor: pointer;
+    // cursor: pointer;
     padding: 0 8px;
-    text-align: center;
+    // text-align: center;
+
+    .form-check {
+      padding-left: 0;
+    }
   }
+
   .dropdown-menu {
     white-space: nowrap;
     & > li {
@@ -41,9 +46,6 @@
       }
     }
   }
-  th.oadatatablecheckbox {
-    width: 16px;
-  }
   .dataTables_length > input {
     line-height: 25px;
     text-align: right;
@@ -55,7 +57,7 @@
   border-bottom: none;
   padding: 5px;
   position: relative;
-  .oadatatableactions {
+  .cd-datatable-actions {
     float: left;
   }
   ::ng-deep .table-filters {
     .form-control {
       height: 30px;
     }
-    .clear-input {
-      height: 30px;
-      i {
-        vertical-align: text-top;
-      }
-    }
   }
   .input-group.dataTables_paginate {
     width: 8%;
   }
 }
 
-::ng-deep .oadatatable {
+::ng-deep .cd-datatable {
   border: 1px solid $color-table-header-border;
   margin-bottom: 0;
   max-width: none !important;
+
   .progress-linear {
     display: block;
     position: relative;
     height: 5px;
     padding: 0;
     margin: 0;
+
     .container {
       background-color: $color-table-active-row;
+
       .bar {
         left: 0;
         height: 100%;
         overflow: hidden;
         background-color: $color-table-active-row;
       }
+
       .bar:before {
         display: block;
         position: absolute;
       }
     }
   }
+
   .datatable-header {
     background-clip: padding-box;
     background-color: $color-table-datatable-header;
     );
     background-repeat: repeat-x;
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffafafa', endColorstr='#ffededed', GradientType=0);
+
     .sort-asc,
     .sort-desc {
       color: $color-table-sort;
     }
+
     .datatable-header-cell {
       @include table-cell;
+
       text-align: left;
       font-weight: bold;
+
       .datatable-header-cell-label {
         &:after {
           font-family: ForkAwesome;
           width: 12px;
         }
       }
+
       &.sortable {
         .datatable-header-cell-label:after {
           content: ' \f0dc';
         }
+
         &.sort-active {
           &.sort-asc .datatable-header-cell-label:after {
             content: ' \f160';
           }
+
           &.sort-desc .datatable-header-cell-label:after {
             content: ' \f161';
           }
         }
       }
+
       &:first-child {
         border-left: none;
       }
     }
   }
   .datatable-body {
+    margin-bottom: -6px;
+
     .empty-row {
       background-color: $color-table-empty-row;
       text-align: center;
       padding-bottom: 5px;
     }
     .datatable-body-row {
-      .label {
-        font-size: 0.9em;
-      }
       &.clickable:hover .datatable-row-group {
         background-color: $color-table-hover-row;
         transition-property: background;
     }
   }
   .datatable-footer {
+    @extend .p-2;
+
     .selected-count,
     .page-count {
       font-style: italic;
       padding-left: 5px;
     }
-    .datatable-pager .pager {
-      margin-right: 5px !important;
-      & li:not(:first-child) {
-        /** Add space between buttons */
-        margin-left: 3px;
-      }
-      & li > a,
-      & li > span {
-        border-radius: 3px;
-      }
-      .pages {
-        & > a,
-        & > span {
-          display: inline-block;
-          padding: 5px 10px;
-          margin-bottom: 5px;
-          border: none;
-        }
-        a:hover {
-          background-color: $color-table-active-row;
-        }
-        &.active > a {
-          background-color: $color-table-active-row-hover;
+    .datatable-pager {
+      // .pager
+      ul {
+        @extend .pagination;
+
+        li {
+          @extend .page-item;
+
+          a {
+            @extend .page-link;
+          }
         }
       }
     }
index aa86e5de32d6aaf5af4e22aab5ee7a738e1389b4..1fa2d5a0498d48b5ad2a7724cabb4e2a6369ee5b 100644 (file)
@@ -4,6 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing';
 
 import { NgxDatatableModule } from '@swimlane/ngx-datatable';
 import * as _ from 'lodash';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
 
 import { configureTestBed } from '../../../../testing/unit-test-helper';
 import { ComponentsModule } from '../../components/components.module';
@@ -32,7 +33,13 @@ describe('TableComponent', () => {
 
   configureTestBed({
     declarations: [TableComponent],
-    imports: [NgxDatatableModule, FormsModule, ComponentsModule, RouterTestingModule]
+    imports: [
+      NgxDatatableModule,
+      FormsModule,
+      ComponentsModule,
+      RouterTestingModule,
+      BsDropdownModule.forRoot()
+    ]
   });
 
   beforeEach(() => {
@@ -354,9 +361,9 @@ describe('TableComponent', () => {
   describe('useCustomClass', () => {
     beforeEach(() => {
       component.customCss = {
-        'label label-danger': 'active',
+        'badge badge-danger': 'active',
         'secret secret-number': 123.456,
-        'btn btn-sm': (v) => _.isString(v) && v.startsWith('http'),
+        btn: (v) => _.isString(v) && v.startsWith('http'),
         secure: (v) => _.isString(v) && v.startsWith('https')
       };
     });
@@ -373,7 +380,7 @@ describe('TableComponent', () => {
     });
 
     it('should match a string and return the corresponding class', () => {
-      expect(component.useCustomClass('active')).toBe('label label-danger');
+      expect(component.useCustomClass('active')).toBe('badge badge-danger');
     });
 
     it('should match a number and return the corresponding class', () => {
@@ -381,11 +388,11 @@ describe('TableComponent', () => {
     });
 
     it('should match against a function and return the corresponding class', () => {
-      expect(component.useCustomClass('http://no.ssl')).toBe('btn btn-sm');
+      expect(component.useCustomClass('http://no.ssl')).toBe('btn');
     });
 
     it('should match against multiple functions and return the corresponding classes', () => {
-      expect(component.useCustomClass('https://secure.it')).toBe('btn btn-sm secure');
+      expect(component.useCustomClass('https://secure.it')).toBe('btn secure');
     });
   });
 });
index 23aa4c12c8a86c0ea82d295dc1ea0c01e86a389f..4f9f8da9cbf22025fe70c24135a6ddeda99f54ff 100644 (file)
@@ -17,7 +17,6 @@ export class Copy2ClipboardButtonDirective implements OnInit {
 
   ngOnInit() {
     const iElement = this.renderer.createElement('i');
-    this.renderer.addClass(iElement, 'icon-prepend');
     this.renderer.addClass(iElement, 'fa');
     this.renderer.addClass(iElement, 'fa-clipboard');
     this.renderer.appendChild(this.elementRef.nativeElement, iElement);
index 1a17b9f04b478634e1f05245b3ad8849661f01d0..d9129858aa0e74a54abea8b4085b0515dc3e7816 100644 (file)
@@ -14,7 +14,6 @@ export class PasswordButtonDirective implements OnInit {
   ngOnInit() {
     this.renderer.setAttribute(this.elementRef.nativeElement, 'tabindex', '-1');
     this.iElement = this.renderer.createElement('i');
-    this.renderer.addClass(this.iElement, 'icon-prepend');
     this.renderer.addClass(this.iElement, 'fa');
     this.renderer.appendChild(this.elementRef.nativeElement, this.iElement);
     this.update();
index 50578b8d0958a73ca777cdac9a49aa8d6f1162c1..4a9bdc4a738f982ef05280e7a5ad2383852ab164 100644 (file)
@@ -9,7 +9,7 @@ export enum Icons {
   exchange = 'fa fa-exchange', // Edit-Peer
   copy = 'fa fa-copy', // Copy
   clipboard = 'fa fa-clipboard', // Clipboard
-  flatten = 'fa-chain-broken', // Flatten, Link broken, Mark Lost
+  flatten = 'fa fa-chain-broken', // Flatten, Link broken, Mark Lost
   trash = 'fa fa-trash-o', // Move to trash
   lock = 'fa fa-lock', // Protect
   unlock = 'fa fa-unlock', // Unprotect
@@ -20,7 +20,7 @@ export enum Icons {
   stop = 'fa fa-stop', // Disable
   analyse = 'fa fa-stethoscope', // Scrub
   deepCheck = 'fa fa-cog', // Deep Scrub, Setting, Configuration
-  reweight = 'fa-balance-scale', // Reweight
+  reweight = 'fa fa-balance-scale', // Reweight
   left = 'fa fa-arrow-left', // Mark out
   right = 'fa fa-arrow-right', // Mark in
   down = 'fa fa-arrow-down', // Mark Down
@@ -59,7 +59,6 @@ export enum Icons {
   flag = 'fa fa-flag', // OSD configuration
 
   /* Icons for special effect */
-  width = 'fa fa-fw', // set one or more icons to the same fixed width
   large = 'fa fa-lg', // icon becomes 33% larger
   large2x = 'fa fa-2x', // icon becomes 50% larger
   large3x = 'fa fa-3x', // icon becomes 3 times larger
index 64d72b10ac8824e0dc8741e2d41bf5c8b75732cb..7614a3357fc5ea13b804c6938eb08428956f87ef 100644 (file)
@@ -1,4 +1,4 @@
-import { ToastOptions } from 'ng2-toastr';
+import { IndividualConfig } from 'ngx-toastr';
 import { Icons } from '../enum/icons.enum';
 import { NotificationType } from '../enum/notification-type.enum';
 
@@ -14,7 +14,7 @@ export class CdNotificationConfig {
     public type: NotificationType = NotificationType.info,
     public title?: string,
     public message?: string, // Use this for additional information only
-    public options?: any | ToastOptions,
+    public options?: any | IndividualConfig,
     public application: string = 'Ceph'
   ) {
     this.applicationClass = this.classes[this.application];
index e6fd703491d6608fc74a07a6850e6abd2a77d702..2c031fe18825e266083625b389e921ded03539df 100644 (file)
@@ -220,7 +220,7 @@ describe('NotificationService', () => {
       service.show(NotificationType.info, 'Some info');
       expect(toastr.info).toHaveBeenCalledWith(
         `<small class="date">${time}</small>` +
-          '<i class="pull-right custom-icon ceph-icon" title="Ceph"></i>',
+          '<i class="float-right custom-icon ceph-icon" title="Ceph"></i>',
         'Some info',
         undefined
       );
@@ -234,7 +234,7 @@ describe('NotificationService', () => {
       expect(toastr.error).toHaveBeenCalledWith(
         'Some operation failed<br>' +
           `<small class="date">${time}</small>` +
-          '<i class="pull-right custom-icon ceph-icon" title="Ceph"></i>',
+          '<i class="float-right custom-icon ceph-icon" title="Ceph"></i>',
         'Some error',
         undefined
       );
@@ -253,7 +253,7 @@ describe('NotificationService', () => {
       expect(toastr.success).toHaveBeenCalledWith(
         'Some alert resolved<br>' +
           `<small class="date">${time}</small>` +
-          '<i class="pull-right custom-icon prometheus-icon" title="Prometheus"></i>',
+          '<i class="float-right custom-icon prometheus-icon" title="Prometheus"></i>',
         'Alert resolved',
         undefined
       );
index 7dcb01392b06754841e4f9cd3b49a30fb9c9fbcc..996fa30ec5bf6c7b41e889697a73cfbbec9d1d46 100644 (file)
@@ -1,7 +1,7 @@
 import { Injectable } from '@angular/core';
 
 import * as _ from 'lodash';
-import { ToastOptions, ToastsManager } from 'ng2-toastr';
+import { IndividualConfig, ToastrService } from 'ngx-toastr';
 import { BehaviorSubject } from 'rxjs';
 
 import { NotificationType } from '../enum/notification-type.enum';
@@ -27,7 +27,7 @@ export class NotificationService {
   KEY = 'cdNotifications';
 
   constructor(
-    public toastr: ToastsManager,
+    public toastr: ToastrService,
     private taskMessageService: TaskMessageService,
     private cdDatePipe: CdDatePipe
   ) {
@@ -81,7 +81,7 @@ export class NotificationService {
     type: NotificationType,
     title: string,
     message?: string,
-    options?: any | ToastOptions,
+    options?: any | IndividualConfig,
     application?: string
   ): number;
   show(config: CdNotificationConfig | (() => CdNotificationConfig)): number;
@@ -89,7 +89,7 @@ export class NotificationService {
     arg: NotificationType | CdNotificationConfig | (() => CdNotificationConfig),
     title?: string,
     message?: string,
-    options?: any | ToastOptions,
+    options?: any | IndividualConfig,
     application?: string
   ): number {
     return window.setTimeout(() => {
@@ -167,7 +167,7 @@ export class NotificationService {
   renderTimeAndApplicationHtml(notification: CdNotification): string {
     return `<small class="date">${this.cdDatePipe.transform(
       notification.timestamp
-    )}</small><i class="pull-right custom-icon ${notification.applicationClass}" title="${
+    )}</small><i class="float-right custom-icon ${notification.applicationClass}" title="${
       notification.application
     }"></i>`;
   }
diff --git a/src/pybind/mgr/dashboard/frontend/src/defaults.scss b/src/pybind/mgr/dashboard/frontend/src/defaults.scss
deleted file mode 100644 (file)
index 9cf30b3..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*The file suppose to contain all variables, mixins and extends*/
-
-@import 'vendor.variables';
-
-$screen-sm-min: 768px !default;
-$screen-md-min: 992px !default;
-$screen-lg-min: 1200px !default;
-
-$screen-xs-max: calc(#{$screen-sm-min} - 1px);
-$screen-sm-max: calc(#{$screen-md-min} - 1px);
-$screen-md-max: calc(#{$screen-lg-min} - 1px);
-
-$color-solid-red: #ff0000 !default;
-$color-pink: #a94442 !default;
-$color-light-red: #f2dede !default;
-
-$color-orange: #ff6600 !default;
-
-$color-bright-yellow: #ffc200 !default;
-$color-light-yellow: #fff3cd !default;
-
-$color-bright-green: #00bb00 !default;
-$color-green: #71843f !default;
-
-$color-blue: #288cea !default;
-$color-light-blue: #d9edf7 !default;
-$color-sky-blue: #afd9ee !default;
-
-$color-black: #000 !default;
-$color-transparent-black: rgba(0, 0, 0, 0.7) !default;
-$color-solid-gray: #555555 !default;
-$color-dark-gray: #474544 !default;
-$color-gray: #505050 !default;
-$color-mild-gray: #777777 !default;
-$color-blue-gray: #90949c !default;
-$color-grad-gray: #ededed !default;
-$color-shadow-gray: rgba(3, 3, 3, 0.175) !default;
-$color-light-gray: #d1d1d1 !default;
-$color-soft-gray: #ddd !default;
-$color-white-gray: #eee !default;
-$color-shade-gray: #efefef !default;
-$color-light-shade-gray: #f3f3f3 !default;
-$color-whitesmoke-gray: #f5f5f5 !default;
-$color-solid-white: #ffffff !default;
-$color-transparent: rgba(0, 0, 0, 0.09) !default;
-$color-brand-teal: #2b99a8 !default;
-$color-brand-gray: #374249 !default;
-
-$color-primary: $color-brand-teal !default;
-$color-secondary: $color-brand-gray !default;
-$color-accent: #ef5c55 !default;
-
-$color-app-bg: $color-solid-white !default;
-$color-bg-darken: $color-dark-gray !default;
-$color-links: $color-primary !default;
-$color-links-focus: $color-dark-gray !default;
-$color-breadcrumb: $color-dark-gray !default;
-$color-button-text: $color-white-gray !default;
-$color-button: $color-primary !default;
-$color-button-hover: darken($color-primary, 3) !default;
-$color-button-border: darken($color-primary, 6) !default;
-$color-button-badge: $color-white-gray !default;
-$color-button-caret: $color-white-gray !default;
-$color-dropdown-menu: $color-dark-gray !default;
-$color-dropdown-active-text: $color-white-gray !default;
-$color-dropdown-active-bg: $color-primary !default;
-$color-caret-text: $color-solid-white !default;
-$color-progress-bar-info-bg: $color-primary !default;
-$color-progress-bar-freespace-bg: $color-light-gray !default;
-$color-oaprogress-text: $color-black !default;
-$color-tags-border: $color-light-gray !default;
-$color-tags-box-shadow: $color-transparent !default;
-$color-error-btn-bg: $color-light-red !default;
-$color-error-btn-border: $color-pink !default;
-$color-noscript-text: $color-mild-gray !default;
-$color-required-text: $color-pink !default;
-
-/*Button*/
-$button-radius: 1.875rem !default;
-
-/*Login*/
-$color-login-row-text: $color-solid-white !default;
-$color-login-row-bg: $color-secondary !default;
-$color-password-toggle-text: $color-solid-white !default;
-$color-password-toggle-bg: $color-solid-gray !default;
-$color-password-toggle-focus: $color-primary !default;
-$color-login-checkbox-bg: $color-primary !default;
-$color-login-checkbox-border: $color-primary !default;
-$color-login-active-row-bg: $color-light-yellow !default;
-$color-login-active-row-text: $color-black !default;
-
-/*Landing Page*/
-
-/*InfoGroup*/
-$color-info-group-underline: $color-whitesmoke-gray !default;
-
-/*InfoCard*/
-$color-info-card-background: $color-whitesmoke-gray !default;
-$color-info-card-border: $color-soft-gray !default;
-
-/*Navigation*/
-$color-navbar-bg: $color-secondary !default;
-$color-navbar-brand: $color-white-gray !default;
-$color-nav-top-bar: $color-primary !default;
-$color-nav-bottom-bar: $color-primary !default;
-$color-nav-toggle-bar: $color-white-gray !default;
-$color-nav-toggle-shadow: $color-solid-white !default;
-$color-nav-collapse-border: $color-white-gray !default;
-$color-nav-open-bg: $color-primary !default;
-$color-nav-links: $color-white-gray !default;
-$color-nav-links-hover: $color-primary !default;
-$color-nav-active-link-bg: $color-primary !default;
-$color-nav-border-top-collapse: $color-white-gray !default;
-
-/*Helper*/
-$color-helper-bg: $color-primary !default;
-
-/*Table*/
-$color-table-seperator-border: $color-transparent !default;
-$color-table-input-border: $color-transparent !default;
-$color-table-dropdown-bg: $color-whitesmoke-gray !default;
-$color-table-header-bg: $color-whitesmoke-gray !default;
-$color-table-header-border: $color-light-gray !default;
-$color-table-active-row: $color-sky-blue !default;
-$color-table-active-row-hover: $color-light-blue !default;
-$color-table-progress-bar-bg: $color-sky-blue !default;
-$color-table-progress-bar-active: $color-primary !default;
-$color-table-gradient-1: $color-whitesmoke-gray !default;
-$color-table-gradient-2: $color-grad-gray !default;
-$color-table-sort: $color-primary !default;
-$color-table-empty-row: $color-light-yellow !default;
-$color-table-hover-row: $color-white-gray !default;
-$color-table-even-row-bg: $color-solid-white !default;
-$color-table-odd-row-bg: $color-whitesmoke-gray !default;
-$color-table-datatable-header: $color-whitesmoke-gray !default;
-
-/*Chart tooltip*/
-$color-chart-tooltip-bg: $color-transparent-black !default;
-$color-chat-tooltip-text: $color-solid-white !default;
-$color-chart-tooltip-border: $color-black !default;
-
-/*Popover*/
-$color-popover-seperator-text: $color-blue-gray !default;
-$color-popover-seperator-bg: $color-white-gray !default;
-$color-popover-message-text: $color-dark-gray !default;
-$color-popover-table-text: $color-dark-gray !default;
-$color-popover-date: $color-solid-gray !default;
-
-/*RGW user form*/
-$color-rgw-icon: $color-blue-gray !default;
-
-@mixin table-cell {
-  padding: 5px;
-  border: none;
-  border-left: 1px solid $color-light-gray;
-  border-bottom: 1px solid $color-light-gray;
-}
-
-@mixin hf {
-  border-bottom: 1px solid $color-light-gray;
-  background-color: $color-whitesmoke-gray;
-}
-
-@function strip-unit($value) {
-  @return $value / ($value * 0 + 1);
-}
-
-@mixin fluid-font-size($min-vw, $max-vw, $min-font-size, $max-font-size) {
-  $u1: unit($min-vw);
-  $u2: unit($max-vw);
-  $u3: unit($min-font-size);
-  $u4: unit($max-font-size);
-
-  @if $u1 == $u2 and $u1 == $u3 and $u1 == $u4 {
-    & {
-      font-size: $min-font-size;
-      @media screen and (min-width: $min-vw) {
-        font-size: calc(
-          #{$min-font-size} + #{strip-unit($max-font-size - $min-font-size)} *
-            ((100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)})
-        );
-      }
-      @media screen and (min-width: $max-vw) {
-        font-size: $max-font-size;
-      }
-    }
-  }
-}
index 05a8f70911674c969fd215efb2964bd94b8ef53f..f314e2c53a8f5e0fa991df7576f5f7fb69283105 100644 (file)
@@ -8,7 +8,7 @@
     document.write('<base href="' + document.location+ '" />');
   </script>
 
-  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
 </head>
 <body>
index 1a267838cc4255a8b13232c9c4c233e42ddc4e03..544e6e5b9fb6cd44a0bc04fdb3b105012e6d26b0 100644 (file)
@@ -1,9 +1,24 @@
 /* You can add global styles to this file, and also import other style files */
-
 @import 'defaults';
-$fa-font-path: '../node_modules/fork-awesome/fonts';
-@import '../node_modules/fork-awesome/scss/fork-awesome';
-$font_family_1: 'ForkAwesome';
+
+// Fork-Awesome
+$fa-font-path: '~fork-awesome/fonts';
+$font-family-icon: 'ForkAwesome';
+
+// Bootstrap
+$theme-colors: (
+  'primary': $color-primary,
+  'secondary': $color-accent,
+  'dark': $color-mild-gray
+);
+
+$font-family-sans-serif: 'Helvetica Neue', Helvetica, Arial, 'Noto Sans', sans-serif,
+  'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+$badge-font-size: 1rem;
+
+@import '~bootstrap/scss/bootstrap';
+@import '~fork-awesome/scss/fork-awesome';
 @import 'app/ceph/dashboard/info-card/info-card-popover.scss';
 
 /* Basics */
@@ -16,14 +31,6 @@ body {
   height: 100%;
   font-size: 12px;
 }
-a {
-  color: $color-links;
-  cursor: pointer;
-}
-a:hover,
-a:focus {
-  color: $color-links-focus;
-}
 h1 {
   letter-spacing: -1px;
   font-size: 2em;
@@ -45,11 +52,7 @@ option {
   font-weight: normal;
   font-style: normal;
 }
-/* For awesome-bootstrap-checkbox */
-.checkbox input[type='checkbox']:checked + label:after {
-  font-family: $font_family_1;
-}
-/*******/
+
 .full-height {
   height: 100%;
 }
@@ -83,6 +86,32 @@ option {
 }
 
 /* Buttons */
+.btn-light {
+  background-color: $color-solid-white !important;
+  border-color: $color-input-border !important;
+
+  &:hover {
+    background-color: $color-soft-gray !important;
+    border-color: $color-input-border-hover !important;
+  }
+}
+
+.btn-secondary,
+.btn-light {
+  border-radius: $button-radius;
+}
+
+form .input-group .btn-light {
+  border-radius: $border-radius;
+}
+
+// We have some inputs that don't have a corresponding formControlName,
+// to be able to get the same styling and no JS errors we need use a different
+// class name
+.cd-form-control {
+  @extend .form-control;
+}
+
 .btn {
   &,
   &:active,
@@ -93,64 +122,14 @@ option {
     }
   }
 }
-.btn-primary {
-  color: $color-button-text;
-  background-color: $color-accent;
-  border-color: $color-accent;
-  border-radius: $button-radius;
-}
-.btn-primary:hover,
-.btn-primary:focus,
-.btn-primary:active,
-.btn-primary.active,
-.open .dropdown-toggle.btn-primary {
-  color: $color-button-text;
-  background-color: lighten($color-accent, 10);
-  border-color: lighten($color-accent, 10);
-}
-.btn-primary:active,
-.btn-primary.active,
-.open .dropdown-toggle.btn-primary {
-  background-image: none;
-
-  &:hover,
-  &:focus {
-    background-color: lighten($color-accent, 10);
-    border-color: lighten($color-accent, 10);
-  }
-}
-.btn-primary.disabled,
-.btn-primary[disabled],
-fieldset[disabled] .btn-primary,
-.btn-primary.disabled:hover,
-.btn-primary[disabled]:hover,
-fieldset[disabled] .btn-primary:hover,
-.btn-primary.disabled:focus,
-.btn-primary[disabled]:focus,
-fieldset[disabled] .btn-primary:focus,
-.btn-primary.disabled:active,
-.btn-primary[disabled]:active,
-fieldset[disabled] .btn-primary:active,
-.btn-primary.disabled.active,
-.btn-primary[disabled].active,
-fieldset[disabled] .btn-primary.active {
-  background-color: $color-accent;
-  border-color: $color-accent;
-}
 .btn-primary .badge {
   color: $color-primary;
   background-color: $color-button-badge;
 }
-.btn-default {
-  border-radius: $button-radius;
-}
-.form-group .btn-default {
-  border-radius: 4px;
-}
 .btn-group > .btn > i.fa,
-button.btn.btn-label > i.fa {
+.cd-datatable-actions button.btn i.fa {
   /** Add space between icon and text */
-  padding-right: 5px;
+  margin-right: 5px;
 }
 
 /* Dropdown */
@@ -164,7 +143,7 @@ button.btn.btn-label > i.fa {
 }
 .dropdown-menu > li > a > i.fa {
   /** Add space between icon and text */
-  padding-right: 5px;
+  margin-right: 5px;
 }
 .dropdown-menu > .active > a {
   color: $color-dropdown-active-text;
@@ -176,15 +155,15 @@ button.btn.btn-label > i.fa {
     background-color: darken($color-dropdown-active-bg, 10);
   }
 }
-.dataTables_wrapper .dropdown-menu > li.divider {
+.dataTables_wrapper .dropdown-menu > li.dropdown-divider {
   cursor: auto;
 }
 
 /* Grid */
 .container,
 .container-fluid {
-  padding-left: 30px;
-  padding-right: 30px;
+  padding-left: 30px !important;
+  padding-right: 30px !important;
 }
 .row {
   margin-left: -30px;
@@ -226,68 +205,45 @@ button.btn.btn-label > i.fa {
 .col-sm-7,
 .col-sm-8,
 .col-sm-9,
-.col-xs-1,
-.col-xs-10,
-.col-xs-11,
-.col-xs-12,
-.col-xs-2,
-.col-xs-3,
-.col-xs-4,
-.col-xs-5,
-.col-xs-6,
-.col-xs-7,
-.col-xs-8,
-.col-xs-9 {
+.col-1,
+.col-10,
+.col-11,
+.col-12,
+.col-2,
+.col-3,
+.col-4,
+.col-5,
+.col-6,
+.col-7,
+.col-8,
+.col-9 {
   padding-left: 30px;
   padding-right: 30px;
 }
-/* Progressbar */
-.progress-bar {
-  background-image: none !important;
-}
-.progress-bar-info {
-  background-color: $color-progress-bar-info-bg;
-}
-.progress-bar-freespace {
-  background-color: $color-progress-bar-freespace-bg;
-}
-.oaprogress {
-  position: relative;
-  margin-bottom: 0;
-}
-.oaprogress div.progress-bar {
-  position: static;
-}
-.oaprogress span {
-  position: absolute;
-  display: block;
-  width: 100%;
-  color: $color-oaprogress-text;
-  font-weight: normal;
-}
 tags-input .tags {
   border-radius: 4px;
   border: 1px solid $color-tags-border;
   box-shadow: inset 0 1px 1px $color-tags-box-shadow;
 }
-uib-accordion .panel-title,
-.panel .accordion-title {
+uib-accordion .card-title,
+.card .accordion-title {
   font-size: 14px !important;
 }
-.panel-body h2:first-child {
-  margin-top: 0;
+.card-header {
+  font-size: 1.3em;
 }
-.pull-left {
-  float: left;
+.card-body h2:first-child {
+  margin-top: 0;
 }
 .disabled {
   pointer-events: none;
 }
-.clickable {
+.clickable,
+a {
   cursor: pointer;
 }
-.has-error .has-error-btn,
-.has-error .has-error-btn:disabled:hover {
+:invalid .has-error-btn,
+:invalid .has-error-btn:disabled:hover {
   background-color: $color-error-btn-bg;
   border-color: $color-error-btn-border;
 }
@@ -302,7 +258,7 @@ uib-accordion .panel-title,
   color: $color-required-text;
 }
 /* Forms */
-.form-group > .control-label > span.required {
+.form-group > .col-form-label > span.required {
   @extend .fa;
   @extend .fa-asterisk;
   @extend .required;
@@ -319,17 +275,19 @@ uib-accordion .panel-title,
     box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px 2px rgba($color-primary, 0.5);
   }
 }
-/* Panel */
-.panel-footer button.btn:not(:first-child) {
+
+.custom-checkbox {
+  padding-top: 7px;
+}
+
+/* Card */
+.card-footer button.btn:not(:first-child) {
   margin-left: 5px;
 }
 /* Modal dialog */
 .modal-footer button.btn:not(:first-child) {
   margin-left: 5px;
 }
-.margin-right-sm {
-  margin-right: 10px;
-}
 .nav-tabs {
   margin-bottom: 15px;
 }
@@ -361,12 +319,6 @@ uib-accordion .panel-title,
   background: $color-transparent-black !important;
 }
 
-h3.page-header {
-  margin-left: 1em;
-  margin-top: 1em;
-  border-color: #f0f0f0;
-}
-
 .tooltip-wide .tooltip-inner {
   width: 400px;
 }
@@ -382,3 +334,38 @@ h3.page-header {
   padding-left: 1em;
   margin: 0;
 }
+
+.cd-header,
+legend {
+  @extend .pb-1;
+  @extend .mt-4;
+  @extend .mb-4;
+  @extend .border-bottom;
+}
+
+@include media-breakpoint-up(sm) {
+  .col-form-label {
+    text-align: right;
+  }
+}
+
+.form-group > label {
+  font-weight: 700;
+}
+
+// Firefox is adding a white background-coor in these components
+cd-submit-button {
+  background-color: transparent !important;
+}
+
+// All '.fa' icons will have fixed width
+.fa {
+  @extend .fa-fw;
+}
+
+pre {
+  @extend .card;
+  @extend .bg-light;
+  @extend .p-2;
+  // @extend my-2;
+}
index b37e5fccf6f8a7b4372c1b6628360d2899e84225..3a574dfa5386fd3a54ce4ed5124d6aa9aae3f608 100644 (file)
@@ -1,4 +1,4 @@
-@import '../defaults';
+@import 'defaults';
 
 .chart-container {
   position: absolute;
diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/defaults.scss b/src/pybind/mgr/dashboard/frontend/src/styles/defaults.scss
new file mode 100644 (file)
index 0000000..145937f
--- /dev/null
@@ -0,0 +1,188 @@
+/*The file suppose to contain all variables, mixins and extends*/
+
+@import 'vendor.variables';
+
+$screen-sm-min: 576px !default;
+$screen-md-min: 768px !default;
+$screen-lg-min: 992px !default;
+$screen-xl-min: 1200px !default;
+
+$screen-xs-max: calc(#{$screen-sm-min} - 1px);
+$screen-sm-max: calc(#{$screen-md-min} - 1px);
+$screen-md-max: calc(#{$screen-lg-min} - 1px);
+$screen-lg-max: calc(#{$screen-xl-min} - 1px);
+
+$color-solid-red: #ff0000 !default;
+$color-pink: #a94442 !default;
+$color-light-red: #f2dede !default;
+
+// $color-orange: #ff6600 !default;
+
+$color-bright-yellow: #ffc200 !default;
+$color-light-yellow: #fff3cd !default;
+
+$color-bright-green: #00bb00 !default;
+// $color-green: #71843f !default;
+
+$color-blue: #288cea !default;
+$color-light-blue: #d1ecf1 !default;
+$color-sky-blue: #afd9ee !default;
+
+$color-black: #000 !default;
+$color-transparent-black: rgba(0, 0, 0, 0.7) !default;
+$color-solid-gray: #555555 !default;
+$color-dark-gray: #474544 !default;
+// $color-gray: #505050 !default;
+$color-mild-gray: #777777 !default;
+$color-blue-gray: #90949c !default;
+$color-grad-gray: #ededed !default;
+$color-shadow-gray: rgba(3, 3, 3, 0.175) !default;
+$color-light-gray: #d1d1d1 !default;
+$color-soft-gray: #ddd !default;
+$color-white-gray: #eee !default;
+$color-shade-gray: #efefef !default;
+$color-light-shade-gray: #f3f3f3 !default;
+$color-whitesmoke-gray: #f5f5f5 !default;
+$color-solid-white: #ffffff !default;
+$color-transparent: rgba(0, 0, 0, 0.09) !default;
+$color-input-border: #ced4da;
+$color-input-border-hover: #adadad;
+$color-brand-teal: #2b99a8 !default;
+$color-brand-gray: #374249 !default;
+
+$color-primary: $color-brand-teal !default;
+$color-secondary: $color-brand-gray !default;
+$color-accent: #ef5c55 !default;
+
+$color-app-bg: $color-solid-white !default;
+// $color-bg-darken: $color-dark-gray !default;
+// $color-links: $color-primary !default;
+// $color-links-focus: $color-dark-gray !default;
+$color-breadcrumb: $color-dark-gray !default;
+// $color-button-text: $color-white-gray !default;
+$color-button: $color-primary !default;
+// $color-button-hover: darken($color-primary, 3) !default;
+// $color-button-border: darken($color-primary, 6) !default;
+$color-button-badge: $color-white-gray !default;
+$color-dropdown-menu: $color-dark-gray !default;
+$color-dropdown-active-text: $color-white-gray !default;
+$color-dropdown-active-bg: $color-primary !default;
+$color-progress-bar-info-bg: $color-primary !default;
+$color-progress-bar-freespace-bg: $color-light-gray !default;
+$color-progress-text: $color-black !default;
+$color-tags-border: $color-light-gray !default;
+$color-tags-box-shadow: $color-transparent !default;
+$color-error-btn-bg: $color-light-red !default;
+$color-error-btn-border: $color-pink !default;
+$color-noscript-text: $color-mild-gray !default;
+$color-required-text: $color-pink !default;
+
+/*Button*/
+$button-radius: 1.875rem !default;
+
+/*Login*/
+$color-login-row-text: $color-solid-white !default;
+$color-login-row-bg: $color-secondary !default;
+$color-password-toggle-text: $color-solid-white !default;
+$color-password-toggle-bg: $color-solid-gray !default;
+$color-password-toggle-focus: $color-primary !default;
+// $color-login-active-row-bg: $color-light-yellow !default;
+// $color-login-active-row-text: $color-black !default;
+
+/*Landing Page*/
+
+/*InfoGroup*/
+// $color-info-group-underline: $color-whitesmoke-gray !default;
+
+/*InfoCard*/
+// $color-info-card-background: $color-whitesmoke-gray !default;
+$color-info-card-border: $color-soft-gray !default;
+
+/*Navigation*/
+$color-navbar-bg: $color-secondary !default;
+$color-navbar-brand: $color-white-gray !default;
+$color-nav-top-bar: $color-primary !default;
+$color-nav-bottom-bar: $color-primary !default;
+$color-nav-toggle-bar: $color-white-gray !default;
+$color-nav-toggle-shadow: $color-solid-white !default;
+$color-nav-collapse-border: $color-white-gray !default;
+$color-nav-open-bg: $color-primary !default;
+$color-nav-links: $color-white-gray !default;
+$color-nav-links-hover: $color-primary !default;
+$color-nav-active-link-bg: $color-primary !default;
+$color-nav-border-top-collapse: $color-white-gray !default;
+
+/*Helper*/
+$color-helper-bg: $color-primary !default;
+
+/*Table*/
+$color-table-seperator-border: $color-transparent !default;
+$color-table-input-border: $color-transparent !default;
+$color-table-dropdown-bg: $color-whitesmoke-gray !default;
+$color-table-header-bg: $color-whitesmoke-gray !default;
+$color-table-header-border: $color-light-gray !default;
+$color-table-active-row: $color-sky-blue !default;
+$color-table-active-row-hover: $color-light-blue !default;
+// $color-table-progress-bar-bg: $color-sky-blue !default;
+$color-table-progress-bar-active: $color-primary !default;
+$color-table-gradient-1: $color-whitesmoke-gray !default;
+$color-table-gradient-2: $color-grad-gray !default;
+$color-table-sort: $color-primary !default;
+$color-table-empty-row: $color-light-yellow !default;
+$color-table-hover-row: $color-white-gray !default;
+$color-table-even-row-bg: $color-solid-white !default;
+$color-table-odd-row-bg: $color-whitesmoke-gray !default;
+$color-table-datatable-header: $color-whitesmoke-gray !default;
+
+/*Chart tooltip*/
+$color-chart-tooltip-bg: $color-transparent-black !default;
+$color-chat-tooltip-text: $color-solid-white !default;
+$color-chart-tooltip-border: $color-black !default;
+
+/*Popover*/
+$color-popover-seperator-text: $color-blue-gray !default;
+$color-popover-seperator-bg: $color-white-gray !default;
+$color-popover-message-text: $color-dark-gray !default;
+$color-popover-table-text: $color-dark-gray !default;
+$color-popover-date: $color-solid-gray !default;
+
+/*RGW user form*/
+$color-rgw-icon: $color-blue-gray !default;
+
+@mixin table-cell {
+  padding: 5px;
+  border: none;
+  border-left: 1px solid $color-light-gray;
+  border-bottom: 1px solid $color-light-gray;
+}
+
+@mixin hf {
+  border-bottom: 1px solid $color-light-gray;
+  background-color: $color-whitesmoke-gray;
+}
+
+@function strip-unit($value) {
+  @return $value / ($value * 0 + 1);
+}
+
+@mixin fluid-font-size($min-vw, $max-vw, $min-font-size, $max-font-size) {
+  $u1: unit($min-vw);
+  $u2: unit($max-vw);
+  $u3: unit($min-font-size);
+  $u4: unit($max-font-size);
+
+  @if $u1 == $u2 and $u1 == $u3 and $u1 == $u4 {
+    & {
+      font-size: $min-font-size;
+      @media screen and (min-width: $min-vw) {
+        font-size: calc(
+          #{$min-font-size} + #{strip-unit($max-font-size - $min-font-size)} *
+            ((100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)})
+        );
+      }
+      @media screen and (min-width: $max-vw) {
+        font-size: $max-font-size;
+      }
+    }
+  }
+}
index ab747bf6c2fb8a6714738d709de5eb11562e4312..d15ab9d51a9fa3c2262356cbafaea7a91145d7a9 100644 (file)
@@ -1,4 +1,4 @@
-@import '../defaults';
+@import 'defaults';
 
 ::ng-deep .popover-content {
   padding: 0.5em;
diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/vendor.overrides.scss b/src/pybind/mgr/dashboard/frontend/src/styles/vendor.overrides.scss
new file mode 100644 (file)
index 0000000..0cca9de
--- /dev/null
@@ -0,0 +1,3 @@
+/* Vendor specific scss */
+
+@import 'defaults';
diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/vendor.variables.scss b/src/pybind/mgr/dashboard/frontend/src/styles/vendor.variables.scss
new file mode 100644 (file)
index 0000000..e35fef1
--- /dev/null
@@ -0,0 +1 @@
+/* Vendor specific variables */\r
diff --git a/src/pybind/mgr/dashboard/frontend/src/vendor.overrides.scss b/src/pybind/mgr/dashboard/frontend/src/vendor.overrides.scss
deleted file mode 100644 (file)
index 0cca9de..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* Vendor specific scss */
-
-@import 'defaults';
diff --git a/src/pybind/mgr/dashboard/frontend/src/vendor.variables.scss b/src/pybind/mgr/dashboard/frontend/src/vendor.variables.scss
deleted file mode 100644 (file)
index e35fef1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* Vendor specific variables */\r