diff --git a/app/index.html b/app/index.html index 71a5c0c718..c836dc4c2c 100644 --- a/app/index.html +++ b/app/index.html @@ -255,6 +255,8 @@

JavaScript Required

+ + diff --git a/app/scripts/app.js b/app/scripts/app.js index ca4513454c..78c47d6d03 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -271,6 +271,16 @@ angular controller: 'ServiceController', reloadOnSearch: false }) + .when('/project/:project/browse/service-instances', { + templateUrl: 'views/service-instances.html', + controller: 'ServiceInstancesController', + reloadOnSearch: false + }) + .when('/project/:project/browse/service-instances/:instance', { + templateUrl: 'views/browse/service-instance.html', + controller: 'ServiceInstanceController', + reloadOnSearch: false + }) .when('/project/:project/browse/storage', { templateUrl: 'views/storage.html', controller: 'StorageController', diff --git a/app/scripts/constants.js b/app/scripts/constants.js index 1dfcc84f35..333bf3b40c 100644 --- a/app/scripts/constants.js +++ b/app/scripts/constants.js @@ -190,6 +190,23 @@ angular.extend(window.OPENSHIFT_CONSTANTS, { prefixes: [ "/browse/routes/" ] + }, + { + label: "Provisioned Services", + href: "/browse/service-instances", + prefixes: [ + "/browse/service-instances/" + ], + isValid: function(){ + return _.get(window.OPENSHIFT_CONSTANTS, 'ENABLE_TECH_PREVIEW_FEATURE.service_catalog_landing_page'); + }, + canI: { + resource: { + group: 'servicecatalog.k8s.io', + resource: 'instances' + }, + verb: 'list' + } } ] } diff --git a/app/scripts/controllers/serviceInstance.js b/app/scripts/controllers/serviceInstance.js new file mode 100644 index 0000000000..14bfeeff3d --- /dev/null +++ b/app/scripts/controllers/serviceInstance.js @@ -0,0 +1,104 @@ +'use strict'; + +angular.module('openshiftConsole') + .controller('ServiceInstanceController', function ($scope, + $filter, + $routeParams, + DataService, + ProjectsService) { + $scope.alerts = {}; + //$scope.displayName = null; + $scope.projectName = $routeParams.project; + $scope.serviceInstance = null; + $scope.serviceClass = null; + $scope.serviceClasses = {}; + + $scope.breadcrumbs = [ + { + title: "Provisioned Services", + link: "project/" + $routeParams.project + "/browse/service-instances" + }, + { + title: $routeParams.instance + } + ]; + + var watches = []; + + /*var setDisplayName = function() { + if(!$scope.serviceInstance || !$scope.serviceClasses) { + return; + } + + $scope.displayName = $filter('serviceInstanceDisplayName')($scope.serviceInstance, $scope.serviceClasses); + };*/ + + var updateServiceClassMetadata = function() { + if(!$scope.serviceInstance || !$scope.serviceClasses) { + return; + } + + var serviceClassName = _.get($scope.serviceInstance.spec, 'serviceClassName'); + $scope.serviceClass = _.get($scope.serviceClasses, [serviceClassName]); + $scope.plan = _.find(_.get($scope.serviceClass, 'plans'), {name: 'default'}); + }; + + var serviceResolved = function(service, action) { + $scope.loaded = true; + $scope.serviceInstance = service; + + if (action === "DELETED") { + $scope.alerts["deleted"] = { + type: "warning", + message: "This provisioned service has been deleted." + }; + } + + //setDisplayName(); + updateServiceClassMetadata(); + }; + + ProjectsService + .get($routeParams.project) + .then(_.spread(function(project, context) { + $scope.project = project; + $scope.projectContext = context; + + DataService + .get({ + group: 'servicecatalog.k8s.io', + resource: 'instances' + }, $routeParams.instance, context, { errorNotification: false }) + .then(function(service) { + + serviceResolved(service); + + watches.push(DataService.watchObject({ + group: 'servicecatalog.k8s.io', + resource: 'instances' + }, $routeParams.instance, context, serviceResolved)); + + }, function(error) { + $scope.loaded = true; + $scope.alerts["load"] = { + type: "error", + message: "The service details could not be loaded.", + details: $filter('getErrorDetails')(error) + }; + }); + + DataService.list({ + group: 'servicecatalog.k8s.io', + resource: 'serviceclasses' + }, context, function(serviceClasses) { + $scope.serviceClasses = serviceClasses.by('metadata.name'); + //setDisplayName(); + updateServiceClassMetadata(); + }); + + $scope.$on('$destroy', function(){ + DataService.unwatchAll(watches); + }); + + })); + }); diff --git a/app/scripts/controllers/serviceInstances.js b/app/scripts/controllers/serviceInstances.js new file mode 100644 index 0000000000..5e7b7a5935 --- /dev/null +++ b/app/scripts/controllers/serviceInstances.js @@ -0,0 +1,185 @@ +'use strict'; + +angular.module('openshiftConsole') + .controller('ServiceInstancesController', function ($scope, + $filter, + $routeParams, + APIService, + BindingService, + Constants, + DataService, + LabelFilter, + Logger, + ProjectsService) { + $scope.alerts = {}; + $scope.applicationsByBinding = {}; + $scope.bindings = {}; + $scope.bindableServiceInstances = {}; + //$scope.bindingsByApplicationUID = {}; + $scope.bindingsByInstanceRef = {}; + $scope.emptyMessage = "Loading..."; + $scope.labelSuggestions = {}; + $scope.projectName = $routeParams.project; + $scope.serviceClasses = {}; + $scope.serviceInstances = {}; + $scope.unfilteredServiceInstances = {}; + + var watches = []; + + var updateFilter = function() { + $scope.serviceInstances = LabelFilter.getLabelSelector().select($scope.unfilteredServiceInstances); + }; + + var sortServiceInstances = function() { + $scope.bindableServiceInstances = BindingService.filterBindableServiceInstances($scope.unfilteredServiceInstances, $scope.serviceClasses); + $scope.unfilteredServiceInstances = BindingService.sortServiceInstances($scope.unfilteredServiceInstances, $scope.serviceClasses); + }; + + var groupBindings = function() { + // Build two maps: + // - Bindings by the UID of the target object + // - API objects by binding name + /* + state.bindingsByApplicationUID = {}; + state.applicationsByBinding = {}; + //state.deleteableBindingsByApplicationUID = {}; + + // If there are no bindings, nothing to do. + if (_.isEmpty(state.bindings)) { + return; + } + + // All objects that can be a target for bindings. + var objectsByKind = [ + overview.deployments, + overview.deploymentConfigs, + overview.vanillaReplicationControllers, + overview.vanillaReplicaSets, + overview.statefulSets + ]; + + // Make sure all the binding targets have loaded first. + if (_.some(objectsByKind, function(collection) { return !collection; })) { + return; + } + + // Build a map of pod preset selectors by binding name. + var podPresetSelectors = {}; + _.each(state.bindings, function(binding) { + var podPresetSelector = _.get(binding, 'spec.alphaPodPresetTemplate.selector'); + if (podPresetSelector) { + podPresetSelectors[binding.metadata.name] = new LabelSelector(podPresetSelector); + } + }); + + _.each(objectsByKind, function(collection) { + _.each(collection, function(apiObject) { + // Key by UID since name is not unique across different kinds. + var applicationUID = getUID(apiObject); + + // Create a selector for the potential binding target to check if the + // pod preset covers the selector. + var applicationSelector = new LabelSelector(_.get(apiObject, 'spec.selector')); + state.bindingsByApplicationUID[applicationUID] = []; + state.deleteableBindingsByApplicationUID[applicationUID] = []; + + // Look at each pod preset selector to see if it covers this API object selector. + _.each(podPresetSelectors, function(podPresetSelector, bindingName) { + if (podPresetSelector.covers(applicationSelector)) { + // Keep a map of the target UID to the binding and the binding to + // the target. We want to show bindings both in the "application" + // object rows and the service instance rows. + state.bindingsByApplicationUID[applicationUID].push(state.bindings[bindingName]); + if (!_.get(state.bindings[bindingName], 'metadata.deletionTimestamp')) { + state.deleteableBindingsByApplicationUID[applicationUID].push(state.bindings[bindingName]); + } + state.applicationsByBinding[bindingName] = state.applicationsByBinding[bindingName] || []; + state.applicationsByBinding[bindingName].push(apiObject); + } + }); + }); + }); + + $scope.bindingsByInstanceRef = _.reduce(state.bindingsByInstanceRef, function(result, bindingList, key) { + result[key] = _.sortBy(bindingList, function(binding) { + var apps = _.get(state.applicationsByBinding, [binding.metadata.name]); + var firstName = _.get(_.head(apps), ['metadata', 'name']); + return firstName || binding.metadata.name; + }); + return result; + }, {});*/ + }; + + ProjectsService + .get($routeParams.project) + .then(_.spread(function(project, context) { + $scope.project = project; + $scope.projectContext = context; + + watches.push(DataService.watch({ + group: 'servicecatalog.k8s.io', + resource: 'bindings' + }, context, function(bindings) { + $scope.bindings = bindings.by('metadata.name'); + $scope.bindingsByInstanceRef = _.groupBy($scope.bindings, 'spec.instanceRef.name'); + groupBindings(); + //refreshSecrets(context); + })); + + watches.push(DataService.watch({ + group: 'servicecatalog.k8s.io', + resource: 'instances' + }, context, function(serviceInstances) { + $scope.emptyMessage = "No provisioned services to show"; + $scope.unfilteredServiceInstances = serviceInstances.by('metadata.name'); + + //_.each($scope.unfilteredServiceInstances, function (instance) { + // var notifications = ResourceAlertsService.getServiceInstanceAlerts(instance); + // setNotifications(instance, notifications); + //}); + + sortServiceInstances(); + updateFilter(); + updateFilterWarning(); + + LabelFilter.addLabelSuggestionsFromResources($scope.unfilteredServiceInstances, $scope.labelSuggestions); + LabelFilter.setLabelSuggestions($scope.labelSuggestions); + + Logger.log("provisioned services (subscribe)", $scope.unfilteredServiceInstances); + })); + + DataService.list({ + group: 'servicecatalog.k8s.io', + resource: 'serviceclasses' + }, context, function(serviceClasses) { + $scope.serviceClasses = serviceClasses.by('metadata.name'); + sortServiceInstances(); + updateFilter(); + }); + + function updateFilterWarning() { + if (!LabelFilter.getLabelSelector().isEmpty() && _.isEmpty($scope.serviceInstances) && !_.isEmpty($scope.unfilteredServiceInstances)) { + $scope.alerts["all-instances-filtered"] = { + type: "warning", + details: "The active filters are hiding all provisioned services." + }; + } + else { + delete $scope.alerts["all-instances-filtered"]; + } + } + + LabelFilter.onActiveFiltersChanged(function(labelSelector) { + // trigger a digest loop + $scope.$apply(function() { + $scope.serviceInstances = labelSelector.select($scope.unfilteredServiceInstances); + updateFilterWarning(); + }); + }); + + $scope.$on('$destroy', function(){ + DataService.unwatchAll(watches); + }); + + })); + }); diff --git a/app/scripts/directives/overview/serviceBinding.js b/app/scripts/directives/overview/serviceBinding.js index 02b56107da..836f0068bb 100644 --- a/app/scripts/directives/overview/serviceBinding.js +++ b/app/scripts/directives/overview/serviceBinding.js @@ -9,6 +9,7 @@ bindings: { namespace: '<', binding: '<', + refApiObject: ' + + + +
+
+
+
+ + +
Loading...
+
+

+ + {{serviceInstance | serviceInstanceDisplayName:serviceClasses}} + created +

+ +
+
+
+
+
+
+
+ + + Details +
+
+
+

Plan

+

+ {{plan.description}} +

+
+
Description:
+
+

+

+
+
Status:
+
+ + {{serviceInstance | serviceInstanceStatus | sentenceCase}} +
+
Status Reason:
+
+ {{serviceInstance | serviceInstanceMessage}} +
+ +
+
+
+ + +
+
+ +
+
+ + Events + + +
+
+
+
+
+
+
+
diff --git a/app/views/directives/resource-service-bindings.html b/app/views/directives/resource-service-bindings.html index 5a24978902..b2fab00811 100644 --- a/app/views/directives/resource-service-bindings.html +++ b/app/views/directives/resource-service-bindings.html @@ -1,9 +1,10 @@
-

Service Bindings

+

Bindings

diff --git a/app/views/overview/_service-binding.html b/app/views/overview/_service-binding.html index a57cefd0a6..d1501c308d 100644 --- a/app/views/overview/_service-binding.html +++ b/app/views/overview/_service-binding.html @@ -3,7 +3,12 @@

- {{$ctrl.serviceClass.externalMetadata.displayName || $ctrl.serviceClass.metadata.name}} + + {{$ctrl.serviceClass.externalMetadata.displayName || $ctrl.serviceClass.metadata.name}} + + + {{$ctrl.binding.spec.secretName}} + {{$ctrl.binding.spec.instanceRef.name}} diff --git a/app/views/overview/_service-instance-row.html b/app/views/overview/_service-instance-row.html index 69b4699809..3f11b9f57f 100644 --- a/app/views/overview/_service-instance-row.html +++ b/app/views/overview/_service-instance-row.html @@ -6,7 +6,8 @@

- + +

diff --git a/app/views/service-instances.html b/app/views/service-instances.html new file mode 100644 index 0000000000..435cc48e85 --- /dev/null +++ b/app/views/service-instances.html @@ -0,0 +1,89 @@ + + + + +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameStatusCreatedBindings
{{emptyMessage}}
{{serviceInstance | serviceInstanceDisplayName:serviceClasses}} +
+ + {{serviceInstance | serviceInstanceStatus | sentenceCase}} +
+
+ ago + +
+

+ + {{application.metadata.name}} + + + {{firstBinding.spec.secretName}} + + + +

+
+
+ No bindings +
+
+
+
+
+
+
+
+
diff --git a/dist/scripts/scripts.js b/dist/scripts/scripts.js index c9f8f5acfa..ce7b8e9c1a 100644 --- a/dist/scripts/scripts.js +++ b/dist/scripts/scripts.js @@ -3,7 +3,7 @@ function OverviewController(e, t, n, a, r, o, i, s, c, l, u, d, m, p, g, f, h, v, y, b, C, S, w, k, j) { var P = this, R = t("isIE")() || t("isEdge")(); e.projectName = n.project; -var E, T, I = t("annotation"), D = t("buildConfigForBuild"), N = t("deploymentIsInProgress"), A = t("imageObjectRef"), B = t("isJenkinsPipelineStrategy"), L = t("isNewerResource"), U = t("label"), O = t("podTemplate"), x = {}, F = {}, M = {}, V = P.state = { +var E, I, T = t("annotation"), N = t("buildConfigForBuild"), D = t("deploymentIsInProgress"), A = t("imageObjectRef"), B = t("isJenkinsPipelineStrategy"), L = t("isNewerResource"), U = t("label"), O = t("podTemplate"), x = {}, F = {}, M = {}, V = P.state = { alerts: {}, builds: {}, clusterQuotas: {}, @@ -205,14 +205,14 @@ _.isEmpty(e) || (f.addLabelSuggestionsFromResources(e, x), "pipeline" !== P.view }, ke = function(e) { _.isEmpty(e) || (f.addLabelSuggestionsFromResources(e, F), "pipeline" === P.viewBy && f.setLabelSuggestions(F)); }, je = function(e) { -return "Succeeded" !== e.status.phase && "Failed" !== e.status.phase && (!U(e, "openshift.io/deployer-pod-for.name") && (!I(e, "openshift.io/build.name") && "slave" !== U(e, "jenkins"))); +return "Succeeded" !== e.status.phase && "Failed" !== e.status.phase && (!U(e, "openshift.io/deployer-pod-for.name") && (!T(e, "openshift.io/build.name") && "slave" !== U(e, "jenkins"))); }, Pe = function() { V.podsByOwnerUID = C.groupByOwnerUID(P.pods), P.monopods = _.filter(V.podsByOwnerUID[""], je); }, Re = function(e) { -return !!_.get(e, "status.replicas") || (!I(e, "deploymentConfig") || N(e)); +return !!_.get(e, "status.replicas") || (!T(e, "deploymentConfig") || D(e)); }, Ee = function(e) { -return I(e, "deploymentConfig"); -}, Te = function() { +return T(e, "deploymentConfig"); +}, Ie = function() { if (P.deploymentConfigs && P.replicationControllers) { var e = []; P.replicationControllersByDeploymentConfig = {}, P.currentByDeploymentConfig = {}, M = {}; @@ -223,7 +223,7 @@ var r = Ee(a) || ""; var o = M[r]; o && !L(a, o) || (M[r] = a); var i; -"Complete" === I(a, "deploymentStatus") && ((i = t[r]) && !L(a, i) || (t[r] = a)), Re(a) && _.set(n, [ r, a.metadata.name ], a); +"Complete" === T(a, "deploymentStatus") && ((i = t[r]) && !L(a, i) || (t[r] = a)), Re(a) && _.set(n, [ r, a.metadata.name ], a); }), _.each(t, function(e, t) { _.set(n, [ t, e.metadata.name ], e); }), _.each(n, function(e, t) { @@ -231,29 +231,29 @@ var n = u.sortByDeploymentVersion(e, !0); P.replicationControllersByDeploymentConfig[t] = n, P.currentByDeploymentConfig[t] = _.head(n); }), P.vanillaReplicationControllers = _.sortBy(e, "metadata.name"), ve(); } -}, Ie = function(e, t) { +}, Te = function(e, t) { if (_.get(e, "status.replicas")) return !0; var n = u.getRevision(e); return !n || !!t && u.getRevision(t) === n; -}, De = function() { +}, Ne = function() { P.replicaSets && E && (P.replicaSetsByDeploymentUID = b.groupByControllerUID(P.replicaSets), P.currentByDeploymentUID = {}, _.each(P.replicaSetsByDeploymentUID, function(e, t) { if (t) { var n = E[t], a = _.filter(e, function(e) { -return Ie(e, n); +return Te(e, n); }), r = u.sortByRevision(a); P.replicaSetsByDeploymentUID[t] = r, P.currentByDeploymentUID[t] = _.head(r); } }), P.vanillaReplicaSets = _.sortBy(P.replicaSetsByDeploymentUID[""], "metadata.name"), Ce()); -}, Ne = {}, $e = function(e) { +}, De = {}, $e = function(e) { e && V.allServices && _.each(e, function(e) { var t = [], n = H(e), a = O(e); -_.each(Ne, function(e, n) { +_.each(De, function(e, n) { e.matches(a) && t.push(V.allServices[n]); }), V.servicesByObjectUID[n] = _.sortBy(t, "metadata.name"); }); }, Ae = function() { if (V.allServices) { -Ne = _.mapValues(V.allServices, function(e) { +De = _.mapValues(V.allServices, function(e) { return new LabelSelector(e.spec.selector); }); var e = [ P.deploymentConfigs, P.vanillaReplicationControllers, P.deployments, P.vanillaReplicaSets, P.statefulSets, P.monopods ]; @@ -265,7 +265,7 @@ V.routesByService = _.mapValues(e, j.sortRoutesByScore), Y(); }, Le = function() { V.hpaByResource = d.groupHPAs(P.horizontalPodAutoscalers); }, Ue = function(e) { -var t = D(e), n = P.buildConfigs[t]; +var t = N(e), n = P.buildConfigs[t]; if (n) { P.recentPipelinesByBuildConfig[t] = P.recentPipelinesByBuildConfig[t] || [], P.recentPipelinesByBuildConfig[t].push(e); var a = i.usesDeploymentConfigs(n); @@ -320,7 +320,7 @@ if (V.builds && P.buildConfigs) { P.recentPipelinesByBuildConfig = {}, V.recentBuildsByBuildConfig = {}, V.recentPipelinesByDeploymentConfig = {}; var e = {}; _.each(i.interestingBuilds(V.builds), function(t) { -var n = D(t); +var n = N(t); B(t) ? Ue(t) : (e[n] = e[n] || [], e[n].push(t)); }), P.recentPipelinesByBuildConfig = _.mapValues(P.recentPipelinesByBuildConfig, function(e) { return i.sortBuilds(e, !0); @@ -381,19 +381,19 @@ P.pods && p.fetchReferencedImageStreamImages(P.pods, V.imagesByDockerReference, Ye.push(l.watch("pods", a, function(e) { P.pods = e.by("metadata.name"), Pe(), r(), _e(), $e(P.monopods), pe(P.monopods), we(P.monopods), ie(), h.log("pods (subscribe)", P.pods); })), Ye.push(l.watch("replicationcontrollers", a, function(e) { -P.replicationControllers = e.by("metadata.name"), Te(), $e(P.vanillaReplicationControllers), $e(P.monopods), pe(P.vanillaReplicationControllers), we(P.vanillaReplicationControllers), Qe(), ie(), h.log("replicationcontrollers (subscribe)", P.replicationControllers); +P.replicationControllers = e.by("metadata.name"), Ie(), $e(P.vanillaReplicationControllers), $e(P.monopods), pe(P.vanillaReplicationControllers), we(P.vanillaReplicationControllers), Qe(), ie(), h.log("replicationcontrollers (subscribe)", P.replicationControllers); })), Ye.push(l.watch("deploymentconfigs", a, function(e) { -P.deploymentConfigs = e.by("metadata.name"), Te(), $e(P.deploymentConfigs), $e(P.vanillaReplicationControllers), we(P.deploymentConfigs), Ce(), He(), Ke(), Qe(), ie(), h.log("deploymentconfigs (subscribe)", P.deploymentConfigs); +P.deploymentConfigs = e.by("metadata.name"), Ie(), $e(P.deploymentConfigs), $e(P.vanillaReplicationControllers), we(P.deploymentConfigs), Ce(), He(), Ke(), Qe(), ie(), h.log("deploymentconfigs (subscribe)", P.deploymentConfigs); })), Ye.push(l.watch({ group: "extensions", resource: "replicasets" }, a, function(e) { -P.replicaSets = e.by("metadata.name"), De(), $e(P.vanillaReplicaSets), $e(P.monopods), pe(P.vanillaReplicaSets), we(P.vanillaReplicaSets), Qe(), ie(), h.log("replicasets (subscribe)", P.replicaSets); +P.replicaSets = e.by("metadata.name"), Ne(), $e(P.vanillaReplicaSets), $e(P.monopods), pe(P.vanillaReplicaSets), we(P.vanillaReplicaSets), Qe(), ie(), h.log("replicasets (subscribe)", P.replicaSets); })), Ye.push(l.watch({ group: "apps", resource: "deployments" }, a, function(e) { -E = e.by("metadata.uid"), P.deployments = _.sortBy(E, "metadata.name"), De(), $e(P.deployments), $e(P.vanillaReplicaSets), we(P.deployments), Qe(), ie(), h.log("deployments (subscribe)", P.deploymentsByUID); +E = e.by("metadata.uid"), P.deployments = _.sortBy(E, "metadata.name"), Ne(), $e(P.deployments), $e(P.vanillaReplicaSets), we(P.deployments), Qe(), ie(), h.log("deployments (subscribe)", P.deploymentsByUID); })), Ye.push(l.watch("builds", a, function(e) { V.builds = e.by("metadata.name"), We(), h.log("builds (subscribe)", V.builds); })), Ye.push(l.watch({ @@ -429,7 +429,7 @@ P.horizontalPodAutoscalers = e.by("metadata.name"), Le(), h.log("autoscalers (su poll: R, pollInterval: 6e4 })), Ye.push(l.watch("imagestreams", a, function(e) { -T = e.by("metadata.name"), p.buildDockerRefMapForImageStreams(T, V.imageStreamImageRefByDockerReference), r(), h.log("imagestreams (subscribe)", T); +I = e.by("metadata.name"), p.buildDockerRefMapForImageStreams(I, V.imageStreamImageRefByDockerReference), r(), h.log("imagestreams (subscribe)", I); }, { poll: R, pollInterval: 6e4 @@ -498,7 +498,7 @@ function ResourceServiceBindings(e, t, n, a) { var r = this, o = e("enableTechPreviewFeature"); r.bindings = [], r.bindableServiceInstances = [], r.serviceClasses = [], r.serviceInstances = [], r.showBindings = a.SERVICE_CATALOG_ENABLED && o("pod_presets"); var i = e("isIE")() || e("isEdge")(), s = [], c = e("canI"), l = function() { -r.apiObject && r.bindings && (r.bindings = n.getBindingsForResource(r.bindings, r.apiObject)); +r.apiObject && r.bindings && ("Instance" === _.get(r.apiObject, "kind") ? r.bindings = _.filter(r.bindings, [ "spec.instanceRef.name", _.get(r.apiObject, "metadata.name") ]) : r.bindings = n.getBindingsForResource(r.bindings, r.apiObject)); }, u = function() { r.bindableServiceInstances = n.filterBindableServiceInstances(r.serviceInstances, r.serviceClasses), r.orderedServiceInstances = n.sortServiceInstances(r.serviceInstances, r.serviceClasses); }; @@ -738,6 +738,20 @@ prefixes: [ "/browse/services/" ] label: "Routes", href: "/browse/routes", prefixes: [ "/browse/routes/" ] +}, { +label: "Provisioned Services", +href: "/browse/service-instances", +prefixes: [ "/browse/service-instances/" ], +isValid: function() { +return _.get(window.OPENSHIFT_CONSTANTS, "ENABLE_TECH_PREVIEW_FEATURE.service_catalog_landing_page"); +}, +canI: { +resource: { +group: "servicecatalog.k8s.io", +resource: "instances" +}, +verb: "list" +} } ] } ] }, { @@ -1084,6 +1098,14 @@ reloadOnSearch: !1 templateUrl: "views/browse/service.html", controller: "ServiceController", reloadOnSearch: !1 +}).when("/project/:project/browse/service-instances", { +templateUrl: "views/service-instances.html", +controller: "ServiceInstancesController", +reloadOnSearch: !1 +}).when("/project/:project/browse/service-instances/:instance", { +templateUrl: "views/browse/service-instance.html", +controller: "ServiceInstanceController", +reloadOnSearch: !1 }).when("/project/:project/browse/storage", { templateUrl: "views/storage.html", controller: "StorageController", @@ -1611,6 +1633,10 @@ var m = s.indexOf(":"); c.segment("images").segmentCoded(s.substring(0, m)).segmentCoded(s.substring(m + 1)); break; +case "Instance": +c.segment("service-instances").segmentCoded(s); +break; + case "StatefulSet": c.segment("stateful-sets").segmentCoded(s); break; @@ -1668,6 +1694,7 @@ replicationcontrollers: "deployments", routes: "routes", secrets: "secrets", services: "services", +instances: "service-instances", persistentvolumeclaims: "storage", statefulsets: "stateful-sets" }; @@ -4637,17 +4664,17 @@ t && (n.logOptions.replicationControllers[e.metadata.name].version = t), n.logCa n.logOptions.builds[e.metadata.name] = {}, n.logCanRun.builds[e.metadata.name] = !_.includes([ "New", "Pending", "Error" ], e.status.phase); }, E = function() { n.filteredStatefulSets = s.filterForKeywords(_.values(n.statefulSets), S, w); -}, T = function() { +}, I = function() { b = _.filter(n.pods, function(e) { return !n.filters.hideOlderResources || "Succeeded" !== e.status.phase && "Failed" !== e.status.phase; }), n.filteredPods = s.filterForKeywords(b, S, w); -}, I = a("isIncompleteBuild"), D = a("buildConfigForBuild"), N = a("isRecentBuild"), A = function() { +}, T = a("isIncompleteBuild"), N = a("buildConfigForBuild"), D = a("isRecentBuild"), A = function() { moment().subtract(5, "m"); h = _.filter(n.builds, function(e) { if (!n.filters.hideOlderResources) return !0; -if (I(e)) return !0; -var t = D(e); -return t ? n.latestBuildByConfig[t].metadata.name === e.metadata.name : N(e); +if (T(e)) return !0; +var t = N(e); +return t ? n.latestBuildByConfig[t].metadata.name === e.metadata.name : D(e); }), n.filteredBuilds = s.filterForKeywords(h, S, w); }, B = a("deploymentStatus"), L = a("deploymentIsInProgress"), U = function() { v = _.filter(n.replicationControllers, function(e) { @@ -4701,7 +4728,7 @@ var t = _.get(n, [ "podsByOwnerUID", e.metadata.uid ], []); _.isEmpty(t) || u.toPodsForDeployment(e, t); }, m.get(e.project).then(_.spread(function(e, a) { n.project = e, n.projectContext = a, o.watch("pods", a, function(e) { -n.podsByName = e.by("metadata.name"), n.pods = C(n.podsByName, !0), n.podsByOwnerUID = d.groupByOwnerUID(n.pods), n.podsLoaded = !0, _.each(n.pods, j), T(), c.log("pods", n.pods); +n.podsByName = e.by("metadata.name"), n.pods = C(n.podsByName, !0), n.podsByOwnerUID = d.groupByOwnerUID(n.pods), n.podsLoaded = !0, _.each(n.pods, j), I(), c.log("pods", n.pods); }), o.watch({ resource: "statefulsets", group: "apps", @@ -4720,7 +4747,7 @@ n.replicaSets = C(e.by("metadata.name"), !0), n.replicaSetsLoaded = !0, O(), c.l }), n.$on("$destroy", function() { o.unwatchAll(g); }), n.$watch("filters.hideOlderResources", function() { -T(), A(), U(), O(), E(); +I(), A(), U(), O(), E(); var e = t.search(); e.hideOlderResources = n.filters.hideOlderResources ? "true" : "false", t.replace().search(e); }), n.$watch("kindSelector.selected.kind", function() { @@ -4820,12 +4847,12 @@ httpErr: e("getErrorDetails")(a) }); }, E = {}; n.tab && (E[n.tab] = !0); -var T = u.getSubjectKinds(); +var I = u.getSubjectKinds(); angular.extend(a, { selectedTab: E, projectName: f, forms: {}, -subjectKinds: T, +subjectKinds: I, newBinding: { role: "", kind: n.tab || "User", @@ -4858,7 +4885,7 @@ return e ? a + (v(e, "description") || "") : ""; } } }); -var I = function(e, t, n, r) { +var T = function(e, t, n, r) { var o = { alerts: {}, detailsMarkup: C.remove.areYouSure.html.subject({ @@ -4901,10 +4928,10 @@ e && !_.includes(a.projects, e) ? a.projects = [ e ].concat(t) : a.projects = t; }), l.get(n.project).then(_.spread(function(n, r) { g = r, j(), k(g), angular.extend(a, { project: n, -subjectKinds: T, +subjectKinds: I, canUpdateRolebindings: y("rolebindings", "update", f), confirmRemove: function(n, r, i) { -var c = null, l = I(n, r, i, a.user.metadata.name); +var c = null, l = T(n, r, i, a.user.metadata.name); _.isEqual(n, a.user.metadata.name) && u.isLastRole(a.user.metadata.name, a.roleBindings) && (c = !0), o.open({ animation: !0, templateUrl: "views/modals/confirm.html", @@ -5663,7 +5690,7 @@ e.logCanRun = !_.includes([ "New", "Pending" ], P(t)); }, E = t("isIE")() || t("isEdge")(); f.get(n.project).then(_.spread(function(u, f) { e.project = u, e.projectContext = f; -var v = {}, T = function() { +var v = {}, I = function() { if (e.hpaForRS = s.filterHPA(v, y, n.replicaSet), e.deploymentConfigName && e.isActive) { var t = s.filterHPA(v, "DeploymentConfig", e.deploymentConfigName); e.autoscalers = e.hpaForRS.concat(t); @@ -5671,18 +5698,18 @@ e.autoscalers = e.hpaForRS.concat(t); var a = s.filterHPA(v, "Deployment", e.deployment.metadata.name); e.autoscalers = e.hpaForRS.concat(a); } else e.autoscalers = e.hpaForRS; -}, I = function() { +}, T = function() { j.push(o.watch(e.resource, f, function(t) { var n, a = []; angular.forEach(t.by("metadata.name"), function(t) { (C(t, "deploymentConfig") || "") === e.deploymentConfigName && a.push(t); -}), n = i.getActiveDeployment(a), e.isActive = n && n.metadata.uid === e.replicaSet.metadata.uid, T(); +}), n = i.getActiveDeployment(a), e.isActive = n && n.metadata.uid === e.replicaSet.metadata.uid, I(); })); -}, D = function() { +}, N = function() { s.getHPAWarnings(e.replicaSet, e.autoscalers, e.limitRanges, u).then(function(t) { e.hpaWarnings = t; }); -}, N = function(a) { +}, D = function(a) { var r = C(a, "deploymentConfig"); if (r) { b = !0, e.deploymentConfigName = r; @@ -5734,7 +5761,7 @@ title: e.deployment.metadata.name, link: m.resourceURL(e.deployment) }, humanizedKind: "Deployments" -}), $(), T(); +}), $(), I(); })), j.push(o.watch({ group: "extensions", resource: "replicasets" @@ -5754,20 +5781,20 @@ errorNotification: !1 }).then(function(t) { switch (e.loaded = !0, e.replicaSet = t, R(t), y) { case "ReplicationController": -N(t); +D(t); break; case "ReplicaSet": L(); } -D(), e.breadcrumbs = r.getBreadcrumbs({ +N(), e.breadcrumbs = r.getBreadcrumbs({ object: t }), j.push(o.watchObject(e.resource, n.replicaSet, f, function(t, n) { "DELETED" === n && (e.alerts.deleted = { type: "warning", message: "This " + S + " has been deleted." -}), e.replicaSet = t, R(t), D(), U(), e.deployment && $(); -})), e.deploymentConfigName && I(), j.push(o.watch("pods", f, function(t) { +}), e.replicaSet = t, R(t), N(), U(), e.deployment && $(); +})), e.deploymentConfigName && T(), j.push(o.watch("pods", f, function(t) { var n = t.by("metadata.name"); e.podsForDeployment = g.filterForOwner(n, e.replicaSet); })); @@ -5797,12 +5824,12 @@ group: "autoscaling", resource: "horizontalpodautoscalers", version: "v1" }, f, function(e) { -v = e.by("metadata.name"), T(), D(); +v = e.by("metadata.name"), I(), N(); }, { poll: E, pollInterval: 6e4 })), o.list("limitranges", f).then(function(t) { -e.limitRanges = t.by("metadata.name"), D(); +e.limitRanges = t.by("metadata.name"), N(); }); j.push(o.watch("resourcequotas", f, function(t) { e.quotas = t.by("metadata.name"); @@ -6013,6 +6040,89 @@ e.routesForService = {}, angular.forEach(n.by("metadata.name"), function(n) { n.unwatchAll(i); }); })); +} ]), angular.module("openshiftConsole").controller("ServiceInstancesController", [ "$scope", "$filter", "$routeParams", "APIService", "BindingService", "Constants", "DataService", "LabelFilter", "Logger", "ProjectsService", function(e, t, n, a, r, o, i, s, c, l) { +e.alerts = {}, e.applicationsByBinding = {}, e.bindings = {}, e.bindableServiceInstances = {}, e.bindingsByInstanceRef = {}, e.emptyMessage = "Loading...", e.labelSuggestions = {}, e.projectName = n.project, e.serviceClasses = {}, e.serviceInstances = {}, e.unfilteredServiceInstances = {}; +var u = [], d = function() { +e.serviceInstances = s.getLabelSelector().select(e.unfilteredServiceInstances); +}, m = function() { +e.bindableServiceInstances = r.filterBindableServiceInstances(e.unfilteredServiceInstances, e.serviceClasses), e.unfilteredServiceInstances = r.sortServiceInstances(e.unfilteredServiceInstances, e.serviceClasses); +}, p = function() {}; +l.get(n.project).then(_.spread(function(t, n) { +function a() { +s.getLabelSelector().isEmpty() || !_.isEmpty(e.serviceInstances) || _.isEmpty(e.unfilteredServiceInstances) ? delete e.alerts["all-instances-filtered"] : e.alerts["all-instances-filtered"] = { +type: "warning", +details: "The active filters are hiding all provisioned services." +}; +} +e.project = t, e.projectContext = n, u.push(i.watch({ +group: "servicecatalog.k8s.io", +resource: "bindings" +}, n, function(t) { +e.bindings = t.by("metadata.name"), e.bindingsByInstanceRef = _.groupBy(e.bindings, "spec.instanceRef.name"), p(); +})), u.push(i.watch({ +group: "servicecatalog.k8s.io", +resource: "instances" +}, n, function(t) { +e.emptyMessage = "No provisioned services to show", e.unfilteredServiceInstances = t.by("metadata.name"), m(), d(), a(), s.addLabelSuggestionsFromResources(e.unfilteredServiceInstances, e.labelSuggestions), s.setLabelSuggestions(e.labelSuggestions), c.log("provisioned services (subscribe)", e.unfilteredServiceInstances); +})), i.list({ +group: "servicecatalog.k8s.io", +resource: "serviceclasses" +}, n, function(t) { +e.serviceClasses = t.by("metadata.name"), m(), d(); +}), s.onActiveFiltersChanged(function(t) { +e.$apply(function() { +e.serviceInstances = t.select(e.unfilteredServiceInstances), a(); +}); +}), e.$on("$destroy", function() { +i.unwatchAll(u); +}); +})); +} ]), angular.module("openshiftConsole").controller("ServiceInstanceController", [ "$scope", "$filter", "$routeParams", "DataService", "ProjectsService", function(e, t, n, a, r) { +e.alerts = {}, e.projectName = n.project, e.serviceInstance = null, e.serviceClass = null, e.serviceClasses = {}, e.breadcrumbs = [ { +title: "Provisioned Services", +link: "project/" + n.project + "/browse/service-instances" +}, { +title: n.instance +} ]; +var o = [], i = function() { +if (e.serviceInstance && e.serviceClasses) { +var t = _.get(e.serviceInstance.spec, "serviceClassName"); +e.serviceClass = _.get(e.serviceClasses, [ t ]), e.plan = _.find(_.get(e.serviceClass, "plans"), { +name: "default" +}); +} +}, s = function(t, n) { +e.loaded = !0, e.serviceInstance = t, "DELETED" === n && (e.alerts.deleted = { +type: "warning", +message: "This provisioned service has been deleted." +}), i(); +}; +r.get(n.project).then(_.spread(function(r, c) { +e.project = r, e.projectContext = c, a.get({ +group: "servicecatalog.k8s.io", +resource: "instances" +}, n.instance, c, { +errorNotification: !1 +}).then(function(e) { +s(e), o.push(a.watchObject({ +group: "servicecatalog.k8s.io", +resource: "instances" +}, n.instance, c, s)); +}, function(n) { +e.loaded = !0, e.alerts.load = { +type: "error", +message: "The service details could not be loaded.", +details: t("getErrorDetails")(n) +}; +}), a.list({ +group: "servicecatalog.k8s.io", +resource: "serviceclasses" +}, c, function(t) { +e.serviceClasses = t.by("metadata.name"), i(); +}), e.$on("$destroy", function() { +a.unwatchAll(o); +}); +})); } ]), angular.module("openshiftConsole").controller("SecretsController", [ "$routeParams", "$scope", "DataService", "ProjectsService", function(e, t, n, a) { t.projectName = e.project, t.secretsByType = {}, t.alerts = t.alerts || {}, a.get(e.project).then(_.spread(function(e, a) { t.project = e, t.context = a, n.list("secrets", a).then(function(e) { @@ -7499,12 +7609,12 @@ title: R var E = { name: "app", value: "" -}, T = t("orderByDisplayName"), I = t("getErrorDetails"), D = {}, N = function() { -f.hideNotification("create-builder-list-config-maps-error"), f.hideNotification("create-builder-list-secrets-error"), _.each(D, function(e) { +}, I = t("orderByDisplayName"), T = t("getErrorDetails"), N = {}, D = function() { +f.hideNotification("create-builder-list-config-maps-error"), f.hideNotification("create-builder-list-secrets-error"), _.each(N, function(e) { !e.id || "error" !== e.type && "warning" !== e.type || f.hideNotification(e.id); }); }; -e.$on("$destroy", N), h.get(r.project).then(_.spread(function(n, i) { +e.$on("$destroy", D), h.get(r.project).then(_.spread(function(n, i) { e.project = n, e.breadcrumbs[0].title = t("displayName")(n), r.sourceURI && (e.sourceURIinParams = !0); var h = function() { e.hideCPU || (e.cpuProblems = d.validatePodLimits(e.limitRanges, "cpu", [ e.container ], n)), e.memoryProblems = d.validatePodLimits(e.limitRanges, "memory", [ e.container ], n); @@ -7564,18 +7674,18 @@ var a = [], o = []; e.valueFromObjects = [], c.list("configmaps", i, null, { errorNotification: !1 }).then(function(t) { -a = T(t.by("metadata.name")), e.valueFromObjects = a.concat(o); +a = I(t.by("metadata.name")), e.valueFromObjects = a.concat(o); }, function(e) { 403 !== e.code && f.addNotification({ id: "create-builder-list-config-maps-error", type: "error", message: "Could not load config maps.", -details: I(e) +details: T(e) }); }), c.list("secrets", i, null, { errorNotification: !1 }).then(function(t) { -o = T(t.by("metadata.name")), e.valueFromObjects = o.concat(a); +o = I(t.by("metadata.name")), e.valueFromObjects = o.concat(a); var n = b.groupSecretsByType(t), r = _.mapValues(n, function(e) { return _.map(e, "metadata.name"); }); @@ -7587,7 +7697,7 @@ e.unshift(""); id: "create-builder-list-secrets-error", type: "error", message: "Could not load secrets.", -details: I(e) +details: T(e) }); }), c.get("imagestreams", t.imageName, { namespace: t.namespace || r.project @@ -7664,16 +7774,16 @@ cancelButtonText: "Cancel" } }).result.then(B); }, U = function(t) { -N(), D = t.quotaAlerts || [], e.nameTaken || _.some(D, { +D(), N = t.quotaAlerts || [], e.nameTaken || _.some(N, { type: "error" -}) ? (e.disableInputs = !1, _.each(D, function(e) { +}) ? (e.disableInputs = !1, _.each(N, function(e) { e.id = _.uniqueId("create-builder-alert-"), f.addNotification(e); -})) : _.isEmpty(D) ? B() : (L(D), e.disableInputs = !1); +})) : _.isEmpty(N) ? B() : (L(N), e.disableInputs = !1); }; e.projectDisplayName = function() { return k(this.project) || this.projectName; }, e.createApp = function() { -e.disableInputs = !0, N(), e.buildConfig.envVars = w.compactEntries(e.buildConfigEnvVars), e.deploymentConfig.envVars = w.compactEntries(e.DCEnvVarsFromUser), e.labels = w.mapEntries(w.compactEntries(e.labelArray)); +e.disableInputs = !0, D(), e.buildConfig.envVars = w.compactEntries(e.buildConfigEnvVars), e.deploymentConfig.envVars = w.compactEntries(e.DCEnvVarsFromUser), e.labels = w.mapEntries(w.compactEntries(e.labelArray)); var t = s.generate(e); A = [], angular.forEach(t, function(e) { null !== e && (m.debug("Generated resource definition:", e), A.push(e)); @@ -9040,7 +9150,7 @@ scope: p }).result.then(function() { l.getLatestQuotaAlerts(p.createResources, { namespace: p.input.selectedProject.metadata.name -}).then(D); +}).then(N); }); } function y() { @@ -9052,7 +9162,7 @@ t > 0 && a.push(k()), e > 0 && a.push(w()), n.all(a).then(b); } function b() { var e, n; -I(), "Template" === p.resourceKind && p.templateOptions.process && !p.errorOccurred ? p.isDialog ? p.$emit("fileImportedFromYAMLOrJSON", { +T(), "Template" === p.resourceKind && p.templateOptions.process && !p.errorOccurred ? p.isDialog ? p.$emit("fileImportedFromYAMLOrJSON", { project: p.input.selectedProject, template: p.resource }) : (n = p.templateOptions.add || p.updateResources.length > 0 ? p.input.selectedProject.metadata.name : "", e = s.createFromTemplateURL(p.resource, p.input.selectedProject.metadata.name, { @@ -9218,19 +9328,19 @@ cancelButtonText: "Cancel" } } }).result.then(y); -}, T = {}, I = function() { -c.hideNotification("from-file-error"), _.each(T, function(e) { +}, I = {}, T = function() { +c.hideNotification("from-file-error"), _.each(I, function(e) { !e.id || "error" !== e.type && "warning" !== e.type || c.hideNotification(e.id); }); -}, D = function(e) { -I(), T = u.getSecurityAlerts(p.createResources, p.input.selectedProject.metadata.name); +}, N = function(e) { +T(), I = u.getSecurityAlerts(p.createResources, p.input.selectedProject.metadata.name); var t = e.quotaAlerts || []; -T = T.concat(t), _.filter(T, { +I = I.concat(t), _.filter(I, { type: "error" -}).length ? (_.each(T, function(e) { +}).length ? (_.each(I, function(e) { e.id = _.uniqueId("from-file-alert-"), c.addNotification(e); -}), p.disableInputs = !1) : T.length ? (E(T), p.disableInputs = !1) : y(); -}, N = function() { +}), p.disableInputs = !1) : I.length ? (E(I), p.disableInputs = !1) : y(); +}, D = function() { if (_.has(p.input.selectedProject, "metadata.uid")) return n.when(p.input.selectedProject); var t = p.input.selectedProject.metadata.name, a = p.input.selectedProject.metadata.annotations["new-display-name"], r = e("description")(p.input.selectedProject); return m.create(t, a, r); @@ -9245,11 +9355,11 @@ var e = []; p.errorOccurred = !1, _.forEach(p.resourceList, function(t) { if (!f(t)) return p.errorOccurred = !0, !1; e.push(C(t)); -}), N().then(function(t) { +}), D().then(function(t) { p.input.selectedProject = t, n.all(e).then(function() { p.errorOccurred || (1 === p.createResources.length && "Template" === p.resourceList[0].kind ? h() : _.isEmpty(p.updateResources) ? l.getLatestQuotaAlerts(p.createResources, { namespace: p.input.selectedProject.metadata.name -}).then(D) : (p.updateTemplate = 1 === p.updateResources.length && "Template" === p.updateResources[0].kind, p.updateTemplate ? h() : v())); +}).then(N) : (p.updateTemplate = 1 === p.updateResources.length && "Template" === p.updateResources[0].kind, p.updateTemplate ? h() : v())); }); }, function(e) { c.addNotification({ @@ -9261,10 +9371,10 @@ details: R(e) }); } }, p.cancel = function() { -I(), s.toProjectOverview(p.input.selectedProject.metadata.name); +T(), s.toProjectOverview(p.input.selectedProject.metadata.name); }; var $ = e("displayName"); -p.$on("importFileFromYAMLOrJSON", p.create), p.$on("$destroy", I); +p.$on("importFileFromYAMLOrJSON", p.create), p.$on("$destroy", T); } ] }; } ]), angular.module("openshiftConsole").directive("oscFileInput", [ "Logger", function(e) { @@ -10682,12 +10792,12 @@ if (!m.pod) return null; var t = m.options.selectedContainer; switch (e) { case "memory/usage": -var n = I(t); +var n = T(t); if (n) return s.bytesToMiB(d(n)); break; case "cpu/usage_rate": -var a = D(t); +var a = N(t); if (a) return d(a); } return null; @@ -10717,10 +10827,10 @@ _.each(e.datasets, function(e) { t[e.id] = e.data; }); var n, r = c.getSparklineData(t), o = e.chartPrefix + "sparkline"; -T[o] ? T[o].load(r) : ((n = L(e)).data = r, e.chartDataColors && (n.color = { +I[o] ? I[o].load(r) : ((n = L(e)).data = r, e.chartDataColors && (n.color = { pattern: e.chartDataColors }), a(function() { -$ || (T[o] = c3.generate(n)); +$ || (I[o] = c3.generate(n)); })); } } @@ -10731,7 +10841,7 @@ function v() { return 60 * m.options.timeRange.value * 1e3; } function y() { -return Math.floor(v() / N) + "ms"; +return Math.floor(v() / D) + "ms"; } function b(e, t, n) { var a, r = { @@ -10780,7 +10890,7 @@ isNaN(a) && (a = 0), e.convert && (a = e.convert(a)), t.used = d3.round(a, e.usa function j(e, t) { m.noData = !1; var n = _.initial(t.data); -e.data ? e.data = _.chain(e.data).takeRight(N).concat(n).value() : e.data = n; +e.data ? e.data = _.chain(e.data).takeRight(D).concat(n).value() : e.data = n; } function P() { if (w()) { @@ -10808,7 +10918,7 @@ m.loaded = !0; } } m.includedMetrics = m.includedMetrics || [ "cpu", "memory", "network" ]; -var R, E = {}, T = {}, I = n("resources.limits.memory"), D = n("resources.limits.cpu"), N = 30, $ = !1; +var R, E = {}, I = {}, T = n("resources.limits.memory"), N = n("resources.limits.cpu"), D = 30, $ = !1; m.uniqueID = c.uniqueID(), m.metrics = [], _.includes(m.includedMetrics, "memory") && m.metrics.push({ label: "Memory", units: "MiB", @@ -10905,14 +11015,14 @@ delete e.data; }, !0), R = t(P, c.getDefaultUpdateInterval(), !1); }); var O = o.$on("metrics.charts.resize", function() { -c.redraw(E), c.redraw(T); +c.redraw(E), c.redraw(I); }); m.$on("$destroy", function() { R && (t.cancel(R), R = null), O && (O(), O = null), angular.forEach(E, function(e) { e.destroy(); -}), E = null, angular.forEach(T, function(e) { +}), E = null, angular.forEach(I, function(e) { e.destroy(); -}), T = null, $ = !0; +}), I = null, $ = !0; }); } }; @@ -10972,9 +11082,9 @@ return e[0]; }), i); } function u(e) { -k || (D = 0, t.showAverage = _.size(t.pods) > 5 || w, _.each(t.metrics, function(n) { +k || (N = 0, t.showAverage = _.size(t.pods) > 5 || w, _.each(t.metrics, function(n) { var a, r = o(e, n), i = n.descriptor; -w && n.compactCombineWith && (i = n.compactCombineWith, n.lastValue && (I[i].lastValue = (I[i].lastValue || 0) + n.lastValue)), C[i] ? (C[i].load(r), t.showAverage ? C[i].legend.hide() : C[i].legend.show()) : ((a = N(n)).data = r, C[i] = c3.generate(a)); +w && n.compactCombineWith && (i = n.compactCombineWith, n.lastValue && (T[i].lastValue = (T[i].lastValue || 0) + n.lastValue)), C[i] ? (C[i].load(r), t.showAverage ? C[i].legend.hide() : C[i].legend.show()) : ((a = D(n)).data = r, C[i] = c3.generate(a)); })); } function d() { @@ -10998,10 +11108,10 @@ return w || (n.containerName = t.options.selectedContainer.name), n.start = j || } } function f(e) { -if (!k) if (D++, t.noData) t.metricsError = { +if (!k) if (N++, t.noData) t.metricsError = { status: _.get(e, "status", 0), details: _.get(e, "data.errorMsg") || _.get(e, "statusText") || "Status code " + _.get(e, "status", 0) -}; else if (!(D < 2) && t.alerts) { +}; else if (!(N < 2) && t.alerts) { var n = "metrics-failed-" + t.uniqueID; t.alerts[n] = { type: "error", @@ -11010,14 +11120,14 @@ links: [ { href: "", label: "Retry", onClick: function() { -delete t.alerts[n], D = 1, y(); +delete t.alerts[n], N = 1, y(); } } ] }; } } function h() { -return _.isEmpty(t.pods) ? (t.loaded = !0, !1) : !t.metricsError && D < 2; +return _.isEmpty(t.pods) ? (t.loaded = !0, !1) : !t.metricsError && N < 2; } function v(e, n, a) { t.noData = !1; @@ -11038,7 +11148,7 @@ t.loaded = !0; } var b, C = {}, S = 30, w = "compact" === t.profile, k = !1; t.uniqueID = s.uniqueID(); -var j, P, R = {}, E = w, T = function(e) { +var j, P, R = {}, E = w, I = function(e) { return e >= 1024; }; t.metrics = [ { @@ -11046,10 +11156,10 @@ label: "Memory", units: "MiB", convert: i.bytesToMiB, formatUsage: function(e) { -return T(e) && (e /= 1024), s.formatUsage(e); +return I(e) && (e /= 1024), s.formatUsage(e); }, usageUnits: function(e) { -return T(e) ? "GiB" : "MiB"; +return I(e) ? "GiB" : "MiB"; }, descriptor: "memory/usage", type: "pod_container", @@ -11094,17 +11204,17 @@ compactDatasetLabel: "Received", compactType: "spline", chartID: "network-rx-" + t.uniqueID } ]; -var I = _.keyBy(t.metrics, "descriptor"); +var T = _.keyBy(t.metrics, "descriptor"); t.loaded = !1, t.noData = !0, t.showComputeUnitsHelp = function() { l.showComputeUnitsHelp(); }; -var D = 0; +var N = 0; c.getMetricsURL().then(function(e) { t.metricsURL = e; }), t.options = { rangeOptions: s.getTimeRangeOptions() }, t.options.timeRange = _.head(t.options.rangeOptions), t.options.selectedContainer = _.head(t.containers); -var N = function(e) { +var D = function(e) { var n = s.getDefaultSparklineConfig(e.chartID, e.units, w); return _.set(n, "legend.show", !w && !t.showAverage), n; }; @@ -11176,17 +11286,17 @@ offset: { top: t.followAffixTop || 0 } })); -}, T = function() { +}, I = function() { return $("#" + t.logViewerID + " .log-view-output"); -}, I = function(e) { -var n = T(), a = n.offset().top; +}, T = function(e) { +var n = I(), a = n.offset().top; if (!(a < 0)) { var r = $(".ellipsis-pulser").outerHeight(!0), o = t.fixedHeight ? t.fixedHeight : Math.floor($(window).height() - a - r); t.chromeless || t.fixedHeight || (o -= 40), e ? n.animate({ "min-height": o + "px" }, "fast") : n.css("min-height", o + "px"), t.fixedHeight && n.css("max-height", o); } -}, D = function() { +}, N = function() { if (!S) { var e = function() { clearInterval(S), S = null, t.$evalAsync(function() { @@ -11194,13 +11304,13 @@ t.sized = !0; }); }, n = 0; S = setInterval(function() { -n > 10 ? e() : (n++, T().is(":visible") && (I(), e())); +n > 10 ? e() : (n++, I().is(":visible") && (T(), e())); }, 100); } -}, N = _.debounce(function() { -I(!0), w(), R(), k(), E(), P(); +}, D = _.debounce(function() { +T(!0), w(), R(), k(), E(), P(); }, 100); -p.on("resize", N); +p.on("resize", D); var A, B = function() { j = !0, d.scrollBottom(h); }, L = document.createDocumentFragment(), U = _.debounce(function() { @@ -11233,7 +11343,7 @@ n++, L.appendChild(f(n, e)), U(); }; (A = c.createStream(b, C, t.context, e)).onMessage(function(r, o, i) { t.$evalAsync(function() { -t.empty = !1, "logs" !== t.state && (t.state = "logs", D()); +t.empty = !1, "logs" !== t.state && (t.state = "logs", N()); }), r && (e.limitBytes && i >= e.limitBytes && (t.$evalAsync(function() { t.limitReached = !0, t.loading = !1; }), O(!0)), a(r), !t.largeLog && n >= e.tailLines && t.$evalAsync(function() { @@ -11296,7 +11406,7 @@ t.autoScrollActive = !t.autoScrollActive, t.autoScrollActive && B(); goChromeless: d.chromelessLink, restartLogs: x }), t.$on("$destroy", function() { -O(), p.off("resize", N), p.off("scroll", P), g.off("scroll", P); +O(), p.off("resize", D), p.off("scroll", P), g.off("scroll", P); }), "deploymentconfigs/logs" === b && !C) return t.state = "empty", void (t.emptyStateMessage = "Logs are not available for this replication controller because it was not generated from a deployment configuration."); t.$watchGroup([ "name", "options.container", "run" ], x); } ], @@ -13085,6 +13195,7 @@ controllerAs: "$ctrl", bindings: { namespace: "<", binding: "<", +refApiObject: "\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "\n" + + "
Loading...
\n" + + "
\n" + + "

\n" + + "
\n" + + "\n" + + "Actions\n" + + "
    \n" + + "
  • \n" + + "Edit YAML\n" + + "
  • \n" + + "
  • \n" + + "\n" + + "\n" + + "
  • \n" + + "
\n" + + "
\n" + + "{{serviceInstance | serviceInstanceDisplayName:serviceClasses}}\n" + + "created \n" + + "

\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "\n" + + "Details\n" + + "
\n" + + "
\n" + + "
\n" + + "

Plan

\n" + + "

\n" + + "{{plan.description}}\n" + + "

\n" + + "
\n" + + "
Description:
\n" + + "
\n" + + "

\n" + + "

\n" + + "
\n" + + "
Status:
\n" + + "
\n" + + "\n" + + "{{serviceInstance | serviceInstanceStatus | sentenceCase}}\n" + + "
\n" + + "
Status Reason:
\n" + + "
\n" + + "{{serviceInstance | serviceInstanceMessage}}\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "Events\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
" + ); + + $templateCache.put('views/browse/service.html', "\n" + "\n" + @@ -8845,8 +8936,8 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function( $templateCache.put('views/directives/resource-service-bindings.html', "
\n" + - "

Service Bindings

\n" + - "\n" + + "

Bindings

\n" + + "\n" + "\n" + "
\n" + "\n" + @@ -12314,8 +12405,13 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function( "
\n" + "

\n" + "\n" + + "\n" + "{{$ctrl.serviceClass.externalMetadata.displayName || $ctrl.serviceClass.metadata.name}}\n" + "\n" + + "\n" + + "{{$ctrl.binding.spec.secretName}}\n" + + "\n" + + "\n" + "\n" + "{{$ctrl.binding.spec.instanceRef.name}}\n" + "\n" + @@ -12390,7 +12486,8 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function( "
\n" + "
\n" + "

\n" + - "\n" + + "\n" + + "\n" + "
\n" + "

\n" + "
\n" + @@ -13179,6 +13276,91 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function( ); + $templateCache.put('views/service-instances.html', + "\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "

\n" + + "Provisioned Services\n" + + "\n" + + "

\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + " 0\">\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
NameStatusCreatedBindings
{{emptyMessage}}
{{serviceInstance | serviceInstanceDisplayName:serviceClasses}}\n" + + "
\n" + + "\n" + + "{{serviceInstance | serviceInstanceStatus | sentenceCase}}\n" + + "
\n" + + "
\n" + + " ago\n" + + "\n" + + "
\n" + + "

\n" + + "\n" + + "{{application.metadata.name}}\n" + + "\n" + + "\n" + + "{{firstBinding.spec.secretName}}\n" + + "\n" + + "\n" + + "\n" + + "

\n" + + "
\n" + + "
\n" + + "No bindings\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
" + ); + + $templateCache.put('views/services.html', "\n" + "\n" +