diff --git a/assets/app/scripts/controllers/overview.js b/assets/app/scripts/controllers/overview.js index 3be09fff59b0..4a385d9790c1 100644 --- a/assets/app/scripts/controllers/overview.js +++ b/assets/app/scripts/controllers/overview.js @@ -20,7 +20,9 @@ angular.module('openshiftConsole') Logger, ImageStreamResolver, ObjectDescriber, - $parse) { + $parse, + $filter, + $interval) { $scope.pods = {}; $scope.services = {}; $scope.routes = {}; @@ -56,6 +58,8 @@ angular.module('openshiftConsole') // "" service key for deployment configs not under any service $scope.deploymentConfigsByService = {}; + $scope.recentBuildsByOutputImage = {}; + $scope.labelSuggestions = {}; $scope.alerts = $scope.alerts || {}; $scope.emptyMessage = "Loading..."; @@ -82,6 +86,7 @@ angular.module('openshiftConsole') $scope.topologyItems = { }; $scope.topologyRelations = [ ]; + var intervals = []; var watches = []; watches.push(DataService.watch("pods", $scope, function(pods) { @@ -311,49 +316,9 @@ angular.module('openshiftConsole') Logger.log("imagestreams (subscribe)", $scope.imageStreams); })); - function associateDeploymentConfigTriggersToBuild(deploymentConfig, build) { - // Make sure we have both a deploymentConfig and a build - if (!deploymentConfig || !build) { - return; - } - // Make sure the deployment config has triggers. - if (!deploymentConfig.spec.triggers) { - return; - } - // Make sure we have a build output - if (!build.spec.output.to) { - return; - } - for (var i = 0; i < deploymentConfig.spec.triggers.length; i++) { - var trigger = deploymentConfig.spec.triggers[i]; - if (trigger.type === "ImageChange") { - var buildOutputImage = imageObjectRefFilter(build.spec.output.to, build.metadata.namespace); - var deploymentTriggerImage = imageObjectRefFilter(trigger.imageChangeParams.from, deploymentConfig.metadata.namespace); - if (buildOutputImage !== deploymentTriggerImage) { - continue; - } - - trigger.builds = trigger.builds || {}; - trigger.builds[build.metadata.name] = build; - } - } - } - // Sets up subscription for deploymentConfigs, associates builds to triggers on deploymentConfigs - watches.push(DataService.watch("deploymentconfigs", $scope, function(deploymentConfigs, action, deploymentConfig) { + watches.push(DataService.watch("deploymentconfigs", $scope, function(deploymentConfigs) { $scope.deploymentConfigs = deploymentConfigs.by("metadata.name"); - if (!action) { - angular.forEach($scope.deploymentConfigs, function(depConfig) { - angular.forEach($scope.builds, function(build) { - associateDeploymentConfigTriggersToBuild(depConfig, build); - }); - }); - } - else if (action !== 'DELETED') { - angular.forEach($scope.builds, function(build) { - associateDeploymentConfigTriggersToBuild(deploymentConfig, build); - }); - } deploymentConfigsByService(); // Must be called after deploymentConfigsByService() @@ -363,24 +328,25 @@ angular.module('openshiftConsole') Logger.log("deploymentconfigs (subscribe)", $scope.deploymentConfigs); })); + function updateRecentBuildsByOutputImage() { + $scope.recentBuildsByOutputImage = {}; + angular.forEach($scope.builds, function(build) { + // pre-filter the list to save us some time on each digest loop later + if ($filter('isRecentBuild')(build) || $filter('isOscActiveObject')(build)) { + var buildOutputImage = imageObjectRefFilter(build.spec.output.to, build.metadata.namespace); + $scope.recentBuildsByOutputImage[buildOutputImage] = $scope.recentBuildsByOutputImage[buildOutputImage] || []; + $scope.recentBuildsByOutputImage[buildOutputImage].push(build); + } + }); + } + // Sets up subscription for builds, associates builds to triggers on deploymentConfigs - watches.push(DataService.watch("builds", $scope, function(builds, action, build) { + watches.push(DataService.watch("builds", $scope, function(builds) { $scope.builds = builds.by("metadata.name"); - if (!action) { - angular.forEach($scope.builds, function(bld) { - angular.forEach($scope.deploymentConfigs, function(depConfig) { - associateDeploymentConfigTriggersToBuild(depConfig, bld); - }); - }); - } - else if (action === 'ADDED' || action === 'MODIFIED') { - angular.forEach($scope.deploymentConfigs, function(depConfig) { - associateDeploymentConfigTriggersToBuild(depConfig, build); - }); - } - else if (action === 'DELETED'){ - // TODO - } + updateRecentBuildsByOutputImage(); + + intervals.push($interval(updateRecentBuildsByOutputImage, 5 * 60 * 1000)); // prune the list every 5 minutes + updateTopologyLater(); Logger.log("builds (subscribe)", $scope.builds); })); @@ -543,5 +509,8 @@ angular.module('openshiftConsole') DataService.unwatchAll(watches); window.clearTimeout(updateTimeout); ObjectDescriber.removeResourceChangedCallback(selectionChanged); + angular.forEach(intervals, function (interval){ + $interval.cancel(interval); + }); }); }); diff --git a/assets/app/scripts/directives/resources.js b/assets/app/scripts/directives/resources.js index 5c6afbed0c6b..12deefecf88b 100644 --- a/assets/app/scripts/directives/resources.js +++ b/assets/app/scripts/directives/resources.js @@ -83,7 +83,9 @@ angular.module('openshiftConsole') return { restrict: 'E', scope: { - triggers: '=' + triggers: '=', + buildsByOutputImage: '=', + namespace: '=' }, link: function(scope) { scope.isBuildHidden = function(build) { diff --git a/assets/app/styles/_core.less b/assets/app/styles/_core.less index c79bb651b985..ac9e53a40afc 100644 --- a/assets/app/styles/_core.less +++ b/assets/app/styles/_core.less @@ -777,3 +777,7 @@ labels + .resource-details { h1 small.meta { font-size: 12px; } + +.action-divider { + color: @gray-light; +} \ No newline at end of file diff --git a/assets/app/views/_triggers.html b/assets/app/views/_triggers.html index 4a9bec84ed01..ce534a54f37f 100644 --- a/assets/app/views/_triggers.html +++ b/assets/app/views/_triggers.html @@ -1,47 +1,43 @@
-
- - - - - - - - - - - Build - - - {{build.metadata.labels.buildconfig}} - #{{build | annotation : 'buildNumber'}} - - - - {{build.metadata.name}} - - - completed. - failed. - encountered an error. - was cancelled. - is {{build.status.phase | lowercase}}. - - A new deployment will be created automatically once the build completes. +
+
+ + + + Build + + + {{build.metadata.labels.buildconfig}} + #{{build | annotation : 'buildNumber'}} + + + + {{build.metadata.name}} + + + completed. + failed. + encountered an error. + was cancelled. + is {{build.status.phase | lowercase}}. + + A new deployment will be created automatically once the build completes. + - - - View Log - - Dismiss + + View Log + + | + Dismiss +
diff --git a/assets/app/views/project.html b/assets/app/views/project.html index 1c2f6d483e88..9772763f0590 100644 --- a/assets/app/views/project.html +++ b/assets/app/views/project.html @@ -145,7 +145,7 @@

Pods in deployments created from this deployment config will be routed to by this service. Show things related to triggers that are about to create stuff, like builds. --> - +

- +
Pods in deployments created from this deployment config will not be routed to by any service. Show things related to triggers that are about to create stuff, like builds. --> - +
diff --git a/pkg/assets/bindata.go b/pkg/assets/bindata.go index c72b5b5712fd..0e76e50f11bc 100644 --- a/pkg/assets/bindata.go +++ b/pkg/assets/bindata.go @@ -3106,8 +3106,8 @@ a.state && a.state.running && b++; }, a.$on("$destroy", function() { d.unwatchAll(i); }); -} ]), angular.module("openshiftConsole").controller("OverviewController", [ "$scope", "DataService", "annotationFilter", "hashSizeFilter", "imageObjectRefFilter", "deploymentCausesFilter", "labelFilter", "LabelFilter", "Logger", "ImageStreamResolver", "ObjectDescriber", "$parse", function(a, b, c, d, e, f, g, h, i, j, k, l) { -function m() { +} ]), angular.module("openshiftConsole").controller("OverviewController", [ "$scope", "DataService", "annotationFilter", "hashSizeFilter", "imageObjectRefFilter", "deploymentCausesFilter", "labelFilter", "LabelFilter", "Logger", "ImageStreamResolver", "ObjectDescriber", "$parse", "$filter", "$interval", function(a, b, c, d, e, f, g, h, i, j, k, l, m, n) { +function o() { a.monopodsByService = { "":{} }, a.podsByService = {}, a.podsByDeployment = {}; @@ -3132,13 +3132,13 @@ angular.forEach(f, function(b) { j = j || a.deploymentsByService[h] && a.deploymentsByService[h][b]; }), j || (a.monopodsByService[h] = a.monopodsByService[h] || {}, a.monopodsByService[h][e] = d); } -}), 0 === f.length && 0 === g.length && n(d) && (a.monopodsByService[""][e] = d); -}), i.log("podsByDeployment", a.podsByDeployment), i.log("podsByService", a.podsByService), i.log("monopodsByService", a.monopodsByService), v(); +}), 0 === f.length && 0 === g.length && p(d) && (a.monopodsByService[""][e] = d); +}), i.log("podsByDeployment", a.podsByDeployment), i.log("podsByService", a.podsByService), i.log("monopodsByService", a.monopodsByService), x(); } -function n(a) { +function p(a) { return "Succeeded" === a.status.phase || "Terminated" === a.status.phase || "Failed" === a.status.phase ? !1 :g(a, "openshift.io/deployer-pod-for.name") ? !1 :c(a, "openshift.io/build.name") ? !1 :!0; } -function o() { +function q() { a.deploymentConfigsByService = { "":{} }, angular.forEach(a.deploymentConfigs, function(b, c) { @@ -3150,7 +3150,7 @@ h.covers(f) && (a.deploymentConfigsByService[g][c] = b, d = !0); }), d || (a.deploymentConfigsByService[""][c] = b); }); } -function p() { +function r() { var b = a.deploymentsByService = { "":{} }, d = a.deploymentsByServiceByDeploymentConfig = { @@ -3165,34 +3165,32 @@ h.covers(i) && (b[c][f] = e, d[c][j] = d[c][j] || {}, d[c][j][f] = e, g = !0); }), g || (b[""][f] = e, d[""][j] = d[""][j] || {}, d[""][j][f] = e); }); } -function q(a, b) { -if (a && b && a.spec.triggers && b.spec.output.to) for (var c = 0; c < a.spec.triggers.length; c++) { -var d = a.spec.triggers[c]; -if ("ImageChange" === d.type) { -var f = e(b.spec.output.to, b.metadata.namespace), g = e(d.imageChangeParams.from, a.metadata.namespace); -if (f !== g) continue; -d.builds = d.builds || {}, d.builds[b.metadata.name] = b; -} +function s() { +a.recentBuildsByOutputImage = {}, angular.forEach(a.builds, function(b) { +if (m("isRecentBuild")(b) || m("isOscActiveObject")(b)) { +var c = e(b.spec.output.to, b.metadata.namespace); +a.recentBuildsByOutputImage[c] = a.recentBuildsByOutputImage[c] || [], a.recentBuildsByOutputImage[c].push(b); } +}); } -function r() { +function t() { var b = 0 === d(a.unfilteredServices) && 0 === d(a.pods) && 0 === d(a.deployments) && 0 === d(a.deploymentConfigs); a.renderOptions.showSidebarRight = !b, a.renderOptions.showGetStarted = b; } -function s() { +function u() { h.getLabelSelector().isEmpty() || !$.isEmptyObject(a.services) || $.isEmptyObject(a.unfilteredServices) ? delete a.alerts.services :a.alerts.services = { type:"warning", details:"The active filters are hiding all services." }; } -function t(a) { +function v(a) { return "true" === c(a, "openshift.io/host.generated"); } -function u() { +function w() { function b(a) { return a.kind + a.metadata.uid; } -y = null; +B = null; var c = [], d = {}; angular.forEach(a.services, function(a) { d[b(a)] = a; @@ -3200,7 +3198,7 @@ d[b(a)] = a; angular.forEach(c, function(e, f) { var g = a.services[f]; (!f || g) && angular.forEach(e, function(e) { -(c !== a.monopodsByService || n(e)) && (d[b(e)] = e); +(c !== a.monopodsByService || p(e)) && (d[b(e)] = e); }); }); }), [ a.podsByService, a.monopodsByService, a.routesByService ].forEach(function(d) { @@ -3231,69 +3229,59 @@ target:b(d) a.topologyItems = d, a.topologyRelations = c; }); } -function v() { -y || (y = window.setTimeout(u, 100)); +function x() { +B || (B = window.setTimeout(w, 100)); } -function w(b) { +function y(b) { a.topologySelection = b; } -a.pods = {}, a.services = {}, a.routes = {}, a.routesByService = {}, a.displayRouteByService = {}, a.unfilteredServices = {}, a.deployments = {}, a.deploymentConfigs = void 0, a.builds = {}, a.imageStreams = {}, a.imagesByDockerReference = {}, a.imageStreamImageRefByDockerReference = {}, a.podsByService = {}, a.podsByDeployment = {}, a.monopodsByService = {}, a.deploymentsByServiceByDeploymentConfig = {}, a.deploymentsByService = {}, a.deploymentConfigsByService = {}, a.labelSuggestions = {}, a.alerts = a.alerts || {}, a.emptyMessage = "Loading...", a.renderOptions = a.renderOptions || {}, a.renderOptions.showSidebarRight = !1, a.topologyKinds = { +a.pods = {}, a.services = {}, a.routes = {}, a.routesByService = {}, a.displayRouteByService = {}, a.unfilteredServices = {}, a.deployments = {}, a.deploymentConfigs = void 0, a.builds = {}, a.imageStreams = {}, a.imagesByDockerReference = {}, a.imageStreamImageRefByDockerReference = {}, a.podsByService = {}, a.podsByDeployment = {}, a.monopodsByService = {}, a.deploymentsByServiceByDeploymentConfig = {}, a.deploymentsByService = {}, a.deploymentConfigsByService = {}, a.recentBuildsByOutputImage = {}, a.labelSuggestions = {}, a.alerts = a.alerts || {}, a.emptyMessage = "Loading...", a.renderOptions = a.renderOptions || {}, a.renderOptions.showSidebarRight = !1, a.topologyKinds = { DeploymentConfig:location.href + "#vertex-DeploymentConfig", Pod:location.href + "#vertex-Pod", ReplicationController:location.href + "#vertex-ReplicationController", Route:location.href + "#vertex-Route", Service:location.href + "#vertex-Service" }, a.topologySelection = null, a.topologyItems = {}, a.topologyRelations = []; -var x = []; -x.push(b.watch("pods", a, function(b) { -a.pods = b.by("metadata.name"), m(), r(), j.fetchReferencedImageStreamImages(a.pods, a.imagesByDockerReference, a.imageStreamImageRefByDockerReference, a), v(), i.log("pods", a.pods); -})), x.push(b.watch("services", a, function(b) { -a.unfilteredServices = b.by("metadata.name"), h.addLabelSuggestionsFromResources(a.unfilteredServices, a.labelSuggestions), h.setLabelSuggestions(a.labelSuggestions), a.services = h.getLabelSelector().select(a.unfilteredServices), p(), o(), m(), r(), a.emptyMessage = "No services to show", s(), v(), i.log("services (list)", a.services); -})), x.push(b.watch("routes", a, function(b) { +var z = [], A = []; +A.push(b.watch("pods", a, function(b) { +a.pods = b.by("metadata.name"), o(), t(), j.fetchReferencedImageStreamImages(a.pods, a.imagesByDockerReference, a.imageStreamImageRefByDockerReference, a), x(), i.log("pods", a.pods); +})), A.push(b.watch("services", a, function(b) { +a.unfilteredServices = b.by("metadata.name"), h.addLabelSuggestionsFromResources(a.unfilteredServices, a.labelSuggestions), h.setLabelSuggestions(a.labelSuggestions), a.services = h.getLabelSelector().select(a.unfilteredServices), r(), q(), o(), t(), a.emptyMessage = "No services to show", u(), x(), i.log("services (list)", a.services); +})), A.push(b.watch("routes", a, function(b) { a.routes = b.by("metadata.name"); var c = a.routesByService = {}, d = a.displayRouteByService = {}; angular.forEach(a.routes, function(a, b) { if ("Service" === a.spec.to.kind) { var e = a.spec.to.name; -c[e] = c[e] || {}, c[e][b] = a, (!d[e] || !t(a) && t(d[e])) && (d[e] = a); +c[e] = c[e] || {}, c[e][b] = a, (!d[e] || !v(a) && v(d[e])) && (d[e] = a); } -}), v(), i.log("routes (subscribe)", a.routesByService); -})), x.push(b.watch("replicationcontrollers", a, function(b, c, d) { +}), x(), i.log("routes (subscribe)", a.routesByService); +})), A.push(b.watch("replicationcontrollers", a, function(b, c, d) { a.deployments = b.by("metadata.name"), d ? "DELETED" !== c && (d.causes = f(d)) :angular.forEach(a.deployments, function(a) { a.causes = f(a); -}), p(), m(), r(), v(), i.log("deployments (subscribe)", a.deployments); -})), x.push(b.watch("imagestreams", a, function(b) { -a.imageStreams = b.by("metadata.name"), j.buildDockerRefMapForImageStreams(a.imageStreams, a.imageStreamImageRefByDockerReference), j.fetchReferencedImageStreamImages(a.pods, a.imagesByDockerReference, a.imageStreamImageRefByDockerReference, a), v(), i.log("imagestreams (subscribe)", a.imageStreams); -})), x.push(b.watch("deploymentconfigs", a, function(b, c, d) { -a.deploymentConfigs = b.by("metadata.name"), c ? "DELETED" !== c && angular.forEach(a.builds, function(a) { -q(d, a); -}) :angular.forEach(a.deploymentConfigs, function(b) { -angular.forEach(a.builds, function(a) { -q(b, a); -}); -}), o(), r(), v(), i.log("deploymentconfigs (subscribe)", a.deploymentConfigs); -})), x.push(b.watch("builds", a, function(b, c, d) { -a.builds = b.by("metadata.name"), c ? ("ADDED" === c || "MODIFIED" === c) && angular.forEach(a.deploymentConfigs, function(a) { -q(a, d); -}) :angular.forEach(a.builds, function(b) { -angular.forEach(a.deploymentConfigs, function(a) { -q(a, b); -}); -}), v(), i.log("builds (subscribe)", a.builds); +}), r(), o(), t(), x(), i.log("deployments (subscribe)", a.deployments); +})), A.push(b.watch("imagestreams", a, function(b) { +a.imageStreams = b.by("metadata.name"), j.buildDockerRefMapForImageStreams(a.imageStreams, a.imageStreamImageRefByDockerReference), j.fetchReferencedImageStreamImages(a.pods, a.imagesByDockerReference, a.imageStreamImageRefByDockerReference, a), x(), i.log("imagestreams (subscribe)", a.imageStreams); +})), A.push(b.watch("deploymentconfigs", a, function(b) { +a.deploymentConfigs = b.by("metadata.name"), q(), t(), x(), i.log("deploymentconfigs (subscribe)", a.deploymentConfigs); +})), A.push(b.watch("builds", a, function(b) { +a.builds = b.by("metadata.name"), s(), z.push(n(s, 3e5)), x(), i.log("builds (subscribe)", a.builds); })), h.onActiveFiltersChanged(function(b) { a.$apply(function() { -a.services = b.select(a.unfilteredServices), s(), u(); +a.services = b.select(a.unfilteredServices), u(), w(); }); }); -var y = null; +var B = null; a.$on("select", function(b, c) { a.$apply(function() { a.topologySelection = c, c ? k.setObject(c, c.kind) :k.clearObject(); }); -}, !0), k.onResourceChanged(w), a.$watch("overviewMode", function(a) { +}, !0), k.onResourceChanged(y), a.$watch("overviewMode", function(a) { "topology" === a && (k.source = null); }), a.$on("$destroy", function() { -b.unwatchAll(x), window.clearTimeout(y), k.removeResourceChangedCallback(w); +b.unwatchAll(A), window.clearTimeout(B), k.removeResourceChangedCallback(y), angular.forEach(z, function(a) { +n.cancel(a); +}); }); } ]), angular.module("openshiftConsole").controller("SettingsController", [ "$scope", "DataService", "AlertMessageService", "$filter", "$modal", "$location", "LabelFilter", "$timeout", "Logger", function(a, b, c, d, e, f, g, h, i) { a.quotas = {}, a.limitRanges = {}, a.limitsByType = {}, a.labelSuggestions = {}, a.alerts = a.alerts || {}, a.emptyMessageQuotas = "Loading...", a.emptyMessageLimitRanges = "Loading...", a.renderOptions = a.renderOptions || {}, a.renderOptions.hideFilterWidget = !0; @@ -4490,7 +4478,9 @@ return "hide/build/" + a.metadata.uid; return { restrict:"E", scope:{ -triggers:"=" +triggers:"=", +buildsByOutputImage:"=", +namespace:"=" }, link:function(b) { b.isBuildHidden = function(b) { @@ -6579,16 +6569,10 @@ var _scriptsTemplatesJs = []byte(`angular.module('openshiftConsoleTemplates', [] $templateCache.put('views/_triggers.html', "
\n" + "
\n" + - "
\n" + + "
\n" + + "
\n" + "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + + "\n" + "\n" + "Build\n" + "\n" + @@ -6600,7 +6584,7 @@ var _scriptsTemplatesJs = []byte(`angular.module('openshiftConsoleTemplates', [] "\n" + "{{build.metadata.name}}\n" + "\n" + - "\n" + + "\n" + "completed.\n" + "failed.\n" + "encountered an error.\n" + @@ -6614,7 +6598,9 @@ var _scriptsTemplatesJs = []byte(`angular.module('openshiftConsoleTemplates', [] "\n" + "View Log\n" + "\n" + - "Dismiss\n" + + "|\n" + + "Dismiss\n" + + "
\n" + "
\n" + "
\n" + "
" @@ -9265,14 +9251,14 @@ var _scriptsTemplatesJs = []byte(`angular.module('openshiftConsoleTemplates', [] "\n" + "
\n" + "\n" + - "\n" + + "\n" + "
\n" + "\n" + "
\n" + "\n" + "
\n" + "\n" + - "\n" + + "\n" + "
\n" + "
0 || (deployment | isRecentDeployment : deploymentConfigs[deploymentConfigId]) || !(deployment | isDeployment)\" class=\"animate-repeat\">\n" + "\n" + @@ -9295,7 +9281,7 @@ var _scriptsTemplatesJs = []byte(`angular.module('openshiftConsoleTemplates', [] "
0\">\n" + "
\n" + "\n" + - "\n" + + "\n" + "
\n" + "\n" + "\n" + @@ -69767,6 +69753,7 @@ labels+.resource-details{margin-top:10px} [flex].page-header{margin-top:21px} .resource-details h3{padding-bottom:10px;border-bottom:1px solid #eee} h1 small.meta{font-size:12px} +.action-divider{color:#999} .ellipsis-loader{display:inline-block;position:relative;vertical-align:middle} .ellipsis-loader div{position:absolute} .ellipsis-loader div:after,.ellipsis-loader div:before{content:"";position:absolute}