| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <section class="container"> |
| <div class="row"> |
| <div class="col-sm-8 col-xs-6"> |
| <input ng-model="state.search.$" type="text" placeholder="Search for bundles or types" class="form-control" /> |
| </div> |
| <div class="col-sm-3 col-sm-offset-1 col-xs-6 text-right"> |
| <button class="btn btn-success" ng-click="launchCatalogUploader()"> |
| <i class="fa fa-fw fa-upload"></i> |
| Upload to catalog |
| </button> |
| </div> |
| </div> |
| <div class="row" ng-if="isNonEmpty(state.search)"> |
| <div class="col-md-12 clear-search" ng-click="clearSearchFilters()"> |
| <i class="fa fa-fw fa-window-close"></i> Clear current search query, filters, and sorts |
| </div> |
| </div> |
| |
| <div class="row"> |
| <div class="col-md-12"> |
| <header class="row filters"> |
| <div class="col-sm-6"> |
| <div class="btn-group btn-group-sm" role="group" aria-label="View switcher"> |
| <button ng-model="state.view" uib-btn-radio="'bundles'" type="button" class="btn btn-default" ng-class="{'btn-primary': state.view === 'bundles'}">Bundles</button> |
| <button ng-model="state.view" uib-btn-radio="'types'" type="button" class="btn btn-default" ng-class="{'btn-primary': state.view === 'types'}">Types</button> |
| </div> |
| </div> |
| <div class="col-sm-6 text-right"> |
| <div class="btn-group" uib-dropdown> |
| <button type="button" class="btn btn-link" uib-dropdown-toggle> |
| Version <span class="caret"></span> |
| </button> |
| <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu> |
| <li ng-repeat="version in config.versions | orderBy:'-' track by $index" ng-class="{'active': state.search.version === version}"> |
| <a ng-click="state.search.version = version">{{version}}</a> |
| </li> |
| </ul> |
| </div> |
| <div class="btn-group" uib-dropdown> |
| <button type="button" class="btn btn-link" uib-dropdown-toggle> |
| Sort <span class="caret"></span> |
| </button> |
| <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu> |
| <li ng-repeat="orderBy in config.orderBy track by orderBy.id" ng-class="{'active': state.orderBy === orderBy}"> |
| <a ng-click="state.orderBy = orderBy">{{orderBy.label}}</a> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </header> |
| </div> |
| |
| <div class="col-md-12"> |
| <ul class="list-group list-group-bundles" ng-if="state.view === 'bundles'"> |
| <li ng-repeat="bundle in bundles | filter:state.search | orderBy:state.orderBy.id as filteredBundles track by (bundle.symbolicName + bundle.version)" |
| ng-class="{'expanded': !isCollapsed, 'is-expandable': bundle.types.length > 0}" |
| class="list-group-item bundles-list"> |
| <div class="media bundle-top-region" ng-init="isCollapsed = true" ng-click="isCollapsed = bundle.types.length > 0 ? !isCollapsed : true"> |
| <div class="media-left"> |
| <a ui-sref="bundle({bundleId: bundle.symbolicName, bundleVersion: bundle.version})"> |
| <img ng-src="{{::bundle | iconGeneratorPipe:'symbolicName'}}" class="media-object" alt="{{::bundle.symbolicName}}'s logo" /> |
| </a> |
| </div> |
| <div class="media-body catalog-item-body"> |
| <div class="pull-right highlights" ng-bind-html="::bundle | bundleHighlights"></div> |
| <h4 class="media-heading"> |
| <a ui-sref="bundle({bundleId: bundle.symbolicName, bundleVersion: bundle.version})" class="list-group-item-heading"> |
| {{bundle | bundleName}} |
| </a> |
| <span class="label label-default">{{::bundle.version}}</span> |
| </h4> |
| <p class="media-auto-wrap text-muted" ng-if="bundle.symbolicName.startsWith('brooklyn-catalog-bom')"><small> |
| <i class="fa fa-fw fa-exclamation-circle"></i> This bundle comes from a BOM file that does not declare a bundle name |
| </small></p> |
| <p class="media-auto-wrap text-muted" ng-if="bundle.types.length == 0"><small> |
| <i class="fa fa-fw fa-exclamation-circle"></i> No registered types in this bundle |
| </small></p> |
| <p class="media-description">{{bundle | bundleDescription}}</p> |
| </div> |
| </div> |
| |
| <div class="extra" uib-collapse="isCollapsed"> |
| <!-- note entities are not filtered as search changes; but they will take an initial search; not intuitive --> |
| <div ng-init="filteredEntities = (bundle.types | bundleTypeFilter:'org.apache.brooklyn.api.entity.Entity' | filter:state.search)" ng-show="::filteredEntities.length > 0"> |
| <ul class="list-group list-group-types"> |
| <li class="list-group-item typed-group-table-header"> |
| <ng-pluralize count="::filteredEntities.length" |
| when="{'one': 'Entity', 'other': 'Entities'}"> |
| </ng-pluralize> |
| </li> |
| <li ng-repeat="entity in ::filteredEntities track by (entity.containingBundle + entity.symbolicName + entity.version)" |
| ng-if="!isCollapsed && $index < pagination.itemsPerPage" |
| ng-class="{'deprecated': entity.deprecated, 'disabled': entity.disabled}" |
| class="list-group-item"> |
| <type-item bundle="::bundle" type="::entity"></type-item> |
| </li> |
| <!-- quick and dirty pagination; should improve / refactor / apply to others; but for now we are only dealing with bundles |
| that might have 1000 entities so only focused on that --> |
| <div ng-if="::filteredEntities.length > pagination.itemsPerPage" style="text-align: right;"> |
| <i>Only showing {{ pagination.itemsPerPage }} of {{ ::filteredEntities.length }}</i> |
| |
| <a ng-click="pagination.itemsPerPage = pagination.itemsPerPage + 20">Show more</a> |
| |
| <a ng-click="pagination.itemsPerPage = filteredEntities.length">Show all</a> |
| </div> |
| </ul> |
| </div> |
| <div ng-init="filteredPolicies = (bundle.types | bundleTypeFilter:'org.apache.brooklyn.api.policy.Policy' | filter:state.search)" ng-show="::filteredPolicies.length > 0"> |
| <ul class="list-group list-group-types"> |
| <li class="list-group-item typed-group-table-header"> |
| <ng-pluralize count="::filteredPolicies.length" |
| when="{'one': 'Policy', 'other': 'Policies'}"> |
| </ng-pluralize> |
| </li> |
| <li ng-repeat="policy in filteredPolicies track by (policy.containingBundle + policy.symbolicName + policy.version)" |
| ng-class="{'deprecated': policy.deprecated, 'disabled': policy.disabled}" |
| class="list-group-item"> |
| <type-item bundle="bundle" type="policy"></type-item> |
| </li> |
| </ul> |
| </div> |
| <div ng-init="filteredEnrichers = (bundle.types | bundleTypeFilter:'org.apache.brooklyn.api.sensor.Enricher' | filter:state.search)" ng-show="::filteredEnrichers.length > 0"> |
| <ul class="list-group list-group-types"> |
| <li class="list-group-item typed-group-table-header"> |
| <ng-pluralize count="::filteredEnrichers.length" |
| when="{'one': 'Enricher', 'other': 'Enrichers'}"> |
| </ng-pluralize> |
| </li> |
| <li ng-repeat="enricher in filteredEnrichers track by (enricher.containingBundle + enricher.symbolicName + enricher.version)" |
| ng-class="{'deprecated': enricher.deprecated, 'disabled': enricher.disabled}" |
| class="list-group-item"> |
| <type-item bundle="bundle" type="enricher"></type-item> |
| </li> |
| </ul> |
| </div> |
| <h5 ng-init="additionalTypes = bundle.types.length - filteredEntities.length - filteredPolicies.length - filteredEnrichers.length" |
| ng-show="additionalTypes > 0" |
| class="text-info"> |
| <i class="fa fa-fw fa-info-circle"></i> |
| There <ng-pluralize count="::additionalTypes" when="{'one': 'is {} type', 'other': 'are {} types'}"></ng-pluralize> in this bundle |
| <span ng-if="additionalTypes < bundle.types.length"> in addition to the |
| above<span ng-if="isNonEmpty(state.search)"> not matching the search criteria</span>.</span> |
| <span ng-if="additionalTypes == bundle.types.length"> but no entities, enrichers or |
| policies<span ng-if="isNonEmpty(state.search)"> matching the search criteria</span>.</span> |
| </h5> |
| </div> |
| </li> |
| |
| <li ng-show="!bundles" class="list-group-item loading"> |
| <h4>Loading bundles</h4> |
| </li> |
| <li ng-show="bundle.types.length === 0" class="list-group-item empty"> |
| <h4>There is no items in the catalog</h4> |
| <button class="btn btn-primary" ng-click="launchCatalogUploader()">Upload some</button> |
| </li> |
| <li ng-show="bundle.types.length > 0 && filteredBundles.length === 0" class="list-group-item no-results"> |
| <h4>No results matching current filters</h4> |
| </li> |
| </ul> |
| |
| <ul class="list-group list-group-types" ng-if="state.view === 'types'"> |
| <li ng-repeat="type in types | filter:state.search | orderBy:state.orderBy.id as filteredTypes track by (type.containingBundle + type.symbolicName + type.version)" |
| ng-class="{'deprecated': type.deprecated, 'disabled': type.disabled}" |
| class="list-group-item"> |
| <type-item bundle="type.bundle" type="type" show-bundle="true" show-type="true"></type-item> |
| </li> |
| |
| <li ng-show="!types" class="list-group-item loading"> |
| <h4>Loading types</h4> |
| </li> |
| <li ng-show="types.length === 0" class="list-group-item empty"> |
| <h4>There are no items in the catalog</h4> |
| <button class="btn btn-primary" ng-click="launchCatalogUploader()">Upload some</button> |
| </li> |
| <li ng-show="filteredTypes.length === 0" class="list-group-item no-results"> |
| <h4>No results matching current filters</h4> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </section> |