@spinnaker/core 2025.0.6 → 2025.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/api/ApiService.d.ts +2 -2
  2. package/dist/api/mock/mockHttpUtils.d.ts +2 -2
  3. package/dist/application/listExtractor/AppListExtractor.d.ts +2 -2
  4. package/dist/bootstrap/paramChangedHelper.d.ts +1 -1
  5. package/dist/cloudProvider/providerSelection/ProviderSelectionService.d.ts +1 -1
  6. package/dist/cluster/filter/ClusterFilterService.d.ts +1 -1
  7. package/dist/cluster/task.matcher.d.ts +1 -1
  8. package/dist/domain/IManagedEntity.d.ts +8 -8
  9. package/dist/domain/IServerGroup.d.ts +1 -0
  10. package/dist/domain/IStageTypeConfig.d.ts +1 -1
  11. package/dist/entityTag/notifications/NotificationsPopover.d.ts +1 -1
  12. package/dist/image/image.reader.d.ts +2 -2
  13. package/dist/index.js +1726 -1521
  14. package/dist/index.js.map +1 -1
  15. package/dist/managed/config/Configuration.d.ts +1 -1
  16. package/dist/managed/config/GitIntegration.d.ts +1 -1
  17. package/dist/managed/constraints/registry.d.ts +2 -2
  18. package/dist/managed/graphql/graphql-sdk.d.ts +137 -137
  19. package/dist/managed/managed.states.d.ts +1 -1
  20. package/dist/managed/overview/artifact/ArtifactActionModal.d.ts +1 -1
  21. package/dist/managed/overview/artifact/VersionOperation.d.ts +3 -3
  22. package/dist/managed/overview/artifact/utils.d.ts +2 -2
  23. package/dist/managed/overview/types.d.ts +9 -9
  24. package/dist/managed/resourceHistory/ManagedResourceHistoryModal.d.ts +1 -1
  25. package/dist/managed/resources/ResourceDefinitionModal.d.ts +1 -1
  26. package/dist/managed/resources/resourceRegistry.d.ts +1 -1
  27. package/dist/managed/versionMetadata/MetadataComponents.d.ts +1 -1
  28. package/dist/managed/versionsHistory/types.d.ts +6 -6
  29. package/dist/manifest/ManifestYaml.d.ts +1 -1
  30. package/dist/modal/wizard/WizardPage.d.ts +1 -1
  31. package/dist/navigation/urlParser.d.ts +1 -1
  32. package/dist/pagerDuty/Pager.d.ts +1 -1
  33. package/dist/pipeline/config/actions/pipelineJson/EditPipelineJsonModal.d.ts +1 -1
  34. package/dist/pipeline/config/stages/FormikStageConfig.d.ts +2 -2
  35. package/dist/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.d.ts +1 -0
  36. package/dist/pipeline/config/stages/common/ExecutionDetailsSection.d.ts +1 -1
  37. package/dist/pipeline/config/stages/entityTags/TagEditor.d.ts +1 -1
  38. package/dist/pipeline/config/templates/PipelineTemplateReader.d.ts +1 -1
  39. package/dist/pipeline/config/triggers/artifacts/helm-image/HelmImageArtifactEditor.d.ts +3 -0
  40. package/dist/pipeline/config/validation/anyFieldRequired.validator.d.ts +1 -1
  41. package/dist/pipeline/config/validation/requiredField.validator.d.ts +1 -1
  42. package/dist/plugins/plugin.registry.d.ts +1 -1
  43. package/dist/presentation/Placement.d.ts +1 -1
  44. package/dist/presentation/Popover.d.ts +1 -1
  45. package/dist/presentation/details/Details.d.ts +7 -0
  46. package/dist/presentation/forms/fields/FormField.d.ts +1 -1
  47. package/dist/presentation/forms/fields/FormikExpressionField.d.ts +1 -1
  48. package/dist/presentation/forms/fields/FormikExpressionRegexField.d.ts +1 -1
  49. package/dist/presentation/forms/fields/FormikFormField.d.ts +1 -1
  50. package/dist/presentation/forms/inputs/interface.d.ts +2 -2
  51. package/dist/presentation/forms/validation/categories.d.ts +3 -3
  52. package/dist/presentation/forms/validation/validation.d.ts +3 -3
  53. package/dist/presentation/hooks/useLatestPromise.hook.d.ts +1 -1
  54. package/dist/presentation/modal/showModal.d.ts +1 -1
  55. package/dist/presentation/tables/Table.d.ts +1 -1
  56. package/dist/presentation/tables/TableCell.d.ts +1 -1
  57. package/dist/presentation/tables/TableRow.d.ts +1 -1
  58. package/dist/presentation/tables/standardGridTableLayout.d.ts +1 -1
  59. package/dist/projects/Projects.d.ts +2 -0
  60. package/dist/projects/index.d.ts +1 -0
  61. package/dist/projects/projects.module.d.ts +3 -2
  62. package/dist/reactShims/AngularJSAdapter.d.ts +3 -3
  63. package/dist/search/infrastructure/SearchResultPods.d.ts +1 -1
  64. package/dist/search/infrastructure/infrastructureSearch.service.d.ts +1 -1
  65. package/dist/serverGroup/details/ServerGroupDetailsWrapper.d.ts +1 -1
  66. package/dist/serverGroupManager/index.d.ts +1 -0
  67. package/dist/serverGroupManager/serverGroupManager.states.d.ts +1 -1
  68. package/dist/utils/Logger.d.ts +1 -1
  69. package/dist/utils/feature/Feature.d.ts +58 -0
  70. package/dist/utils/feature/FeatureContext.d.ts +24 -0
  71. package/dist/utils/feature/index.d.ts +3 -0
  72. package/dist/utils/feature/useFeature.hook.d.ts +15 -0
  73. package/dist/utils/index.d.ts +2 -0
  74. package/dist/utils/json/traverseObject.d.ts +1 -1
  75. package/dist/utils/parseNum.d.ts +1 -0
  76. package/dist/utils/testUtils/index.d.ts +7 -0
  77. package/dist/utils/workerPool.d.ts +1 -1
  78. package/package.json +3 -3
  79. package/src/artifact/ArtifactIconService.ts +1 -0
  80. package/src/artifact/ArtifactTypes.ts +1 -0
  81. package/src/artifact/ExpectedArtifactSelectorViewController.ts +1 -1
  82. package/src/config/VersionChecker.tsx +1 -1
  83. package/src/domain/IServerGroup.ts +1 -0
  84. package/src/help/help.contents.ts +1 -1
  85. package/src/navigation/UrlBuilder.ts +15 -0
  86. package/src/notification/NotificationsList.tsx +12 -8
  87. package/src/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.tsx +8 -2
  88. package/src/pipeline/config/triggers/artifacts/helm-image/HelmImageArtifactEditor.tsx +169 -0
  89. package/src/pipeline/config/triggers/artifacts/index.ts +3 -0
  90. package/src/pipeline/config/validation/PipelineConfigValidator.ts +2 -2
  91. package/src/pipeline/executions/executionGroup/ExecutionGroups.tsx +37 -2
  92. package/src/pipeline/filter/executionFilter.service.ts +50 -5
  93. package/src/presentation/details/Details.tsx +18 -1
  94. package/src/presentation/forms/FormikForm.tsx +1 -1
  95. package/src/projects/ProjectHeader.tsx +12 -9
  96. package/src/projects/Projects.spec.tsx +141 -0
  97. package/src/projects/Projects.tsx +148 -0
  98. package/src/projects/index.ts +1 -0
  99. package/src/projects/{projects.module.js → projects.module.ts} +0 -2
  100. package/src/projects/projects.states.ts +4 -6
  101. package/src/serverGroup/details/ServerGroupDetails.tsx +1 -1
  102. package/src/serverGroupManager/ServerGroupManager.tsx +2 -0
  103. package/src/serverGroupManager/ServerGroupManagerTag.tsx +1 -1
  104. package/src/serverGroupManager/index.ts +1 -0
  105. package/src/serverGroupManager/serverGroupManager.states.ts +3 -3
  106. package/src/utils/feature/Feature.tsx +98 -0
  107. package/src/utils/feature/FeatureContext.tsx +49 -0
  108. package/src/utils/feature/index.ts +3 -0
  109. package/src/utils/feature/useFeature.hook.tsx +25 -0
  110. package/src/utils/index.ts +2 -0
  111. package/src/utils/parseNum.ts +2 -0
  112. package/src/utils/testUtils/index.tsx +30 -0
  113. package/dist/projects/projects.controller.d.ts +0 -2
  114. package/src/projects/projects.controller.js +0 -112
  115. package/src/projects/projects.controller.spec.js +0 -86
  116. package/src/projects/projects.html +0 -87
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import * as angular from 'angular';
2
2
  import angular__default, { module, element, noop as noop$1, copy, toJson, isDefined } from 'angular';
3
3
  import * as _$1 from 'lodash';
4
- import ___default, { cloneDeep, merge, isNil, get, set, intersection, uniq, zipObject, chain, isEqual, padStart, isNumber as isNumber$1, isString, isPlainObject, isArray, isNull, isUndefined, forIn, without, startCase, isBoolean, values, map as map$1, flatten, xor, isFunction, truncate, defaults, toPath, throttle, isObject, findLast, maxBy, sortBy, has, find, cloneDeepWith, pick, size, some, reduce, includes, forOwn, pickBy, filter as filter$1, identity, groupBy, isEmpty, every, each, extend, compact, noop as noop$2, head, partition, memoize, fromPairs, omit, omitBy, isDate, uniqBy, kebabCase, union, keyBy, flatMap, debounce, reverse, orderBy, toNumber, keys, unset, capitalize, flow, clone, bindAll, template as template$2, trim, join, last, max, sumBy, sum, assign, toPairs, defaultsDeep, upperFirst, forEach, first as first$1, countBy, range } from 'lodash';
5
- import { $http, $location, $rootScope, $log, $q, $timeout, $templateRequest, $compile, $controller, $window, $interpolate, $templateCache } from 'ngimport';
4
+ import ___default, { cloneDeep, merge, isNil, set, get, uniq, intersection, zipObject, chain, isEqual, padStart, isNumber as isNumber$1, isString, isPlainObject, isArray, isNull, isUndefined, forIn, without, startCase, isBoolean, values, map as map$1, flatten, xor, isFunction, truncate, defaults, toPath, throttle, isObject, findLast, maxBy, sortBy, has, find, cloneDeepWith, pick, size, some, reduce, includes, forOwn, pickBy, filter as filter$1, identity, groupBy, isEmpty, every, each, extend, compact, noop as noop$2, head, partition, memoize, fromPairs, omit, omitBy, isDate, uniqBy, kebabCase, union, keyBy, flatMap, debounce, reverse, orderBy, toNumber, keys, unset, capitalize, flow, clone, bindAll, template as template$2, trim, join, last, max, sumBy, sum, assign, toPairs, defaultsDeep, upperFirst, forEach, first as first$1, countBy, range } from 'lodash';
5
+ import { $http, $location, $rootScope, $q, $log, $window, $timeout, $templateRequest, $compile, $controller, $interpolate, $templateCache } from 'ngimport';
6
6
  import * as React from 'react';
7
7
  import React__default, { useEffect as useEffect$a, useRef as useRef$4, useMemo as useMemo$2, useState as useState$b, useCallback as useCallback$3, memo as memo$1 } from 'react';
8
8
  import * as rxjs from 'rxjs';
9
- import { fromEvent, defer, from, Subject, of, merge as merge$1, timer, BehaviorSubject, empty, ReplaySubject, combineLatest, forkJoin } from 'rxjs';
10
- import { map, publishReplay, refCount, switchMap, takeUntil, delay, filter, debounceTime, tap, mergeMap, catchError, finalize, toArray, skip, take, startWith, withLatestFrom, distinctUntilChanged, merge as merge$2, first, bufferCount, concatMap, scan } from 'rxjs/operators';
9
+ import { fromEvent, defer, from, Subject, timer, of, merge as merge$1, BehaviorSubject, empty, ReplaySubject, combineLatest, forkJoin } from 'rxjs';
10
+ import { publishReplay, refCount, map, switchMap, takeUntil, delay, filter, debounceTime, tap, mergeMap, catchError, finalize, toArray, skip, take, startWith, withLatestFrom, distinctUntilChanged, merge as merge$2, first, bufferCount, concatMap, scan } from 'rxjs/operators';
11
11
  import { Modal as Modal$1, OverlayTrigger, Tooltip as Tooltip$1, Overlay, Popover as Popover$1, Dropdown, Glyphicon, MenuItem, Button as Button$1, Pagination } from 'react-bootstrap';
12
12
  import * as ReactDOM from 'react-dom';
13
13
  import ReactDOM__default from 'react-dom';
@@ -16,10 +16,12 @@ import VirtualizedSelect from 'react-virtualized-select';
16
16
  import memoizeOne from 'memoize-one';
17
17
  import TetherComponent from 'react-tether';
18
18
  import DiffMatchPatch from 'diff-match-patch';
19
- import $$1 from 'jquery';
19
+ import version from 'root/version.json';
20
20
  import { formatDistanceToNow, formatDistance, format } from 'date-fns';
21
21
  import { DateTime, Duration } from 'luxon';
22
22
  import { react2angular } from 'react2angular';
23
+ import { toast, ToastContainer } from 'react-toastify';
24
+ import $$1 from 'jquery';
23
25
  import classNames from 'classnames';
24
26
  import { Parser, HtmlRenderer } from 'commonmark';
25
27
  import DOMPurify from 'dompurify';
@@ -29,8 +31,6 @@ import { CacheFactory } from 'cachefactory';
29
31
  import * as uiRouterReact from '@uirouter/react';
30
32
  import { UISref, useSref, useIsActive, useCurrentStateAndParams, UIView, useSrefActive, useRouter, useParentView, UISrefActive, useOnStateChanged } from '@uirouter/react';
31
33
  import { connect, Formik, FormikConsumer, FastField, Field, getIn as getIn$1, Form, FieldArray } from 'formik';
32
- import version from 'root/version.json';
33
- import { toast, ToastContainer } from 'react-toastify';
34
34
  import { SpelExpressionEvaluator } from 'spel2js';
35
35
  import DayPicker from 'react-day-picker/DayPickerInput';
36
36
  import 'react-day-picker/lib/style.css';
@@ -57,6 +57,7 @@ import { SortableHandle, arrayMove, SortableElement, SortableContainer } from 'r
57
57
  import * as uiRouterRx from '@uirouter/rx';
58
58
  import { UIRouterRxPlugin } from '@uirouter/rx';
59
59
  import * as propTypes from 'prop-types';
60
+ import { createUltimatePagination, ITEM_TYPES } from 'react-ultimate-pagination';
60
61
  import 'brace/mode/yaml';
61
62
  import 'brace/theme/textmate';
62
63
  import 'bootstrap/dist/css/bootstrap.css';
@@ -76,7 +77,6 @@ import '@uirouter/angularjs/release/stateEvents';
76
77
  import angulartics from 'angulartics';
77
78
  import angularticsGoogleAnalytics from 'angulartics-google-analytics';
78
79
  import 'react-toastify/dist/ReactToastify.min.css';
79
- import { createUltimatePagination, ITEM_TYPES } from 'react-ultimate-pagination';
80
80
  import ANGULAR_UI_BOOTSTRAP from 'angular-ui-bootstrap';
81
81
  import { CellMeasurer, CellMeasurerCache, AutoSizer, List, SortDirection, Table as Table$1, Column } from 'react-virtualized';
82
82
  import SearchApi from 'js-worker-search';
@@ -514,6 +514,7 @@ var spinnakerCore = /*#__PURE__*/Object.freeze({
514
514
  get ProjectHeader () { return ProjectHeader; },
515
515
  get ProjectReader () { return ProjectReader; },
516
516
  get ProjectWriter () { return ProjectWriter; },
517
+ get Projects () { return Projects; },
517
518
  get PubsubSubscriptionReader () { return PubsubSubscriptionReader; },
518
519
  get AngularJSAdapter () { return AngularJSAdapter; },
519
520
  get CoreModalInject () { return CoreModalInject; },
@@ -600,6 +601,7 @@ var spinnakerCore = /*#__PURE__*/Object.freeze({
600
601
  get SERVER_GROUP_MANAGER_STATES () { return SERVER_GROUP_MANAGER_STATES; },
601
602
  get ServerGroupManagerReader () { return ServerGroupManagerReader; },
602
603
  get ServerGroupManagerTag () { return ServerGroupManagerTag; },
604
+ get ServerGroupManagerDetails () { return ServerGroupManagerDetails; },
603
605
  get ServiceAccountReader () { return ServiceAccountReader; },
604
606
  get ServicesReader () { return ServicesReader; },
605
607
  get SLACK_COMPONENT () { return SLACK_COMPONENT; },
@@ -633,6 +635,13 @@ var spinnakerCore = /*#__PURE__*/Object.freeze({
633
635
  get noop () { return noop; },
634
636
  get toIPromise () { return toIPromise; },
635
637
  get RENDER_IF_FEATURE () { return RENDER_IF_FEATURE; },
638
+ get Feature () { return Feature; },
639
+ get IfFeatureEnabled () { return IfFeatureEnabled; },
640
+ get withFeature () { return withFeature; },
641
+ get FeatureFlagsContext () { return FeatureFlagsContext; },
642
+ get FeaturesProvider () { return FeaturesProvider; },
643
+ get useFeatures () { return useFeatures; },
644
+ get useFeature () { return useFeature; },
636
645
  get ScrollToService () { return ScrollToService; },
637
646
  get duration () { return duration; },
638
647
  get timeDiffToString () { return timeDiffToString; },
@@ -645,6 +654,7 @@ var spinnakerCore = /*#__PURE__*/Object.freeze({
645
654
  get WorkerPool () { return WorkerPool; },
646
655
  get filterObjectValues () { return filterObjectValues; },
647
656
  get logger () { return logger; },
657
+ get parseNum () { return parseNum; },
648
658
  get ApplicationsPickerInput () { return ApplicationsPickerInput; },
649
659
  get ScopeClusterSelector () { return ScopeClusterSelector; },
650
660
  get ClusterMatches () { return ClusterMatches; },
@@ -1764,21 +1774,74 @@ const renderIfFeatureComponent = {
1764
1774
  const RENDER_IF_FEATURE = "spinnaker.core.renderIfFeature.directive";
1765
1775
  module(RENDER_IF_FEATURE, []).component("renderIfFeature", renderIfFeatureComponent);
1766
1776
 
1767
- class ScrollToService {
1768
- static toDomId(id) {
1769
- return id.replace(/[\W]/g, "-");
1770
- }
1771
- static scrollTo(selector, scrollableContainer, offset = 0, delay = 0) {
1772
- $timeout(() => {
1773
- const elem = $$1(selector);
1774
- if (elem.length) {
1775
- const content = scrollableContainer ? elem.closest(scrollableContainer) : $$1("body");
1776
- if (content.length) {
1777
- const top = content.scrollTop() + elem.offset().top - offset;
1778
- content.animate({ scrollTop: top + "px" }, 200);
1777
+ class SchedulerFactory {
1778
+ static createScheduler(pollSchedule = SETTINGS.pollSchedule || 3e4) {
1779
+ let scheduler = new Subject();
1780
+ let lastRunTimestamp = new Date().getTime();
1781
+ let pendingRun = null;
1782
+ let suspended = false;
1783
+ let source = timer(pollSchedule, pollSchedule);
1784
+ const run = () => {
1785
+ if (suspended) {
1786
+ return;
1787
+ }
1788
+ $timeout.cancel(pendingRun);
1789
+ lastRunTimestamp = new Date().getTime();
1790
+ scheduler.next(true);
1791
+ pendingRun = null;
1792
+ };
1793
+ source.subscribe(run);
1794
+ const suspendScheduler = () => {
1795
+ $log.debug("auto refresh suspended");
1796
+ suspended = true;
1797
+ };
1798
+ const scheduleNextRun = (delay) => {
1799
+ suspended = false;
1800
+ pendingRun = pendingRun || $timeout(run, delay);
1801
+ };
1802
+ const resumeScheduler = () => {
1803
+ suspended = false;
1804
+ const now = new Date().getTime();
1805
+ $log.debug("auto refresh resumed");
1806
+ if (now - lastRunTimestamp > pollSchedule) {
1807
+ run();
1808
+ } else {
1809
+ scheduleNextRun(pollSchedule - (now - lastRunTimestamp));
1810
+ }
1811
+ };
1812
+ const watchDocumentVisibility = () => {
1813
+ $log.debug("document visibilityState changed to: ", document.visibilityState);
1814
+ if (document.visibilityState === "visible") {
1815
+ resumeScheduler();
1816
+ } else {
1817
+ suspendScheduler();
1818
+ }
1819
+ };
1820
+ const scheduleImmediate = () => {
1821
+ run();
1822
+ suspended = true;
1823
+ scheduleNextRun(pollSchedule);
1824
+ };
1825
+ document.addEventListener("visibilitychange", watchDocumentVisibility);
1826
+ $window.addEventListener("offline", suspendScheduler);
1827
+ $window.addEventListener("online", resumeScheduler);
1828
+ scheduler.next(true);
1829
+ return {
1830
+ subscribe: scheduler.subscribe.bind(scheduler),
1831
+ scheduleImmediate,
1832
+ unsubscribe: () => {
1833
+ suspended = true;
1834
+ if (scheduler) {
1835
+ scheduler.unsubscribe();
1779
1836
  }
1837
+ scheduler = null;
1838
+ source = null;
1839
+ $timeout.cancel(pendingRun);
1840
+ document.removeEventListener("visibilitychange", watchDocumentVisibility);
1841
+ $window.removeEventListener("offline", suspendScheduler);
1842
+ $window.removeEventListener("online", resumeScheduler);
1780
1843
  }
1781
- }, delay);
1844
+ };
1782
1845
  }
1783
1846
  }
1784
1847
 
@@ -1860,6 +1923,124 @@ function timePickerTime(input) {
1860
1923
  const TIME_FORMATTERS = "spinnaker.core.utils.timeFormatters";
1861
1924
  module(TIME_FORMATTERS, []).filter("timestamp", () => timestamp).filter("relativeTime", () => relativeTime).filter("duration", () => duration).filter("timePickerTime", () => timePickerTime).component("systemTimezone", react2angular(SystemTimezone));
1862
1925
 
1926
+ class NotifierService {
1927
+ static publish(message) {
1928
+ const existing = toast.isActive(message.key);
1929
+ if (existing) {
1930
+ toast.update(message.key, { render: message.content, ...message.options });
1931
+ } else {
1932
+ toast(message.content, { toastId: message.key, ...message.options });
1933
+ }
1934
+ }
1935
+ static clear(key) {
1936
+ toast.dismiss(key);
1937
+ }
1938
+ }
1939
+
1940
+ class VersionChecker {
1941
+ static initialize() {
1942
+ $log.debug("Deck version", this.currentVersion.version, "created", timestamp(this.currentVersion.created));
1943
+ this.scheduler = SchedulerFactory.createScheduler();
1944
+ this.scheduler.subscribe(() => this.checkVersion());
1945
+ }
1946
+ static checkVersion() {
1947
+ const url = `/version.json?_=${Date.now()}`;
1948
+ $http.get(url).then((resp) => this.versionRetrieved(resp)).catch(() => {
1949
+ });
1950
+ }
1951
+ static versionRetrieved(response) {
1952
+ const data = response.data;
1953
+ if (data.version === this.currentVersion.version) {
1954
+ this.newVersionSeenCount = 0;
1955
+ } else {
1956
+ this.newVersionSeenCount++;
1957
+ if (this.newVersionSeenCount > 5) {
1958
+ $log.debug("New Deck version:", data.version, "created", timestamp(data.created));
1959
+ NotifierService.publish({
1960
+ key: "newVersion",
1961
+ action: "create",
1962
+ content: /* @__PURE__ */ React__default.createElement("div", null, "A new version of Spinnaker is available", " ", /* @__PURE__ */ React__default.createElement("a", {
1963
+ role: "button",
1964
+ className: "action",
1965
+ onClick: () => document.location.reload()
1966
+ }, "Refresh"))
1967
+ });
1968
+ this.scheduler.unsubscribe();
1969
+ }
1970
+ }
1971
+ }
1972
+ }
1973
+ VersionChecker.currentVersion = version;
1974
+ VersionChecker.newVersionSeenCount = 0;
1975
+
1976
+ const FeatureFlagsContext = React.createContext(SETTINGS.feature);
1977
+ function mergeFeatures(a, b) {
1978
+ return { ...a, ...b };
1979
+ }
1980
+ function FeaturesProvider({
1981
+ features = {},
1982
+ children
1983
+ }) {
1984
+ const currentFeatures = useFeatures();
1985
+ const mergedFeatures = React.useMemo(() => mergeFeatures(currentFeatures, features), [features]);
1986
+ return /* @__PURE__ */ React.createElement(FeatureFlagsContext.Provider, {
1987
+ value: mergedFeatures
1988
+ }, children);
1989
+ }
1990
+
1991
+ function useFeatures() {
1992
+ return React__default.useContext(FeatureFlagsContext);
1993
+ }
1994
+ function useFeature(feature) {
1995
+ const features = useFeatures();
1996
+ return features[feature];
1997
+ }
1998
+
1999
+ function Feature({ feature, children, render = children }) {
2000
+ const hasFeature = useFeature(feature);
2001
+ if (!hasFeature) {
2002
+ return null;
2003
+ }
2004
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, render);
2005
+ }
2006
+ function IfFeatureEnabled({ feature, children, render = children }) {
2007
+ return /* @__PURE__ */ React.createElement(Feature, {
2008
+ feature,
2009
+ render
2010
+ });
2011
+ }
2012
+ function withFeature(feature) {
2013
+ return function wrapWithFeature(Component) {
2014
+ function WithFeature(props) {
2015
+ return /* @__PURE__ */ React.createElement(Feature, {
2016
+ feature
2017
+ }, /* @__PURE__ */ React.createElement(Component, {
2018
+ ...props
2019
+ }));
2020
+ }
2021
+ WithFeature.displayName = `WithFeature(${Component.displayName || Component.name})`;
2022
+ return WithFeature;
2023
+ };
2024
+ }
2025
+
2026
+ class ScrollToService {
2027
+ static toDomId(id) {
2028
+ return id.replace(/[\W]/g, "-");
2029
+ }
2030
+ static scrollTo(selector, scrollableContainer, offset = 0, delay = 0) {
2031
+ $timeout(() => {
2032
+ const elem = $$1(selector);
2033
+ if (elem.length) {
2034
+ const content = scrollableContainer ? elem.closest(scrollableContainer) : $$1("body");
2035
+ if (content.length) {
2036
+ const top = content.scrollTop() + elem.offset().top - offset;
2037
+ content.animate({ scrollTop: top + "px" }, 200);
2038
+ }
2039
+ }
2040
+ }, delay);
2041
+ }
2042
+ }
2043
+
1863
2044
  const decodeUnicodeBase64 = (encodedString) => decodeURIComponent(atob(encodedString).split("").map((char) => "%" + ("00" + char.charCodeAt(0).toString(16)).slice(-2)).join(""));
1864
2045
 
1865
2046
  class UUIDGenerator {
@@ -1950,6 +2131,8 @@ function filterObjectValues(object, predicate, options = {
1950
2131
  return result;
1951
2132
  }
1952
2133
 
2134
+ const parseNum = (numOrStr) => typeof numOrStr === "string" ? parseInt(numOrStr) : numOrStr;
2135
+
1953
2136
  const orEmptyString = (val) => isNil(val) ? "" : val;
1954
2137
  const validationClassName = (validation = {}) => {
1955
2138
  return classNames({
@@ -2712,10 +2895,8 @@ class AngularJSAdapter extends React__default.Component {
2712
2895
  }
2713
2896
  AngularJSAdapter.defaultProps = { locals: {} };
2714
2897
 
2715
- var _rect, _rect2, _rect3, _rect4, _rect5, _rect6, _rect7, _rect8, _rect9, _rect10, _rect11, _rect12;
2716
-
2717
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2718
-
2898
+ var _rect, _rect2, _rect3, _rect4, _rect5, _rect6, _rect7, _rect8, _rect9, _rect0, _rect1, _rect10;
2899
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2719
2900
  var SvgLoadingIndicator = function SvgLoadingIndicator(props) {
2720
2901
  return /*#__PURE__*/React.createElement("svg", _extends({
2721
2902
  xmlns: "http://www.w3.org/2000/svg",
@@ -2870,7 +3051,7 @@ var SvgLoadingIndicator = function SvgLoadingIndicator(props) {
2870
3051
  dur: "1s",
2871
3052
  begin: "-0.25s",
2872
3053
  repeatCount: "indefinite"
2873
- }))), _rect10 || (_rect10 = /*#__PURE__*/React.createElement("rect", {
3054
+ }))), _rect0 || (_rect0 = /*#__PURE__*/React.createElement("rect", {
2874
3055
  x: 47,
2875
3056
  y: 24,
2876
3057
  rx: 3,
@@ -2886,7 +3067,7 @@ var SvgLoadingIndicator = function SvgLoadingIndicator(props) {
2886
3067
  dur: "1s",
2887
3068
  begin: "-0.16666666666666666s",
2888
3069
  repeatCount: "indefinite"
2889
- }))), _rect11 || (_rect11 = /*#__PURE__*/React.createElement("rect", {
3070
+ }))), _rect1 || (_rect1 = /*#__PURE__*/React.createElement("rect", {
2890
3071
  x: 47,
2891
3072
  y: 24,
2892
3073
  rx: 3,
@@ -2902,7 +3083,7 @@ var SvgLoadingIndicator = function SvgLoadingIndicator(props) {
2902
3083
  dur: "1s",
2903
3084
  begin: "-0.08333333333333333s",
2904
3085
  repeatCount: "indefinite"
2905
- }))), _rect12 || (_rect12 = /*#__PURE__*/React.createElement("rect", {
3086
+ }))), _rect10 || (_rect10 = /*#__PURE__*/React.createElement("rect", {
2906
3087
  x: 47,
2907
3088
  y: 24,
2908
3089
  rx: 3,
@@ -3261,7 +3442,9 @@ const DetailsHeader = (props) => /* @__PURE__ */ React__default.createElement("d
3261
3442
  className: "header-text horizontal middle"
3262
3443
  }, props.icon, /* @__PURE__ */ React__default.createElement("h3", {
3263
3444
  className: "horizontal middle space-between flex-1"
3264
- }, props.name)), /* @__PURE__ */ React__default.createElement("div", null, props.children));
3445
+ }, props.name, props.notifications && props.notifications)), props.actions && /* @__PURE__ */ React__default.createElement("div", {
3446
+ className: "actions"
3447
+ }, props.actions), /* @__PURE__ */ React__default.createElement("div", null, props.children));
3265
3448
  const loading = /* @__PURE__ */ React__default.createElement("div", {
3266
3449
  className: "header"
3267
3450
  }, /* @__PURE__ */ React__default.createElement("div", {
@@ -3270,7 +3453,11 @@ const loading = /* @__PURE__ */ React__default.createElement("div", {
3270
3453
  const Details = (props) => /* @__PURE__ */ React__default.createElement("div", {
3271
3454
  className: "details-panel"
3272
3455
  }, props.loading ? loading : props.children);
3456
+ const DetailsContent = ({ loading: loading2, children }) => /* @__PURE__ */ React__default.createElement("div", {
3457
+ className: "content"
3458
+ }, loading2 ? loading2 : children);
3273
3459
  Details.Header = DetailsHeader;
3460
+ Details.Content = DetailsContent;
3274
3461
 
3275
3462
  class Tooltip extends React__default.Component {
3276
3463
  constructor() {
@@ -3696,127 +3883,6 @@ function HelpField(props) {
3696
3883
  }
3697
3884
  }
3698
3885
 
3699
- class SchedulerFactory {
3700
- static createScheduler(pollSchedule = SETTINGS.pollSchedule || 3e4) {
3701
- let scheduler = new Subject();
3702
- let lastRunTimestamp = new Date().getTime();
3703
- let pendingRun = null;
3704
- let suspended = false;
3705
- let source = timer(pollSchedule, pollSchedule);
3706
- const run = () => {
3707
- if (suspended) {
3708
- return;
3709
- }
3710
- $timeout.cancel(pendingRun);
3711
- lastRunTimestamp = new Date().getTime();
3712
- scheduler.next(true);
3713
- pendingRun = null;
3714
- };
3715
- source.subscribe(run);
3716
- const suspendScheduler = () => {
3717
- $log.debug("auto refresh suspended");
3718
- suspended = true;
3719
- };
3720
- const scheduleNextRun = (delay) => {
3721
- suspended = false;
3722
- pendingRun = pendingRun || $timeout(run, delay);
3723
- };
3724
- const resumeScheduler = () => {
3725
- suspended = false;
3726
- const now = new Date().getTime();
3727
- $log.debug("auto refresh resumed");
3728
- if (now - lastRunTimestamp > pollSchedule) {
3729
- run();
3730
- } else {
3731
- scheduleNextRun(pollSchedule - (now - lastRunTimestamp));
3732
- }
3733
- };
3734
- const watchDocumentVisibility = () => {
3735
- $log.debug("document visibilityState changed to: ", document.visibilityState);
3736
- if (document.visibilityState === "visible") {
3737
- resumeScheduler();
3738
- } else {
3739
- suspendScheduler();
3740
- }
3741
- };
3742
- const scheduleImmediate = () => {
3743
- run();
3744
- suspended = true;
3745
- scheduleNextRun(pollSchedule);
3746
- };
3747
- document.addEventListener("visibilitychange", watchDocumentVisibility);
3748
- $window.addEventListener("offline", suspendScheduler);
3749
- $window.addEventListener("online", resumeScheduler);
3750
- scheduler.next(true);
3751
- return {
3752
- subscribe: scheduler.subscribe.bind(scheduler),
3753
- scheduleImmediate,
3754
- unsubscribe: () => {
3755
- suspended = true;
3756
- if (scheduler) {
3757
- scheduler.unsubscribe();
3758
- }
3759
- scheduler = null;
3760
- source = null;
3761
- $timeout.cancel(pendingRun);
3762
- document.removeEventListener("visibilitychange", watchDocumentVisibility);
3763
- $window.removeEventListener("offline", suspendScheduler);
3764
- $window.removeEventListener("online", resumeScheduler);
3765
- }
3766
- };
3767
- }
3768
- }
3769
-
3770
- class NotifierService {
3771
- static publish(message) {
3772
- const existing = toast.isActive(message.key);
3773
- if (existing) {
3774
- toast.update(message.key, { render: message.content, ...message.options });
3775
- } else {
3776
- toast(message.content, { toastId: message.key, ...message.options });
3777
- }
3778
- }
3779
- static clear(key) {
3780
- toast.dismiss(key);
3781
- }
3782
- }
3783
-
3784
- class VersionChecker {
3785
- static initialize() {
3786
- $log.debug("Deck version", this.currentVersion.version, "created", timestamp(this.currentVersion.created));
3787
- this.scheduler = SchedulerFactory.createScheduler();
3788
- this.scheduler.subscribe(() => this.checkVersion());
3789
- }
3790
- static checkVersion() {
3791
- const url = `/version.json?_=${Date.now()}`;
3792
- $http.get(url).then((resp) => this.versionRetrieved(resp)).catch(() => {
3793
- });
3794
- }
3795
- static versionRetrieved(response) {
3796
- const data = response.data;
3797
- if (data.version === this.currentVersion.version) {
3798
- this.newVersionSeenCount = 0;
3799
- } else {
3800
- this.newVersionSeenCount++;
3801
- if (this.newVersionSeenCount > 5) {
3802
- $log.debug("New Deck version:", data.version, "created", timestamp(data.created));
3803
- NotifierService.publish({
3804
- key: "newVersion",
3805
- action: "create",
3806
- content: /* @__PURE__ */ React__default.createElement("div", null, "A new version of Spinnaker is available", " ", /* @__PURE__ */ React__default.createElement("a", {
3807
- role: "button",
3808
- className: "action",
3809
- onClick: () => document.location.reload(true)
3810
- }, "Refresh"))
3811
- });
3812
- this.scheduler.unsubscribe();
3813
- }
3814
- }
3815
- }
3816
- }
3817
- VersionChecker.currentVersion = version;
3818
- VersionChecker.newVersionSeenCount = 0;
3819
-
3820
3886
  var css_248z$2n = ".help-menu {\n border: 0;\n}\n.help-menu .dropdown-toggle,\n.help-menu .dropdown-toggle:active {\n font-size: 14px;\n font-weight: 200;\n margin: 0;\n border: 0;\n background: transparent;\n border-radius: 0;\n color: var(--color-white);\n}\n.help-menu .dropdown-toggle .caret,\n.help-menu .dropdown-toggle:active .caret {\n margin-left: 3px;\n}\n.help-menu .dropdown.open .dropdown-toggle {\n background-color: transparent;\n text-decoration: none;\n color: var(--color-white);\n box-shadow: none;\n}\n.help-menu .dropdown-menu {\n border: 0;\n}\n";
3821
3887
  styleInject(css_248z$2n);
3822
3888
 
@@ -4161,7 +4227,7 @@ const helpContents$4 = {
4161
4227
  "pipeline.config.bake.manifest.overrideExpressionEvaluation": '<p>Explicitly evaluate SpEL expressions in overrides just prior to manifest baking. Can be paired with the "Skip SpEL evaluation" option in the Deploy Manifest stage when baking a third-party manifest artifact with expressions not meant for Spinnaker to evaluate as SpEL.</p>',
4162
4228
  "pipeline.config.bake.manifest.templateRenderer": "<p>This is the engine used for rendering your manifest.</p>",
4163
4229
  "pipeline.config.bake.manifest.helm.chartFilePath": `
4164
- <p>This is the relative path to the directory containing the Chart.yaml file within your Git repo.</p>
4230
+ <p>This is the relative path to the directory containing the Chart.yaml file within your Git repo (or helm/image artifact).</p>
4165
4231
  <p>e.g.: <b>helm/my-chart</b></p>`,
4166
4232
  "pipeline.config.bake.manifest.helm.rawOverrides": "Use <i>--set</i> instead of <i>--set-string</i> when injecting override values. Values injected using <i>--set</i> will be converted to primitive types by Helm.",
4167
4233
  "pipeline.config.bake.manifest.helm.includeCRDs": "<p>Include Custom Resource Definitions in the templated output.</p>",
@@ -8019,7 +8085,8 @@ const ArtifactTypePatterns = {
8019
8085
  MAVEN_FILE: /maven\/file/,
8020
8086
  HTTP_FILE: /http\/file/,
8021
8087
  FRONT50_PIPELINE_TEMPLATE: /front50\/pipelineTemplate/,
8022
- ORACLE_OBJECT: /oracle\/object/
8088
+ ORACLE_OBJECT: /oracle\/object/,
8089
+ HELM_IMAGE: /helm\/image/
8023
8090
  };
8024
8091
  const excludeAllTypesExcept = (...types) => Object.keys(ArtifactTypePatterns).map((k) => ArtifactTypePatterns[k]).filter((type) => !types.includes(type));
8025
8092
 
@@ -12223,9 +12290,21 @@ class ExecutionFilterService {
12223
12290
  static groupExecutions(filteredExecutions, application) {
12224
12291
  const groups = [];
12225
12292
  let executions = [];
12226
- forOwn(groupBy(filteredExecutions, "name"), (groupedExecutions) => {
12227
- executions = executions.concat(groupedExecutions.sort((a, b) => this.executionSorter(a, b)));
12228
- });
12293
+ const executionIds = filteredExecutions.map((e) => e.id);
12294
+ const uniqueIds = new Set(executionIds);
12295
+ const hasDuplicates = executionIds.length !== uniqueIds.size;
12296
+ if (hasDuplicates) {
12297
+ const processedExecutionIds = new Set();
12298
+ forOwn(groupBy(filteredExecutions, "name"), (groupedExecutions) => {
12299
+ const uniqueExecutions = groupedExecutions.filter((execution) => !processedExecutionIds.has(execution.id));
12300
+ uniqueExecutions.forEach((execution) => processedExecutionIds.add(execution.id));
12301
+ executions = executions.concat(uniqueExecutions.sort((a, b) => this.executionSorter(a, b)));
12302
+ });
12303
+ } else {
12304
+ forOwn(groupBy(filteredExecutions, "name"), (groupedExecutions) => {
12305
+ executions = executions.concat(groupedExecutions.sort((a, b) => this.executionSorter(a, b)));
12306
+ });
12307
+ }
12229
12308
  executions.forEach((execution) => {
12230
12309
  const config = application.pipelineConfigs.data.find((p) => p.id === execution.pipelineConfigId);
12231
12310
  if (config != null && config.type === "templatedPipeline") {
@@ -12237,6 +12316,9 @@ class ExecutionFilterService {
12237
12316
  const executionGroups = groupBy(executions, "name");
12238
12317
  forOwn(executionGroups, (groupExecutions, key) => {
12239
12318
  var _a, _b;
12319
+ if (groupExecutions.length === 0) {
12320
+ return;
12321
+ }
12240
12322
  const matchId = (pipelineConfig) => pipelineConfig.id === groupExecutions[0].pipelineConfigId;
12241
12323
  const config = application.pipelineConfigs.data.concat((_b = (_a = application.strategyConfigs) == null ? void 0 : _a.data) != null ? _b : []).find(matchId);
12242
12324
  groupExecutions.sort((a, b) => this.executionSorter(a, b));
@@ -12254,6 +12336,9 @@ class ExecutionFilterService {
12254
12336
  if (sortFilter.groupBy === "timeBoundary") {
12255
12337
  const grouped = this.groupByTimeBoundary(executions);
12256
12338
  forOwn(grouped, (groupExecutions, key) => {
12339
+ if (groupExecutions.length === 0) {
12340
+ return;
12341
+ }
12257
12342
  groupExecutions.sort((a, b) => this.executionSorter(a, b));
12258
12343
  groups.push({
12259
12344
  heading: key,
@@ -12292,6 +12377,15 @@ class ExecutionFilterService {
12292
12377
  }
12293
12378
  static executionsAreDifferent(oldGroup, newGroup) {
12294
12379
  let changeDetected = false;
12380
+ const uniqueOldExecutions = [];
12381
+ const oldExecutionIds = new Set();
12382
+ oldGroup.executions.forEach((execution) => {
12383
+ if (!oldExecutionIds.has(execution.id)) {
12384
+ uniqueOldExecutions.push(execution);
12385
+ oldExecutionIds.add(execution.id);
12386
+ }
12387
+ });
12388
+ oldGroup.executions = uniqueOldExecutions;
12295
12389
  oldGroup.executions.forEach((execution) => {
12296
12390
  const newExecution = newGroup.executions.find((g) => g.id === execution.id);
12297
12391
  if (!newExecution) {
@@ -12304,12 +12398,13 @@ class ExecutionFilterService {
12304
12398
  }
12305
12399
  }
12306
12400
  });
12401
+ const existingExecutionIds = new Set(oldGroup.executions.map((e) => e.id));
12307
12402
  newGroup.executions.forEach((execution) => {
12308
- const oldExecution = oldGroup.executions.find((g) => g.id === execution.id);
12309
- if (!oldExecution) {
12403
+ if (!existingExecutionIds.has(execution.id)) {
12310
12404
  changeDetected = true;
12311
12405
  $log.debug("new execution found, adding", execution.id);
12312
12406
  oldGroup.executions.push(execution);
12407
+ existingExecutionIds.add(execution.id);
12313
12408
  }
12314
12409
  });
12315
12410
  return changeDetected;
@@ -12944,28 +13039,28 @@ const Base64Default = {
12944
13039
  editCmp: DefaultBase64ArtifactEditor
12945
13040
  };
12946
13041
 
12947
- const TYPE$8 = "bitbucket/file";
13042
+ const TYPE$9 = "bitbucket/file";
12948
13043
  const BitbucketMatch = {
12949
13044
  label: "Bitbucket",
12950
13045
  typePattern: ArtifactTypePatterns.BITBUCKET_FILE,
12951
- type: TYPE$8,
13046
+ type: TYPE$9,
12952
13047
  description: "A file stored in git, hosted by Bitbucket.",
12953
13048
  key: "bitbucket",
12954
13049
  isDefault: false,
12955
13050
  isMatch: true,
12956
- editCmp: singleFieldArtifactEditor("name", TYPE$8, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
13051
+ editCmp: singleFieldArtifactEditor("name", TYPE$9, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
12957
13052
  };
12958
13053
  const BitbucketDefault = {
12959
13054
  label: "Bitbucket",
12960
13055
  typePattern: ArtifactTypePatterns.BITBUCKET_FILE,
12961
- type: TYPE$8,
13056
+ type: TYPE$9,
12962
13057
  description: "A file stored in git, hosted by Bitbucket.",
12963
13058
  key: "default.bitbucket",
12964
13059
  isDefault: true,
12965
13060
  isMatch: false,
12966
13061
  editCmp: class extends ArtifactEditor$1 {
12967
13062
  constructor(props) {
12968
- super(props, TYPE$8);
13063
+ super(props, TYPE$9);
12969
13064
  this.onReferenceChanged = (reference) => {
12970
13065
  const clonedArtifact = cloneDeep(this.props.artifact);
12971
13066
  clonedArtifact.reference = reference;
@@ -13001,11 +13096,11 @@ const BitbucketDefault = {
13001
13096
  }
13002
13097
  };
13003
13098
 
13004
- const TYPE$7 = "custom/object";
13099
+ const TYPE$8 = "custom/object";
13005
13100
  const CUSTOM_ARTIFACT_ACCOUNT = "custom-artifact";
13006
13101
  class CustomArtifactEditor extends ArtifactEditor$1 {
13007
13102
  constructor(props) {
13008
- super(props, TYPE$7);
13103
+ super(props, TYPE$8);
13009
13104
  this.onTypeChanged = (type) => {
13010
13105
  this.updateArtifact({ type });
13011
13106
  };
@@ -13074,7 +13169,7 @@ class CustomArtifactEditor extends ArtifactEditor$1 {
13074
13169
  const CustomMatch = {
13075
13170
  label: "Custom",
13076
13171
  typePattern: ArtifactTypePatterns.CUSTOM_OBJECT,
13077
- type: TYPE$7,
13172
+ type: TYPE$8,
13078
13173
  description: "A custom-defined artifact.",
13079
13174
  key: "custom",
13080
13175
  isDefault: false,
@@ -13084,7 +13179,7 @@ const CustomMatch = {
13084
13179
  const CustomDefault = {
13085
13180
  label: "Custom",
13086
13181
  typePattern: ArtifactTypePatterns.CUSTOM_OBJECT,
13087
- type: TYPE$7,
13182
+ type: TYPE$8,
13088
13183
  description: "A custom-defined artifact.",
13089
13184
  key: "default.custom",
13090
13185
  isDefault: true,
@@ -13092,7 +13187,7 @@ const CustomDefault = {
13092
13187
  editCmp: CustomArtifactEditor
13093
13188
  };
13094
13189
 
13095
- const TYPE$6 = "docker/image";
13190
+ const TYPE$7 = "docker/image";
13096
13191
  const setNameAndVersionFromReference = (artifact) => {
13097
13192
  const ref = artifact.reference;
13098
13193
  if (isNil(ref)) {
@@ -13115,24 +13210,24 @@ const setNameAndVersionFromReference = (artifact) => {
13115
13210
  const DockerMatch = {
13116
13211
  label: "Docker",
13117
13212
  typePattern: ArtifactTypePatterns.DOCKER_IMAGE,
13118
- type: TYPE$6,
13213
+ type: TYPE$7,
13119
13214
  isDefault: false,
13120
13215
  isMatch: true,
13121
13216
  description: "A Docker image to be deployed.",
13122
13217
  key: "docker",
13123
- editCmp: singleFieldArtifactEditor("name", TYPE$6, "Docker image", "gcr.io/project/image", "pipeline.config.expectedArtifact.docker.name")
13218
+ editCmp: singleFieldArtifactEditor("name", TYPE$7, "Docker image", "gcr.io/project/image", "pipeline.config.expectedArtifact.docker.name")
13124
13219
  };
13125
13220
  const DockerDefault = {
13126
13221
  label: "Docker",
13127
13222
  typePattern: ArtifactTypePatterns.DOCKER_IMAGE,
13128
- type: TYPE$6,
13223
+ type: TYPE$7,
13129
13224
  isDefault: true,
13130
13225
  isMatch: false,
13131
13226
  description: "A Docker image to be deployed.",
13132
13227
  key: "default.docker",
13133
13228
  editCmp: class extends ArtifactEditor$1 {
13134
13229
  constructor(props) {
13135
- super(props, TYPE$6);
13230
+ super(props, TYPE$7);
13136
13231
  this.onReferenceChanged = (reference) => {
13137
13232
  const clonedArtifact = cloneDeep(this.props.artifact);
13138
13233
  clonedArtifact.reference = reference;
@@ -13154,28 +13249,28 @@ const DockerDefault = {
13154
13249
  }
13155
13250
  };
13156
13251
 
13157
- const TYPE$5 = "gcs/object";
13252
+ const TYPE$6 = "gcs/object";
13158
13253
  const GcsMatch = {
13159
13254
  label: "GCS",
13160
13255
  typePattern: ArtifactTypePatterns.GCS_OBJECT,
13161
- type: TYPE$5,
13256
+ type: TYPE$6,
13162
13257
  description: "A GCS object.",
13163
13258
  key: "gcs",
13164
13259
  isDefault: false,
13165
13260
  isMatch: true,
13166
- editCmp: singleFieldArtifactEditor("name", TYPE$5, "Object path", "gs://bucket/path/to/file", "pipeline.config.expectedArtifact.gcs.name")
13261
+ editCmp: singleFieldArtifactEditor("name", TYPE$6, "Object path", "gs://bucket/path/to/file", "pipeline.config.expectedArtifact.gcs.name")
13167
13262
  };
13168
13263
  const GcsDefault = {
13169
13264
  label: "GCS",
13170
13265
  typePattern: ArtifactTypePatterns.GCS_OBJECT,
13171
- type: TYPE$5,
13266
+ type: TYPE$6,
13172
13267
  description: "A GCS object.",
13173
13268
  key: "default.gcs",
13174
13269
  isDefault: true,
13175
13270
  isMatch: false,
13176
13271
  editCmp: class extends ArtifactEditor$1 {
13177
13272
  constructor(props) {
13178
- super(props, TYPE$5);
13273
+ super(props, TYPE$6);
13179
13274
  this.onReferenceChange = (reference) => {
13180
13275
  if (isNil(reference)) {
13181
13276
  return;
@@ -13207,28 +13302,28 @@ const GcsDefault = {
13207
13302
  }
13208
13303
  };
13209
13304
 
13210
- const TYPE$4 = "github/file";
13305
+ const TYPE$5 = "github/file";
13211
13306
  const GithubMatch = {
13212
13307
  label: "GitHub",
13213
13308
  description: "A file stored in git, hosted by GitHub.",
13214
13309
  key: "github",
13215
13310
  typePattern: ArtifactTypePatterns.GITHUB_FILE,
13216
- type: TYPE$4,
13311
+ type: TYPE$5,
13217
13312
  isDefault: false,
13218
13313
  isMatch: true,
13219
- editCmp: singleFieldArtifactEditor("name", TYPE$4, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
13314
+ editCmp: singleFieldArtifactEditor("name", TYPE$5, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
13220
13315
  };
13221
13316
  const GithubDefault = {
13222
13317
  label: "GitHub",
13223
13318
  typePattern: ArtifactTypePatterns.GITHUB_FILE,
13224
- type: TYPE$4,
13319
+ type: TYPE$5,
13225
13320
  description: "A file stored in git, hosted by GitHub.",
13226
13321
  key: "default.github",
13227
13322
  isDefault: true,
13228
13323
  isMatch: false,
13229
13324
  editCmp: class extends ArtifactEditor$1 {
13230
13325
  constructor(props) {
13231
- super(props, TYPE$4);
13326
+ super(props, TYPE$5);
13232
13327
  this.pathRegex = new RegExp("/repos/[^/]*/[^/]*/contents/(.*)$");
13233
13328
  this.onReferenceChange = (reference) => {
13234
13329
  const results = this.pathRegex.exec(reference);
@@ -13267,28 +13362,28 @@ const GithubDefault = {
13267
13362
  }
13268
13363
  };
13269
13364
 
13270
- const TYPE$3 = "gitlab/file";
13365
+ const TYPE$4 = "gitlab/file";
13271
13366
  const GitlabMatch = {
13272
13367
  label: "Gitlab",
13273
13368
  typePattern: ArtifactTypePatterns.GITLAB_FILE,
13274
- type: TYPE$3,
13369
+ type: TYPE$4,
13275
13370
  description: "A file stored in git, hosted by Gitlab.",
13276
13371
  key: "gitlab",
13277
13372
  isDefault: false,
13278
13373
  isMatch: true,
13279
- editCmp: singleFieldArtifactEditor("name", TYPE$3, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
13374
+ editCmp: singleFieldArtifactEditor("name", TYPE$4, "File path", "manifests/frontend.yaml", "pipeline.config.expectedArtifact.git.name")
13280
13375
  };
13281
13376
  const GitlabDefault = {
13282
13377
  label: "Gitlab",
13283
13378
  typePattern: ArtifactTypePatterns.GITLAB_FILE,
13284
- type: TYPE$3,
13379
+ type: TYPE$4,
13285
13380
  description: "A file stored in git, hosted by Gitlab.",
13286
13381
  key: "default.gitlab",
13287
13382
  isDefault: true,
13288
13383
  isMatch: false,
13289
13384
  editCmp: class extends ArtifactEditor$1 {
13290
13385
  constructor(props) {
13291
- super(props, TYPE$3);
13386
+ super(props, TYPE$4);
13292
13387
  this.pathRegex = new RegExp("/repos/[^/]*/[^/]*/contents/(.*)$");
13293
13388
  this.onReferenceChange = (reference) => {
13294
13389
  const results = this.pathRegex.exec(reference);
@@ -13327,7 +13422,7 @@ const GitlabDefault = {
13327
13422
  }
13328
13423
  };
13329
13424
 
13330
- const TYPE$2 = "git/repo";
13425
+ const TYPE$3 = "git/repo";
13331
13426
  class GitRepoArtifactEditor extends React__default.Component {
13332
13427
  constructor(props) {
13333
13428
  super(props);
@@ -13399,7 +13494,7 @@ const GitRepoMatch = {
13399
13494
  description: "A Git repository.",
13400
13495
  key: "gitrepo",
13401
13496
  typePattern: ArtifactTypePatterns.GIT_REPO,
13402
- type: TYPE$2,
13497
+ type: TYPE$3,
13403
13498
  isDefault: false,
13404
13499
  isMatch: true,
13405
13500
  editCmp: GitRepoArtifactEditor
@@ -13407,7 +13502,7 @@ const GitRepoMatch = {
13407
13502
  const GitRepoDefault = {
13408
13503
  label: "GitRepo",
13409
13504
  typePattern: ArtifactTypePatterns.GIT_REPO,
13410
- type: TYPE$2,
13505
+ type: TYPE$3,
13411
13506
  description: "A Git repository.",
13412
13507
  key: "default.gitrepo",
13413
13508
  isDefault: true,
@@ -13427,6 +13522,124 @@ class ArtifactService {
13427
13522
  }
13428
13523
  }
13429
13524
 
13525
+ const TYPE$2 = "helm/image";
13526
+ class HelmImageEditor extends React__default.Component {
13527
+ constructor(props) {
13528
+ super(props);
13529
+ this.state = {
13530
+ names: [],
13531
+ versions: [],
13532
+ versionsLoading: true,
13533
+ namesLoading: true
13534
+ };
13535
+ this.SEMVER = new RegExp(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/);
13536
+ this.onChange = (e, field) => {
13537
+ const clone = cloneDeep(this.props.artifact);
13538
+ clone[field] = e.value.toString();
13539
+ this.props.onChange(clone);
13540
+ };
13541
+ const { artifact } = this.props;
13542
+ if (artifact.type !== TYPE$2) {
13543
+ const clonedArtifact = cloneDeep(artifact);
13544
+ clonedArtifact.type = TYPE$2;
13545
+ props.onChange(clonedArtifact);
13546
+ }
13547
+ ArtifactService.getArtifactNames(TYPE$2, this.props.account.name).then((names) => {
13548
+ this.setState({
13549
+ names,
13550
+ namesLoading: false
13551
+ });
13552
+ }, () => {
13553
+ this.setState({
13554
+ names: [],
13555
+ namesLoading: false,
13556
+ versionsLoading: false,
13557
+ versions: []
13558
+ });
13559
+ });
13560
+ }
13561
+ componentDidMount() {
13562
+ const { artifact } = this.props;
13563
+ if (artifact.name) {
13564
+ this.getChartVersionOptions(artifact.name);
13565
+ }
13566
+ }
13567
+ componentDidUpdate(prevProps) {
13568
+ if (this.props.account.name !== prevProps.account.name) {
13569
+ ArtifactService.getArtifactNames(TYPE$2, this.props.account.name).then((names) => {
13570
+ this.setState({
13571
+ names,
13572
+ namesLoading: false,
13573
+ versions: []
13574
+ });
13575
+ }, () => {
13576
+ this.setState({
13577
+ names: [],
13578
+ namesLoading: false,
13579
+ versions: []
13580
+ });
13581
+ });
13582
+ }
13583
+ }
13584
+ render() {
13585
+ const { artifact } = this.props;
13586
+ const nameOptions = this.state.names.map((name) => ({ value: name, label: name }));
13587
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(StageConfigField, {
13588
+ label: "Name"
13589
+ }, !this.state.namesLoading && /* @__PURE__ */ React__default.createElement(TetheredSelect, {
13590
+ options: nameOptions,
13591
+ value: artifact.name || "",
13592
+ onChange: (e) => {
13593
+ this.onChange(e, "name");
13594
+ this.getChartVersionOptions(e.value.toString());
13595
+ },
13596
+ clearable: false
13597
+ }), this.state.namesLoading && /* @__PURE__ */ React__default.createElement(Spinner, null)), /* @__PURE__ */ React__default.createElement(StageConfigField, {
13598
+ label: "Version"
13599
+ }, !this.state.versionsLoading && /* @__PURE__ */ React__default.createElement(TetheredCreatable, {
13600
+ options: this.state.versions,
13601
+ value: artifact.version || "",
13602
+ onChange: (e) => {
13603
+ this.onChange(e, "version");
13604
+ },
13605
+ clearable: false
13606
+ }), this.state.versionsLoading && /* @__PURE__ */ React__default.createElement(Spinner, null)));
13607
+ }
13608
+ getChartVersionOptions(chartName) {
13609
+ const { artifact, account } = this.props;
13610
+ this.setState({ versionsLoading: true });
13611
+ ArtifactService.getArtifactVersions(TYPE$2, account.name, chartName).then((versions) => {
13612
+ if (artifact.version && !this.SEMVER.test(artifact.version)) {
13613
+ versions = versions.concat(artifact.version);
13614
+ }
13615
+ this.setState({
13616
+ versions: versions.map((v) => ({ label: v, value: v })),
13617
+ versionsLoading: false
13618
+ });
13619
+ });
13620
+ }
13621
+ }
13622
+ const HelmImageMatch = {
13623
+ label: "Helm",
13624
+ typePattern: ArtifactTypePatterns.HELM_IMAGE,
13625
+ type: TYPE$2,
13626
+ isDefault: false,
13627
+ isMatch: true,
13628
+ description: "A helm chart to be deployed",
13629
+ key: "helm",
13630
+ editCmp: HelmImageEditor
13631
+ };
13632
+ const HelmImageDefault = {
13633
+ label: "Helm",
13634
+ typePattern: ArtifactTypePatterns.HELM_IMAGE,
13635
+ type: TYPE$2,
13636
+ isDefault: true,
13637
+ isMatch: false,
13638
+ description: "A helm chart to be deployed",
13639
+ key: "default.helm",
13640
+ editCmp: HelmImageEditor
13641
+ };
13642
+
13430
13643
  const TYPE$1 = "helm/chart";
13431
13644
  class HelmEditor$1 extends React__default.Component {
13432
13645
  constructor(props) {
@@ -13903,6 +14116,7 @@ ArtifactIconService.registerType(ArtifactTypePatterns.JENKINS_FILE, jenkinsFileI
13903
14116
  ArtifactIconService.registerType(ArtifactTypePatterns.MAVEN_FILE, mavenFileIcon);
13904
14117
  ArtifactIconService.registerType(ArtifactTypePatterns.HTTP_FILE, httpFileIcon);
13905
14118
  ArtifactIconService.registerType(ArtifactTypePatterns.ORACLE_OBJECT, oracleObjectIcon);
14119
+ ArtifactIconService.registerType(ArtifactTypePatterns.HELM_IMAGE, helmChartIcon);
13906
14120
 
13907
14121
  class ArtifactReferenceService {
13908
14122
  static removeReferenceFromStages(reference, stages) {
@@ -14130,7 +14344,7 @@ class ExpectedArtifactSelectorViewController {
14130
14344
  } else {
14131
14345
  const artifact = ExpectedArtifactService.artifactFromExpected(expectedArtifact);
14132
14346
  const allAccounts = this.delegate.getExpectedArtifactAccounts();
14133
- this.accountsForArtifact = artifact.type === "helm/chart" ? allAccounts.filter((a) => a.types.includes(artifact.type) && a.name === artifact.artifactAccount) : allAccounts.filter((a) => a.types.includes(artifact.type));
14347
+ this.accountsForArtifact = artifact.type === "helm/chart" || artifact.type === "helm/image" ? allAccounts.filter((a) => a.types.includes(artifact.type) && a.name === artifact.artifactAccount) : allAccounts.filter((a) => a.types.includes(artifact.type));
14134
14348
  const selected = this.delegate.getSelectedAccount();
14135
14349
  if (!selected || !this.accountsForArtifact.find((a) => a.name === selected.name)) {
14136
14350
  if (this.accountsForArtifact.length) {
@@ -14815,7 +15029,7 @@ class ArtifactEditor extends React__default.Component {
14815
15029
  defaultArtifactAccountIfNecessary() {
14816
15030
  const { artifact, artifactAccounts } = this.props;
14817
15031
  if (!artifact.artifactAccount && artifactAccounts.length > 0) {
14818
- this.onArtifactAccountChanged(head(artifactAccounts.filter((a) => a.types.includes(artifact.type))) || head(artifactAccounts.filter((a) => a.types.includes(TYPE$7))) || head(artifactAccounts));
15032
+ this.onArtifactAccountChanged(head(artifactAccounts.filter((a) => a.types.includes(artifact.type))) || head(artifactAccounts.filter((a) => a.types.includes(TYPE$8))) || head(artifactAccounts));
14819
15033
  }
14820
15034
  }
14821
15035
  componentDidMount() {
@@ -15154,6 +15368,8 @@ const artifactKindConfigs = [
15154
15368
  GitlabDefault,
15155
15369
  HelmMatch,
15156
15370
  HelmDefault,
15371
+ HelmImageMatch,
15372
+ HelmImageDefault,
15157
15373
  HttpMatch,
15158
15374
  HttpDefault,
15159
15375
  IvyMatch,
@@ -17104,6 +17320,14 @@ class ServerGroupsUrlBuilder {
17104
17320
  provider: input.provider,
17105
17321
  project: input.project
17106
17322
  }, { inherit: false });
17323
+ if (input.provider === "ecs" || input.provider && input.provider.includes("ecs") || input.provider === "aws" || input.provider && input.provider.includes("aws")) {
17324
+ const serverGroupParts = input.serverGroup.split("-");
17325
+ let clusterName = input.serverGroup;
17326
+ if (serverGroupParts.length > 1 && serverGroupParts[serverGroupParts.length - 1].match(/^v\d+$/)) {
17327
+ clusterName = serverGroupParts.slice(0, -1).join("-");
17328
+ }
17329
+ return UrlBuilderUtils.buildUrl(href, { clusters: `${input.account}:${clusterName}` });
17330
+ }
17107
17331
  return UrlBuilderUtils.buildUrl(href, { q: input.serverGroup, acct: input.account, reg: input.region });
17108
17332
  }
17109
17333
  }
@@ -28627,10 +28851,15 @@ class NotificationsList extends React__default.Component {
28627
28851
  const { application, updateNotifications } = this.props;
28628
28852
  const { supportedNotificationTypes } = this.state;
28629
28853
  from(AppNotificationsService.getNotificationsForApplication(application.name)).pipe(takeUntil(this.destroy$)).subscribe((notifications) => {
28630
- const results = filter$1(flatten(supportedNotificationTypes.map((type) => {
28631
- return get(notifications, type) || [];
28632
- })), (allow) => allow !== void 0 && allow.level === "application");
28633
- updateNotifications(results);
28854
+ const newNotifications = supportedNotificationTypes.reduce((acc, type) => {
28855
+ const typeNotifications = notifications[type];
28856
+ if (typeNotifications && typeof typeNotifications !== "string") {
28857
+ acc.push(...typeNotifications);
28858
+ }
28859
+ return acc;
28860
+ }, []);
28861
+ const applicationNotifications = newNotifications.filter((allow) => allow !== void 0 && allow.level === "application");
28862
+ updateNotifications(applicationNotifications);
28634
28863
  });
28635
28864
  this.setState({ isNotificationsDirty: false });
28636
28865
  };
@@ -30239,7 +30468,7 @@ const _PipelineConfigValidator = class {
30239
30468
  if (pipeline.strategy && !pipeline.stages.some((stage) => stage.type === "deploy")) {
30240
30469
  messages.push("To be able to create new server groups, a custom strategy should contain a Deploy stage.");
30241
30470
  }
30242
- if ((pipeline.expectedArtifacts || []).some((a) => !a.matchArtifact || a.matchArtifact === {})) {
30471
+ if ((pipeline.expectedArtifacts || []).some((a) => !a.matchArtifact || isEmpty(a.matchArtifact))) {
30243
30472
  messages.push("Every expected artifact must specify an artifact to match against.");
30244
30473
  }
30245
30474
  return messages;
@@ -34832,7 +35061,7 @@ let ProjectHeader = class extends React__default.Component {
34832
35061
  this.handleDropdownToggle = (isOpen) => this.setState({ isOpen });
34833
35062
  this.configureProject = () => {
34834
35063
  const { projectConfiguration } = this.props;
34835
- const { $state } = ReactInjector;
35064
+ const $state = this.props.transition.router.stateService;
34836
35065
  const title = "Configure project";
34837
35066
  ConfigureProjectModal.show({ title, projectConfiguration }).then((result) => {
34838
35067
  if (result.action === "delete") {
@@ -34840,6 +35069,8 @@ let ProjectHeader = class extends React__default.Component {
34840
35069
  } else if (result.action === "upsert") {
34841
35070
  $state.go($state.current, { project: result.name }, { location: "replace", reload: true });
34842
35071
  }
35072
+ }).catch((err) => {
35073
+ console.error(err);
34843
35074
  });
34844
35075
  };
34845
35076
  }
@@ -34969,126 +35200,53 @@ class ProjectsSearchResultType extends SearchResultType {
34969
35200
  }
34970
35201
  searchResultTypeRegistry.register(new ProjectsSearchResultType());
34971
35202
 
34972
- class PubsubSubscriptionReader {
34973
- static getPubsubSubscriptions() {
34974
- return REST("/pubsub/subscriptions").get();
34975
- }
34976
- }
34977
-
34978
- function RegionSelectInput(props) {
34979
- const { account, readOnly, regions, ...otherProps } = props;
34980
- if (!account) {
34981
- return /* @__PURE__ */ React__default.createElement("div", null, "(Select an account)");
34982
- } else if (readOnly) {
34983
- return /* @__PURE__ */ React__default.createElement("p", {
34984
- className: "form-control-static"
34985
- }, props.value);
34986
- }
34987
- const allRegions = regions ? regions : [];
34988
- const options = allRegions.map((region) => ({
34989
- value: region.name,
34990
- label: `${region.name}${region.deprecated ? " (deprecated in the '" + account + "' account)" : ""}`
34991
- }));
34992
- options.unshift({ label: "Select...", value: "", disabled: true });
34993
- return /* @__PURE__ */ React__default.createElement(SelectInput, {
34994
- ...otherProps,
34995
- className: "form-control input-sm",
34996
- options
34997
- });
34998
- }
34999
-
35000
- class RegionSelectField extends React__default.Component {
35001
- handleChange(event) {
35002
- const { component, onChange, field } = this.props;
35003
- component[field] = event.target.value;
35004
- onChange(event.target.value);
35005
- $rootScope.$apply();
35006
- this.setState({});
35007
- }
35008
- render() {
35009
- const { labelColumns, fieldColumns, account, regions, readOnly, component, field } = this.props;
35010
- return /* @__PURE__ */ React__default.createElement("div", {
35011
- className: "form-group"
35012
- }, /* @__PURE__ */ React__default.createElement("div", {
35013
- className: `col-md-${labelColumns} sm-label-right`
35014
- }, "Region"), /* @__PURE__ */ React__default.createElement("div", {
35015
- className: `col-md-${fieldColumns || 7}`
35016
- }, /* @__PURE__ */ React__default.createElement(RegionSelectInput, {
35017
- account,
35018
- regions,
35019
- readOnly,
35020
- value: component[field],
35021
- onChange: (evt) => this.handleChange(evt)
35022
- })));
35023
- }
35024
- }
35025
-
35026
- class RetryService {
35027
- static buildRetrySequence(func, stopCondition, limit, interval) {
35028
- const call = func();
35029
- const promise = call.hasOwnProperty("then") ? call : $q.resolve(call);
35030
- if (limit === 0) {
35031
- return promise;
35032
- } else {
35033
- return promise.then((result) => {
35034
- if (stopCondition(result)) {
35035
- return result;
35036
- } else {
35037
- return $timeout(interval).then(() => this.buildRetrySequence(func, stopCondition, limit - 1, interval));
35038
- }
35039
- }).catch(() => $timeout(interval).then(() => this.buildRetrySequence(func, stopCondition, limit - 1, interval)));
35203
+ const PaginationControls = ({ onPageChanged, activePage, totalPages }) => {
35204
+ const Item = (props) => /* @__PURE__ */ React__default.createElement("li", {
35205
+ className: `${props.isActive ? "active" : ""} ${props.disabled ? "disabled" : ""}`
35206
+ }, /* @__PURE__ */ React__default.createElement("a", {
35207
+ className: `${!props.disabled ? "clickable" : ""}`,
35208
+ onClick: props.onClick
35209
+ }, props.value));
35210
+ const Paging = createUltimatePagination({
35211
+ WrapperComponent: Pagination,
35212
+ itemTypeToComponent: {
35213
+ [ITEM_TYPES.PAGE]: ({ value, isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35214
+ value,
35215
+ isActive,
35216
+ onClick
35217
+ }),
35218
+ [ITEM_TYPES.ELLIPSIS]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35219
+ value: `\u2026`,
35220
+ disabled: isActive,
35221
+ onClick
35222
+ }),
35223
+ [ITEM_TYPES.FIRST_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35224
+ value: `\xAB`,
35225
+ disabled: isActive,
35226
+ onClick
35227
+ }),
35228
+ [ITEM_TYPES.PREVIOUS_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35229
+ value: `\u2039`,
35230
+ disabled: isActive,
35231
+ onClick
35232
+ }),
35233
+ [ITEM_TYPES.NEXT_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35234
+ value: `\u203A`,
35235
+ disabled: isActive,
35236
+ onClick
35237
+ }),
35238
+ [ITEM_TYPES.LAST_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
35239
+ value: `\xBB`,
35240
+ disabled: isActive,
35241
+ onClick
35242
+ })
35040
35243
  }
35041
- }
35042
- }
35043
-
35044
- const ItemDetails = ({ item, transformName }) => /* @__PURE__ */ React.createElement("div", {
35045
- className: "flex-container-h"
35046
- }, /* @__PURE__ */ React.createElement("div", {
35047
- className: "flex-grow"
35048
- }, /* @__PURE__ */ React.createElement("span", {
35049
- className: "small"
35050
- }, /* @__PURE__ */ React.createElement(StatusGlyph, {
35051
- item
35052
- })), transformName ? robotToHuman(item.name) : item.name), /* @__PURE__ */ React.createElement("div", {
35053
- className: "flex-pull-right"
35054
- }, duration(item.runningTimeInMs)));
35055
- const RunningTasksPopoverContent = ({ executions, tasks }) => {
35056
- const sortedTasks = orderBy(tasks || [], ["startTime"], ["asc"]);
35057
- return /* @__PURE__ */ React.createElement("div", {
35058
- className: "RunningTasksPopoverContent"
35059
- }, /* @__PURE__ */ React.createElement("div", null, sortedTasks.map((task, index) => /* @__PURE__ */ React.createElement("div", {
35060
- key: `task-${index}`
35061
- }, /* @__PURE__ */ React.createElement("strong", null, task.name), displayableTasks(task.steps).map((step, i) => /* @__PURE__ */ React.createElement(ItemDetails, {
35062
- key: `task-step-${i}`,
35063
- item: step,
35064
- transformName: true
35065
- }))))), /* @__PURE__ */ React.createElement("div", null, executions.map((execution, index) => /* @__PURE__ */ React.createElement("div", {
35066
- key: `execution-${index}`
35067
- }, /* @__PURE__ */ React.createElement("strong", null, " Pipeline: ", execution.name, " "), (execution.stages || []).map((stage, i) => /* @__PURE__ */ React.createElement(ItemDetails, {
35068
- key: `execution-stage-${i}`,
35069
- item: stage
35070
- }))))));
35071
- };
35072
-
35073
- const RunningTasksTag = ({ executions, tasks }) => {
35074
- const runningExecutions = (executions || []).filter((e) => e.isRunning || e.hasNotStarted);
35075
- const PopoverContent = React.useCallback(() => /* @__PURE__ */ React.createElement(RunningTasksPopoverContent, {
35076
- executions: runningExecutions,
35077
- tasks
35078
- }), [tasks, runningExecutions]);
35079
- if (!(tasks == null ? void 0 : tasks.length) && !runningExecutions.length) {
35080
- return null;
35081
- }
35082
- return /* @__PURE__ */ React.createElement("span", {
35083
- className: "RunningTasksTag"
35084
- }, /* @__PURE__ */ React.createElement(HoverablePopover, {
35085
- Component: PopoverContent,
35086
- className: "menu-running-tasks"
35087
- }, /* @__PURE__ */ React.createElement("span", {
35088
- className: "icon"
35089
- }, /* @__PURE__ */ React.createElement("span", {
35090
- className: "glyphicon icon-spinner fa-spin-slow"
35091
- }))));
35244
+ });
35245
+ return /* @__PURE__ */ React__default.createElement(Paging, {
35246
+ onChange: onPageChanged,
35247
+ currentPage: activePage,
35248
+ totalPages
35249
+ });
35092
35250
  };
35093
35251
 
35094
35252
  var __defProp$h = Object.defineProperty;
@@ -35102,154 +35260,789 @@ var __decorateClass$h = (decorators, target, key, kind) => {
35102
35260
  __defProp$h(target, key, result);
35103
35261
  return result;
35104
35262
  };
35105
- class LoadBalancers$2 extends React__default.Component {
35106
- render() {
35107
- const { application, serverGroup } = this.props;
35108
- const hasLoadBalancer = !!get(serverGroup, "loadBalancers.length") || !!get(serverGroup, "targetGroups.length");
35109
- return hasLoadBalancer && /* @__PURE__ */ React__default.createElement(LoadBalancersTagWrapper, {
35110
- key: "lbwrapper",
35111
- application,
35112
- serverGroup
35113
- });
35114
- }
35115
- }
35116
- class MultiSelectCheckbox extends React__default.Component {
35117
- render() {
35118
- const {
35119
- isMultiSelected,
35120
- sortFilter: { multiselect }
35121
- } = this.props;
35122
- return multiselect && /* @__PURE__ */ React__default.createElement("input", {
35123
- type: "checkbox",
35124
- checked: isMultiSelected
35125
- });
35126
- }
35127
- }
35128
- class CloudProviderIcon extends React__default.Component {
35129
- render() {
35130
- const { serverGroup } = this.props;
35131
- return /* @__PURE__ */ React__default.createElement(CloudProviderLogo, {
35132
- provider: serverGroup.type,
35133
- height: "16px",
35134
- width: "16px"
35135
- });
35136
- }
35137
- }
35138
- class ImageList extends React__default.Component {
35139
- toggle() {
35140
- this.setState((previousState) => {
35141
- return { collapsed: !previousState.collapsed };
35142
- });
35143
- }
35263
+ let InsightMenu = class extends React__default.Component {
35144
35264
  constructor(props) {
35145
35265
  super(props);
35146
- this.state = {
35147
- collapsed: true
35266
+ this.createProject = () => ConfigureProjectModal.show().then((result) => {
35267
+ this.$state.go("home.project.dashboard", { project: result.name });
35268
+ }).catch(() => {
35269
+ });
35270
+ this.createApplication = () => {
35271
+ this.$uibModal.open({
35272
+ scope: this.$rootScope.$new(),
35273
+ templateUrl: this.overrideRegistry.getTemplate("createApplicationModal", "core/src/application/modal/newapplication.html"),
35274
+ resolve: {
35275
+ name: () => ""
35276
+ },
35277
+ controller: this.overrideRegistry.getController("CreateApplicationModalCtrl"),
35278
+ controllerAs: "newAppModal"
35279
+ }).result.then(this.routeToApplication).catch(() => {
35280
+ });
35148
35281
  };
35149
- this.toggle = this.toggle.bind(this);
35150
- }
35151
- render() {
35152
- const images = this.props.images.sort();
35153
- const { collapsed } = this.state;
35154
- const buttonStyle = {
35155
- padding: 0,
35156
- fontSize: "13px"
35282
+ this.routeToApplication = (app) => {
35283
+ this.$state.go("home.applications.application", { application: app.name });
35157
35284
  };
35158
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, collapsed && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("span", null, images[0]), "\xA0", images.length > 1 && /* @__PURE__ */ React__default.createElement("button", {
35159
- className: "link",
35160
- onClick: this.toggle,
35161
- style: buttonStyle
35162
- }, "(+ ", images.length - 1, " more)")), !collapsed && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, images.map((image, index) => /* @__PURE__ */ React__default.createElement("span", {
35163
- key: image
35164
- }, index > 0 && /* @__PURE__ */ React__default.createElement("br", null), image, index < images.length - 1 ? "," : "")), /* @__PURE__ */ React__default.createElement("br", null), /* @__PURE__ */ React__default.createElement("button", {
35165
- className: "link",
35166
- onClick: this.toggle,
35167
- style: buttonStyle
35168
- }, "collapse")));
35169
- }
35170
- }
35171
- class SequenceAndBuildAndImages extends React__default.Component {
35172
- render() {
35173
- const { serverGroup, jenkins, images, docker } = this.props;
35174
- const serverGroupSequence = NameUtils.getSequence(serverGroup.moniker.sequence);
35175
- const ciBuild = serverGroup.buildInfo && serverGroup.buildInfo.ciBuild;
35176
- const appArtifact = serverGroup.buildInfo && serverGroup.buildInfo.appArtifact;
35177
- return /* @__PURE__ */ React__default.createElement("div", null, !!serverGroupSequence && /* @__PURE__ */ React__default.createElement("span", {
35178
- className: "server-group-sequence"
35179
- }, " ", serverGroupSequence), !!serverGroupSequence && (!!jenkins || !!images) && /* @__PURE__ */ React__default.createElement("span", null, ": "), !!jenkins && /* @__PURE__ */ React__default.createElement("a", {
35180
- className: "build-link sp-margin-xs-right",
35181
- href: jenkins.href,
35182
- target: "_blank"
35183
- }, "Build: #", jenkins.number), !!docker && /* @__PURE__ */ React__default.createElement("a", {
35184
- className: "build-link",
35185
- href: docker.href,
35186
- target: "_blank"
35187
- }, docker.image, ":", docker.tag || docker.digest), !!appArtifact && !!appArtifact.version ? /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "\xA0\xA0\xA0\xA0", /* @__PURE__ */ React__default.createElement("img", {
35188
- className: "artifact-icon",
35189
- src: ArtifactIconService.getPath("maven/file"),
35190
- width: "18",
35191
- height: "18"
35192
- }), !!appArtifact.url ? /* @__PURE__ */ React__default.createElement("a", {
35193
- className: "build-link",
35194
- href: appArtifact.url,
35195
- target: "_blank"
35196
- }, appArtifact.version) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, appArtifact.version)) : !!ciBuild && !!ciBuild.jobNumber && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "\xA0\xA0\xA0\xA0", /* @__PURE__ */ React__default.createElement("img", {
35197
- className: "artifact-icon",
35198
- src: ArtifactIconService.getPath("jenkins/file"),
35199
- width: "18",
35200
- height: "18"
35201
- }), !!ciBuild.jobUrl ? /* @__PURE__ */ React__default.createElement("a", {
35202
- className: "build-link",
35203
- href: ciBuild.jobUrl,
35204
- target: "_blank"
35205
- }, ciBuild.jobNumber) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, ciBuild.jobNumber)), !!images && /* @__PURE__ */ React__default.createElement(ImageList, {
35206
- ...this.props
35207
- }));
35208
- }
35209
- }
35210
- class Alerts extends React__default.Component {
35211
- render() {
35212
- const { application, serverGroup } = this.props;
35213
- return /* @__PURE__ */ React__default.createElement(EntityNotifications, {
35214
- application,
35215
- entity: serverGroup,
35216
- entityType: "serverGroup",
35217
- hOffsetPercent: "20%",
35218
- onUpdate: () => application.serverGroups.refresh(),
35219
- pageLocation: "pod",
35220
- placement: "top"
35221
- });
35285
+ this.refreshAllCaches = () => {
35286
+ if (this.state.refreshingCache) {
35287
+ return;
35288
+ }
35289
+ this.setState({ refreshingCache: true });
35290
+ this.cacheInitializer.refreshCaches().then(() => {
35291
+ this.setState({ refreshingCache: false });
35292
+ });
35293
+ };
35294
+ this.state = {};
35295
+ this.$state = ReactInjector.$state;
35296
+ this.$uibModal = ModalInjector.modalService;
35297
+ this.$rootScope = ReactInjector.$rootScope;
35298
+ this.overrideRegistry = ReactInjector.overrideRegistry;
35299
+ this.cacheInitializer = ReactInjector.cacheInitializer;
35222
35300
  }
35223
- }
35224
- let Health = class extends React__default.Component {
35225
35301
  render() {
35226
- const { serverGroup } = this.props;
35227
- return /* @__PURE__ */ React__default.createElement(HealthCounts, {
35228
- container: serverGroup.instanceCounts
35229
- });
35302
+ const { createApp, createProject, refreshCaches } = this.props;
35303
+ const refreshMarkup = this.state.refreshingCache ? /* @__PURE__ */ React__default.createElement("span", null, /* @__PURE__ */ React__default.createElement("span", {
35304
+ className: "fa fa-sync-alt fa-spin"
35305
+ }), " Refreshing...") : /* @__PURE__ */ React__default.createElement("span", null, "Refresh all caches");
35306
+ return /* @__PURE__ */ React__default.createElement("div", {
35307
+ id: "insight-menu"
35308
+ }, createProject && /* @__PURE__ */ React__default.createElement(Button$1, {
35309
+ bsStyle: createApp ? "default" : "primary",
35310
+ href: "javascript:void(0)",
35311
+ onClick: this.createProject,
35312
+ style: { marginRight: createApp ? "5px" : "" }
35313
+ }, "Create Project"), createApp && /* @__PURE__ */ React__default.createElement(Button$1, {
35314
+ bsStyle: "primary",
35315
+ href: "javascript:void(0)",
35316
+ onClick: this.createApplication,
35317
+ style: { marginRight: refreshCaches ? "5px" : "" }
35318
+ }, "Create Application"), refreshCaches && /* @__PURE__ */ React__default.createElement(Button$1, {
35319
+ href: "javascript:void(0)",
35320
+ onClick: this.refreshAllCaches
35321
+ }, refreshMarkup));
35230
35322
  }
35231
35323
  };
35232
- Health = __decorateClass$h([
35233
- Overridable("serverGroups.pod.header.health")
35234
- ], Health);
35235
- class RunningTasks$1 extends React__default.Component {
35236
- render() {
35237
- const { serverGroup } = this.props;
35238
- const hasRunningExecutions = !!serverGroup.runningExecutions.length || !!serverGroup.runningTasks.length;
35239
- return hasRunningExecutions && /* @__PURE__ */ React__default.createElement(RunningTasksTag, {
35240
- tasks: serverGroup.runningTasks,
35241
- executions: serverGroup.runningExecutions
35242
- });
35243
- }
35244
- }
35245
- let ServerGroupHeader = class extends React__default.Component {
35246
- render() {
35247
- const props = this.props;
35248
- return /* @__PURE__ */ React__default.createElement("div", {
35249
- className: "horizontal top server-group-title sticky-header-3"
35250
- }, /* @__PURE__ */ React__default.createElement("div", {
35251
- className: "horizontal section-title flex-1"
35252
- }, /* @__PURE__ */ React__default.createElement(MultiSelectCheckbox, {
35324
+ InsightMenu.defaultProps = { createApp: true, createProject: true, refreshCaches: true };
35325
+ InsightMenu = __decorateClass$h([
35326
+ Overridable("createInsightMenu")
35327
+ ], InsightMenu);
35328
+ window.angular.module("ng").run(["$templateCache", function(templateCache) {
35329
+ templateCache.put("core/src/application/modal/newapplication.html", `<div class="modal-page">
35330
+ <modal-close dismiss="$dismiss()"></modal-close>
35331
+ <div class="modal-header">
35332
+ <h4 class="modal-title">New Application</h4>
35333
+ </div>
35334
+ <div ng-if="newAppModal.state.initializing" style="height: 200px">
35335
+ <loading-spinner size="'medium'"></loading-spinner>
35336
+ </div>
35337
+ <div ng-if="newAppModal.state.initializeFailed" style="...">
35338
+ <div
35339
+ class="horizontal middle center heading-4"
35340
+ style="padding-left: 15px; padding-right: 15px; margin-bottom: 250px; height: 150px"
35341
+ >
35342
+ <i class="fa fa-exclamation-triangle" style="padding-right: 8px"></i>
35343
+ <span>
35344
+ Error initializing dialog. Check that your gate endpoint is accessible. Further information on troubleshooting
35345
+ this error is available <a href="https://www.spinnaker.io/setup/quickstart/faq/">here</a>.
35346
+ </span>
35347
+ </div>
35348
+ </div>
35349
+ <form
35350
+ role="form"
35351
+ class="container-fluid"
35352
+ novalidate
35353
+ name="newApplicationForm"
35354
+ ng-if="!(newAppModal.state.initializing || newAppModal.state.initializeFailed)"
35355
+ >
35356
+ <div class="modal-body">
35357
+ <div class="form-group row">
35358
+ <div class="col-sm-3 sm-label-right">Name *</div>
35359
+ <div class="col-sm-9">
35360
+ <input
35361
+ type="text"
35362
+ autofocus
35363
+ name="name"
35364
+ class="form-control input-sm"
35365
+ data-purpose="application-name"
35366
+ ng-model="newAppModal.application.name"
35367
+ placeholder="Enter an application name"
35368
+ validate-unique="newAppModal.data.appNameList"
35369
+ ng-model-options="{allowInvalid: true}"
35370
+ validate-application-name
35371
+ cloud-providers="newAppModal.application.cloudProviders"
35372
+ required
35373
+ />
35374
+ </div>
35375
+ </div>
35376
+
35377
+ <application-name-validation-messages
35378
+ name="newAppModal.application.name"
35379
+ cloud-providers="newAppModal.application.cloudProviders"
35380
+ ></application-name-validation-messages>
35381
+
35382
+ <div class="form-group row slide-in" ng-if="newApplicationForm.name.$error.validateUnique">
35383
+ <div class="col-sm-9 col-sm-offset-3 error-message">
35384
+ <span>Application name must be unique.</span>
35385
+ </div>
35386
+ </div>
35387
+
35388
+ <div class="form-group row">
35389
+ <div class="col-sm-3 sm-label-right">Owner Email *</div>
35390
+ <div class="col-sm-9">
35391
+ <input
35392
+ type="email"
35393
+ name="email"
35394
+ class="form-control input-sm"
35395
+ data-purpose="application-email"
35396
+ ng-model="newAppModal.application.email"
35397
+ placeholder="Enter an email address"
35398
+ required
35399
+ />
35400
+ </div>
35401
+ </div>
35402
+
35403
+ <div class="form-group row slide-in" ng-if="newApplicationForm.email.$dirty && newApplicationForm.email.$invalid">
35404
+ <div class="col-sm-9 col-sm-offset-3 error-message">
35405
+ <span>Please enter a valid email address</span>
35406
+ </div>
35407
+ </div>
35408
+
35409
+ <div class="form-group row">
35410
+ <div class="col-sm-3 sm-label-right">Repo Type</div>
35411
+ <div class="col-sm-9">
35412
+ <select
35413
+ class="form-control input-sm"
35414
+ ng-options="repoType for repoType in newAppModal.data.gitSources"
35415
+ ng-model="newAppModal.application.repoType"
35416
+ >
35417
+ <option value="">Select Repo Type</option>
35418
+ </select>
35419
+ </div>
35420
+ </div>
35421
+ <div class="form-group row" ng-if="newAppModal.application.repoType">
35422
+ <div class="col-sm-3 sm-label-right">Repo Project</div>
35423
+ <div class="col-sm-9">
35424
+ <input
35425
+ type="text"
35426
+ class="form-control input-sm"
35427
+ ng-model="newAppModal.application.repoProjectKey"
35428
+ placeholder="Enter your source repository project name"
35429
+ />
35430
+ </div>
35431
+ </div>
35432
+ <div class="form-group row" ng-if="newAppModal.application.repoType">
35433
+ <div class="col-sm-3 sm-label-right">Repo Name</div>
35434
+ <div class="col-sm-9">
35435
+ <input
35436
+ type="text"
35437
+ class="form-control input-sm"
35438
+ ng-model="newAppModal.application.repoSlug"
35439
+ placeholder="Enter your source repository name (not the URL)"
35440
+ pattern="^((?!://).)*$"
35441
+ name="repoSlug"
35442
+ />
35443
+ </div>
35444
+ </div>
35445
+
35446
+ <div class="form-group row slide-in" ng-messages="newApplicationForm.repoSlug.$error">
35447
+ <div class="col-sm-9 col-sm-offset-3 error-message" ng-message="pattern">
35448
+ Enter your source repository name (not the URL).
35449
+ </div>
35450
+ </div>
35451
+
35452
+ <chaos-monkey-new-application-config
35453
+ application-config="newAppModal.application"
35454
+ ></chaos-monkey-new-application-config>
35455
+
35456
+ <render-if-feature feature="pagerDuty">
35457
+ <pager-duty-select-field component="newAppModal.application"></pager-duty-select-field>
35458
+ </render-if-feature>
35459
+
35460
+ <render-if-feature feature="slack">
35461
+ <slack-channel-selector
35462
+ channel="newAppModal.application.slackChannel"
35463
+ callback="newAppModal.setAttribute"
35464
+ ></slack-channel-selector>
35465
+ </render-if-feature>
35466
+
35467
+ <div class="form-group row">
35468
+ <div class="col-sm-3 sm-label-right">Description</div>
35469
+ <div class="col-sm-9">
35470
+ <textarea
35471
+ class="form-control input-sm"
35472
+ ng-model="newAppModal.application.description"
35473
+ placeholder="Enter a description"
35474
+ data-purpose="application-description"
35475
+ >
35476
+ </textarea>
35477
+ </div>
35478
+ </div>
35479
+
35480
+ <div class="form-group row" ng-if="newAppModal.data.cloudProviders.length > 1">
35481
+ <div class="col-md-3 sm-label-right">Cloud Providers</div>
35482
+ <div class="col-md-5">
35483
+ <ui-select multiple ng-model="newAppModal.application.cloudProviders" class="form-control input-sm">
35484
+ <ui-select-match> {{$item}} </ui-select-match>
35485
+ <ui-select-choices repeat="provider in newAppModal.data.cloudProviders | filter: $select.search">
35486
+ {{provider}}
35487
+ </ui-select-choices>
35488
+ </ui-select>
35489
+ </div>
35490
+ </div>
35491
+
35492
+ <application-provider-fields
35493
+ cloud-providers="newAppModal.data.cloudProviders"
35494
+ application="newAppModal.application"
35495
+ >
35496
+ </application-provider-fields>
35497
+
35498
+ <div class="form-group row">
35499
+ <div class="col-sm-3 sm-label-right">Instance Health</div>
35500
+ <div class="col-sm-9 sm-control-field checkbox">
35501
+ <label>
35502
+ <input type="checkbox" ng-model="newAppModal.application.platformHealthOnly" />
35503
+ Consider only cloud provider health when executing tasks
35504
+ <help-field key="application.platformHealthOnly"></help-field>
35505
+ </label>
35506
+ </div>
35507
+ </div>
35508
+
35509
+ <div class="form-group row">
35510
+ <div class="col-sm-3 sm-label-right"></div>
35511
+ <div class="col-sm-9 sm-control-field checkbox">
35512
+ <label>
35513
+ <input
35514
+ type="checkbox"
35515
+ ng-model="newAppModal.application.platformHealthOnlyShowOverride"
35516
+ ng-click="newAppModal.updateCloudProviderHealthWarning()"
35517
+ />
35518
+ Show health override option for each operation
35519
+ <help-field key="application.showPlatformHealthOverride"></help-field>
35520
+ </label>
35521
+ </div>
35522
+ </div>
35523
+
35524
+ <div class="col-md-12" ng-if="newAppModal.data.showOverrideWarning">
35525
+ <div class="alert alert-warning">
35526
+ <p>
35527
+ <i class="fa fa-exclamation-triangle"></i>
35528
+ {{newAppModal.data.showOverrideWarning}}
35529
+ </p>
35530
+ <p class="text-right">
35531
+ <a
35532
+ class="btn btn-sm btn-default dirty-flag-dismiss"
35533
+ href
35534
+ ng-click="newAppModal.data.showOverrideWarning = null"
35535
+ >Okay</a
35536
+ >
35537
+ </p>
35538
+ </div>
35539
+ </div>
35540
+
35541
+ <div class="form-group row">
35542
+ <div class="col-sm-3 sm-label-right">
35543
+ Instance Port
35544
+ <help-field key="application.instance.port"></help-field>
35545
+ </div>
35546
+ <div class="col-sm-2">
35547
+ <input
35548
+ type="number"
35549
+ min="0"
35550
+ max="65536"
35551
+ class="form-control input-sm"
35552
+ ng-model="newAppModal.application.instancePort"
35553
+ name="instancePort"
35554
+ />
35555
+ </div>
35556
+ </div>
35557
+
35558
+ <div class="form-group row">
35559
+ <div class="col-sm-3 sm-label-right">Pipeline Behavior</div>
35560
+ <div class="col-sm-9 sm-control-field checkbox">
35561
+ <label>
35562
+ <input type="checkbox" ng-model="editApp.applicationAttributes.enableRestartRunningExecutions" />
35563
+ Enable restarting running pipelines
35564
+ </label>
35565
+ <help-field key="application.enableRestartRunningExecutions"></help-field>
35566
+ <label>
35567
+ <input type="checkbox" ng-model="editApp.applicationAttributes.enableRerunActiveExecutions" />
35568
+ Enable re-run button on active pipelines
35569
+ </label>
35570
+ <help-field key="application.enableRerunActiveExecutions"></help-field>
35571
+ </div>
35572
+ </div>
35573
+
35574
+ <render-if-feature feature="fiatEnabled">
35575
+ <div class="form-group row">
35576
+ <div class="col-sm-3 sm-label-right">Permissions <help-field key="application.permissions"></help-field></div>
35577
+ <div class="col-sm-9">
35578
+ <permissions-configurer
35579
+ permissions="newAppModal.application.permissions"
35580
+ on-permissions-change="newAppModal.handlePermissionsChange"
35581
+ required-group-membership="newAppModal.application.requiredGroupMembership"
35582
+ >
35583
+ </permissions-configurer>
35584
+ </div>
35585
+ </div>
35586
+ </render-if-feature>
35587
+
35588
+ <div class="form-group row slide-in" ng-if="newAppModal.state.errorMessages.length">
35589
+ <div class="col-md-12">
35590
+ <div class="alert alert-danger">
35591
+ <div ng-repeat="errorMessage in newAppModal.state.errorMessages">
35592
+ <status-glyph item="{isFailed: true}"></status-glyph> {{errorMessage}}
35593
+ </div>
35594
+ </div>
35595
+ </div>
35596
+ </div>
35597
+
35598
+ <div class="form-group row">
35599
+ <div class="col-md-12">
35600
+ <em>* Required</em>
35601
+ </div>
35602
+ </div>
35603
+ </div>
35604
+
35605
+ <div class="modal-footer">
35606
+ <a href class="btn btn-default" ng-click="$dismiss()">Cancel</a>
35607
+ <submit-button
35608
+ is-new="true"
35609
+ is-disabled="newApplicationForm.$invalid || newAppModal.state.submitting || newAppModal.data.showOverrideWarning || newAppModal.state.permissionsInvalid"
35610
+ submitting="newAppModal.state.submitting"
35611
+ on-click="newAppModal.submit()"
35612
+ ></submit-button>
35613
+ </div>
35614
+ </form>
35615
+ </div>
35616
+ `);
35617
+ }]);
35618
+
35619
+ function anyFieldFilter() {
35620
+ return function(items, props) {
35621
+ let out = [];
35622
+ if (Array.isArray(items)) {
35623
+ items.forEach(function(item) {
35624
+ let itemMatches = false;
35625
+ const keys = Object.keys(props);
35626
+ for (const prop of keys) {
35627
+ const text = props[prop].toLowerCase();
35628
+ if (item[prop] && item[prop].toString().toLowerCase().includes(text)) {
35629
+ itemMatches = true;
35630
+ break;
35631
+ }
35632
+ }
35633
+ if (itemMatches) {
35634
+ out.push(item);
35635
+ }
35636
+ });
35637
+ } else {
35638
+ out = items;
35639
+ }
35640
+ return out;
35641
+ };
35642
+ }
35643
+ const ANY_FIELD_FILTER = "spinnaker.core.presentation.anyFieldFilter";
35644
+ module(ANY_FIELD_FILTER, []).filter("anyFieldFilter", anyFieldFilter);
35645
+
35646
+ const Projects = () => {
35647
+ const cache = useRef$4(ViewStateCache.get("projects") || ViewStateCache.createCache("projects", { version: 1 })).current;
35648
+ const cached = cache.get("#global") || { projectFilter: "", sort: "name" };
35649
+ const [projects, setProjects] = useState$b([]);
35650
+ const [loaded, setLoaded] = useState$b(false);
35651
+ const [projectFilter, setProjectFilter] = useState$b(cached.projectFilter);
35652
+ const [sortKey, setSortKey] = useState$b(cached.sort);
35653
+ const [currentPage, setCurrentPage] = useState$b(1);
35654
+ const inputRef = useRef$4();
35655
+ useEffect$a(() => {
35656
+ cache.put("#global", { projectFilter, sort: sortKey });
35657
+ }, [projectFilter, sortKey, cache]);
35658
+ useEffect$a(() => {
35659
+ ProjectReader.listProjects().then((result) => {
35660
+ setProjects(result);
35661
+ setLoaded(true);
35662
+ });
35663
+ }, []);
35664
+ useEffect$a(() => {
35665
+ var _a;
35666
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
35667
+ }, []);
35668
+ useEffect$a(() => {
35669
+ setCurrentPage(1);
35670
+ }, [projectFilter, sortKey]);
35671
+ const filteredProjects = useMemo$2(() => {
35672
+ const filterFn = anyFieldFilter();
35673
+ const filtered = filterFn(projects, {
35674
+ name: projectFilter,
35675
+ email: projectFilter
35676
+ });
35677
+ const key = (sortKey == null ? void 0 : sortKey.startsWith("-")) ? sortKey.slice(1) : sortKey;
35678
+ const direction = (sortKey == null ? void 0 : sortKey.startsWith("-")) ? "desc" : "asc";
35679
+ return orderBy(filtered, [key], [direction]);
35680
+ }, [projects, projectFilter, sortKey]);
35681
+ const itemsPerPage = 12;
35682
+ const totalPages = Math.ceil(filteredProjects.length / itemsPerPage) || 1;
35683
+ const pageProjects = filteredProjects.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);
35684
+ const changePage = (page) => setCurrentPage(Number(page));
35685
+ const Loading = () => /* @__PURE__ */ React__default.createElement("div", {
35686
+ className: "horizontal center middle",
35687
+ style: { marginBottom: "250px", height: "100px" }
35688
+ }, /* @__PURE__ */ React__default.createElement(Spinner, {
35689
+ size: "small"
35690
+ }));
35691
+ return /* @__PURE__ */ React__default.createElement("div", {
35692
+ className: "infrastructure"
35693
+ }, /* @__PURE__ */ React__default.createElement("div", {
35694
+ className: "infrastructure-section search-header"
35695
+ }, /* @__PURE__ */ React__default.createElement("div", {
35696
+ className: "container"
35697
+ }, /* @__PURE__ */ React__default.createElement("h2", {
35698
+ className: "header-section"
35699
+ }, /* @__PURE__ */ React__default.createElement("span", {
35700
+ className: "search-label"
35701
+ }, "Projects"), /* @__PURE__ */ React__default.createElement("input", {
35702
+ type: "search",
35703
+ placeholder: "Search projects",
35704
+ className: "form-control input-md",
35705
+ ref: inputRef,
35706
+ value: projectFilter,
35707
+ onChange: (e) => setProjectFilter(e.target.value)
35708
+ })), /* @__PURE__ */ React__default.createElement("div", {
35709
+ className: "header-actions"
35710
+ }, /* @__PURE__ */ React__default.createElement(InsightMenu, {
35711
+ createApp: false,
35712
+ createProject: true,
35713
+ refreshCaches: false
35714
+ })))), /* @__PURE__ */ React__default.createElement("div", {
35715
+ className: "container"
35716
+ }, !loaded && /* @__PURE__ */ React__default.createElement(Loading, null), loaded && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("table", {
35717
+ className: "table table-hover"
35718
+ }, /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("th", {
35719
+ style: { width: "20%" }
35720
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
35721
+ currentSort: sortKey,
35722
+ onChange: setSortKey,
35723
+ label: "Name",
35724
+ sortKey: "name"
35725
+ })), /* @__PURE__ */ React__default.createElement("th", {
35726
+ style: { width: "20%" }
35727
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
35728
+ currentSort: sortKey,
35729
+ onChange: setSortKey,
35730
+ label: "Created",
35731
+ sortKey: "createTs"
35732
+ })), /* @__PURE__ */ React__default.createElement("th", {
35733
+ style: { width: "20%" }
35734
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
35735
+ currentSort: sortKey,
35736
+ onChange: setSortKey,
35737
+ label: "Updated",
35738
+ sortKey: "updateTs"
35739
+ })), /* @__PURE__ */ React__default.createElement("th", {
35740
+ style: { width: "25%" }
35741
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
35742
+ currentSort: sortKey,
35743
+ onChange: setSortKey,
35744
+ label: "Owner",
35745
+ sortKey: "email"
35746
+ })))), /* @__PURE__ */ React__default.createElement("tbody", null, pageProjects.map((project) => {
35747
+ const projectName = project.name.toLowerCase();
35748
+ return /* @__PURE__ */ React__default.createElement(UISref, {
35749
+ key: projectName,
35750
+ to: "home.project.dashboard",
35751
+ params: { project: projectName }
35752
+ }, /* @__PURE__ */ React__default.createElement("tr", {
35753
+ className: "clickable"
35754
+ }, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(UISref, {
35755
+ to: "home.project.dashboard",
35756
+ params: { project: projectName }
35757
+ }, /* @__PURE__ */ React__default.createElement("a", null, projectName))), /* @__PURE__ */ React__default.createElement("td", null, timestamp(project.createTs)), /* @__PURE__ */ React__default.createElement("td", null, timestamp(project.updateTs)), /* @__PURE__ */ React__default.createElement("td", null, project.email)));
35758
+ }))), /* @__PURE__ */ React__default.createElement(PaginationControls, {
35759
+ onPageChanged: changePage,
35760
+ activePage: currentPage,
35761
+ totalPages
35762
+ }))));
35763
+ };
35764
+
35765
+ class PubsubSubscriptionReader {
35766
+ static getPubsubSubscriptions() {
35767
+ return REST("/pubsub/subscriptions").get();
35768
+ }
35769
+ }
35770
+
35771
+ function RegionSelectInput(props) {
35772
+ const { account, readOnly, regions, ...otherProps } = props;
35773
+ if (!account) {
35774
+ return /* @__PURE__ */ React__default.createElement("div", null, "(Select an account)");
35775
+ } else if (readOnly) {
35776
+ return /* @__PURE__ */ React__default.createElement("p", {
35777
+ className: "form-control-static"
35778
+ }, props.value);
35779
+ }
35780
+ const allRegions = regions ? regions : [];
35781
+ const options = allRegions.map((region) => ({
35782
+ value: region.name,
35783
+ label: `${region.name}${region.deprecated ? " (deprecated in the '" + account + "' account)" : ""}`
35784
+ }));
35785
+ options.unshift({ label: "Select...", value: "", disabled: true });
35786
+ return /* @__PURE__ */ React__default.createElement(SelectInput, {
35787
+ ...otherProps,
35788
+ className: "form-control input-sm",
35789
+ options
35790
+ });
35791
+ }
35792
+
35793
+ class RegionSelectField extends React__default.Component {
35794
+ handleChange(event) {
35795
+ const { component, onChange, field } = this.props;
35796
+ component[field] = event.target.value;
35797
+ onChange(event.target.value);
35798
+ $rootScope.$apply();
35799
+ this.setState({});
35800
+ }
35801
+ render() {
35802
+ const { labelColumns, fieldColumns, account, regions, readOnly, component, field } = this.props;
35803
+ return /* @__PURE__ */ React__default.createElement("div", {
35804
+ className: "form-group"
35805
+ }, /* @__PURE__ */ React__default.createElement("div", {
35806
+ className: `col-md-${labelColumns} sm-label-right`
35807
+ }, "Region"), /* @__PURE__ */ React__default.createElement("div", {
35808
+ className: `col-md-${fieldColumns || 7}`
35809
+ }, /* @__PURE__ */ React__default.createElement(RegionSelectInput, {
35810
+ account,
35811
+ regions,
35812
+ readOnly,
35813
+ value: component[field],
35814
+ onChange: (evt) => this.handleChange(evt)
35815
+ })));
35816
+ }
35817
+ }
35818
+
35819
+ class RetryService {
35820
+ static buildRetrySequence(func, stopCondition, limit, interval) {
35821
+ const call = func();
35822
+ const promise = call.hasOwnProperty("then") ? call : $q.resolve(call);
35823
+ if (limit === 0) {
35824
+ return promise;
35825
+ } else {
35826
+ return promise.then((result) => {
35827
+ if (stopCondition(result)) {
35828
+ return result;
35829
+ } else {
35830
+ return $timeout(interval).then(() => this.buildRetrySequence(func, stopCondition, limit - 1, interval));
35831
+ }
35832
+ }).catch(() => $timeout(interval).then(() => this.buildRetrySequence(func, stopCondition, limit - 1, interval)));
35833
+ }
35834
+ }
35835
+ }
35836
+
35837
+ const ItemDetails = ({ item, transformName }) => /* @__PURE__ */ React.createElement("div", {
35838
+ className: "flex-container-h"
35839
+ }, /* @__PURE__ */ React.createElement("div", {
35840
+ className: "flex-grow"
35841
+ }, /* @__PURE__ */ React.createElement("span", {
35842
+ className: "small"
35843
+ }, /* @__PURE__ */ React.createElement(StatusGlyph, {
35844
+ item
35845
+ })), transformName ? robotToHuman(item.name) : item.name), /* @__PURE__ */ React.createElement("div", {
35846
+ className: "flex-pull-right"
35847
+ }, duration(item.runningTimeInMs)));
35848
+ const RunningTasksPopoverContent = ({ executions, tasks }) => {
35849
+ const sortedTasks = orderBy(tasks || [], ["startTime"], ["asc"]);
35850
+ return /* @__PURE__ */ React.createElement("div", {
35851
+ className: "RunningTasksPopoverContent"
35852
+ }, /* @__PURE__ */ React.createElement("div", null, sortedTasks.map((task, index) => /* @__PURE__ */ React.createElement("div", {
35853
+ key: `task-${index}`
35854
+ }, /* @__PURE__ */ React.createElement("strong", null, task.name), displayableTasks(task.steps).map((step, i) => /* @__PURE__ */ React.createElement(ItemDetails, {
35855
+ key: `task-step-${i}`,
35856
+ item: step,
35857
+ transformName: true
35858
+ }))))), /* @__PURE__ */ React.createElement("div", null, executions.map((execution, index) => /* @__PURE__ */ React.createElement("div", {
35859
+ key: `execution-${index}`
35860
+ }, /* @__PURE__ */ React.createElement("strong", null, " Pipeline: ", execution.name, " "), (execution.stages || []).map((stage, i) => /* @__PURE__ */ React.createElement(ItemDetails, {
35861
+ key: `execution-stage-${i}`,
35862
+ item: stage
35863
+ }))))));
35864
+ };
35865
+
35866
+ const RunningTasksTag = ({ executions, tasks }) => {
35867
+ const runningExecutions = (executions || []).filter((e) => e.isRunning || e.hasNotStarted);
35868
+ const PopoverContent = React.useCallback(() => /* @__PURE__ */ React.createElement(RunningTasksPopoverContent, {
35869
+ executions: runningExecutions,
35870
+ tasks
35871
+ }), [tasks, runningExecutions]);
35872
+ if (!(tasks == null ? void 0 : tasks.length) && !runningExecutions.length) {
35873
+ return null;
35874
+ }
35875
+ return /* @__PURE__ */ React.createElement("span", {
35876
+ className: "RunningTasksTag"
35877
+ }, /* @__PURE__ */ React.createElement(HoverablePopover, {
35878
+ Component: PopoverContent,
35879
+ className: "menu-running-tasks"
35880
+ }, /* @__PURE__ */ React.createElement("span", {
35881
+ className: "icon"
35882
+ }, /* @__PURE__ */ React.createElement("span", {
35883
+ className: "glyphicon icon-spinner fa-spin-slow"
35884
+ }))));
35885
+ };
35886
+
35887
+ var __defProp$g = Object.defineProperty;
35888
+ var __getOwnPropDesc$g = Object.getOwnPropertyDescriptor;
35889
+ var __decorateClass$g = (decorators, target, key, kind) => {
35890
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$g(target, key) : target;
35891
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
35892
+ if (decorator = decorators[i])
35893
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
35894
+ if (kind && result)
35895
+ __defProp$g(target, key, result);
35896
+ return result;
35897
+ };
35898
+ class LoadBalancers$2 extends React__default.Component {
35899
+ render() {
35900
+ const { application, serverGroup } = this.props;
35901
+ const hasLoadBalancer = !!get(serverGroup, "loadBalancers.length") || !!get(serverGroup, "targetGroups.length");
35902
+ return hasLoadBalancer && /* @__PURE__ */ React__default.createElement(LoadBalancersTagWrapper, {
35903
+ key: "lbwrapper",
35904
+ application,
35905
+ serverGroup
35906
+ });
35907
+ }
35908
+ }
35909
+ class MultiSelectCheckbox extends React__default.Component {
35910
+ render() {
35911
+ const {
35912
+ isMultiSelected,
35913
+ sortFilter: { multiselect }
35914
+ } = this.props;
35915
+ return multiselect && /* @__PURE__ */ React__default.createElement("input", {
35916
+ type: "checkbox",
35917
+ checked: isMultiSelected
35918
+ });
35919
+ }
35920
+ }
35921
+ class CloudProviderIcon extends React__default.Component {
35922
+ render() {
35923
+ const { serverGroup } = this.props;
35924
+ return /* @__PURE__ */ React__default.createElement(CloudProviderLogo, {
35925
+ provider: serverGroup.type,
35926
+ height: "16px",
35927
+ width: "16px"
35928
+ });
35929
+ }
35930
+ }
35931
+ class ImageList extends React__default.Component {
35932
+ toggle() {
35933
+ this.setState((previousState) => {
35934
+ return { collapsed: !previousState.collapsed };
35935
+ });
35936
+ }
35937
+ constructor(props) {
35938
+ super(props);
35939
+ this.state = {
35940
+ collapsed: true
35941
+ };
35942
+ this.toggle = this.toggle.bind(this);
35943
+ }
35944
+ render() {
35945
+ const images = this.props.images.sort();
35946
+ const { collapsed } = this.state;
35947
+ const buttonStyle = {
35948
+ padding: 0,
35949
+ fontSize: "13px"
35950
+ };
35951
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, collapsed && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("span", null, images[0]), "\xA0", images.length > 1 && /* @__PURE__ */ React__default.createElement("button", {
35952
+ className: "link",
35953
+ onClick: this.toggle,
35954
+ style: buttonStyle
35955
+ }, "(+ ", images.length - 1, " more)")), !collapsed && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, images.map((image, index) => /* @__PURE__ */ React__default.createElement("span", {
35956
+ key: image
35957
+ }, index > 0 && /* @__PURE__ */ React__default.createElement("br", null), image, index < images.length - 1 ? "," : "")), /* @__PURE__ */ React__default.createElement("br", null), /* @__PURE__ */ React__default.createElement("button", {
35958
+ className: "link",
35959
+ onClick: this.toggle,
35960
+ style: buttonStyle
35961
+ }, "collapse")));
35962
+ }
35963
+ }
35964
+ class SequenceAndBuildAndImages extends React__default.Component {
35965
+ render() {
35966
+ const { serverGroup, jenkins, images, docker } = this.props;
35967
+ const serverGroupSequence = NameUtils.getSequence(serverGroup.moniker.sequence);
35968
+ const ciBuild = serverGroup.buildInfo && serverGroup.buildInfo.ciBuild;
35969
+ const appArtifact = serverGroup.buildInfo && serverGroup.buildInfo.appArtifact;
35970
+ return /* @__PURE__ */ React__default.createElement("div", null, !!serverGroupSequence && /* @__PURE__ */ React__default.createElement("span", {
35971
+ className: "server-group-sequence"
35972
+ }, " ", serverGroupSequence), !!serverGroupSequence && (!!jenkins || !!images) && /* @__PURE__ */ React__default.createElement("span", null, ": "), !!jenkins && /* @__PURE__ */ React__default.createElement("a", {
35973
+ className: "build-link sp-margin-xs-right",
35974
+ href: jenkins.href,
35975
+ target: "_blank"
35976
+ }, "Build: #", jenkins.number), !!docker && /* @__PURE__ */ React__default.createElement("a", {
35977
+ className: "build-link",
35978
+ href: docker.href,
35979
+ target: "_blank"
35980
+ }, docker.image, ":", docker.tag || docker.digest), !!appArtifact && !!appArtifact.version ? /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "\xA0\xA0\xA0\xA0", /* @__PURE__ */ React__default.createElement("img", {
35981
+ className: "artifact-icon",
35982
+ src: ArtifactIconService.getPath("maven/file"),
35983
+ width: "18",
35984
+ height: "18"
35985
+ }), !!appArtifact.url ? /* @__PURE__ */ React__default.createElement("a", {
35986
+ className: "build-link",
35987
+ href: appArtifact.url,
35988
+ target: "_blank"
35989
+ }, appArtifact.version) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, appArtifact.version)) : !!ciBuild && !!ciBuild.jobNumber && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "\xA0\xA0\xA0\xA0", /* @__PURE__ */ React__default.createElement("img", {
35990
+ className: "artifact-icon",
35991
+ src: ArtifactIconService.getPath("jenkins/file"),
35992
+ width: "18",
35993
+ height: "18"
35994
+ }), !!ciBuild.jobUrl ? /* @__PURE__ */ React__default.createElement("a", {
35995
+ className: "build-link",
35996
+ href: ciBuild.jobUrl,
35997
+ target: "_blank"
35998
+ }, ciBuild.jobNumber) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, ciBuild.jobNumber)), !!images && /* @__PURE__ */ React__default.createElement(ImageList, {
35999
+ ...this.props
36000
+ }));
36001
+ }
36002
+ }
36003
+ class Alerts extends React__default.Component {
36004
+ render() {
36005
+ const { application, serverGroup } = this.props;
36006
+ return /* @__PURE__ */ React__default.createElement(EntityNotifications, {
36007
+ application,
36008
+ entity: serverGroup,
36009
+ entityType: "serverGroup",
36010
+ hOffsetPercent: "20%",
36011
+ onUpdate: () => application.serverGroups.refresh(),
36012
+ pageLocation: "pod",
36013
+ placement: "top"
36014
+ });
36015
+ }
36016
+ }
36017
+ let Health = class extends React__default.Component {
36018
+ render() {
36019
+ const { serverGroup } = this.props;
36020
+ return /* @__PURE__ */ React__default.createElement(HealthCounts, {
36021
+ container: serverGroup.instanceCounts
36022
+ });
36023
+ }
36024
+ };
36025
+ Health = __decorateClass$g([
36026
+ Overridable("serverGroups.pod.header.health")
36027
+ ], Health);
36028
+ class RunningTasks$1 extends React__default.Component {
36029
+ render() {
36030
+ const { serverGroup } = this.props;
36031
+ const hasRunningExecutions = !!serverGroup.runningExecutions.length || !!serverGroup.runningTasks.length;
36032
+ return hasRunningExecutions && /* @__PURE__ */ React__default.createElement(RunningTasksTag, {
36033
+ tasks: serverGroup.runningTasks,
36034
+ executions: serverGroup.runningExecutions
36035
+ });
36036
+ }
36037
+ }
36038
+ let ServerGroupHeader = class extends React__default.Component {
36039
+ render() {
36040
+ const props = this.props;
36041
+ return /* @__PURE__ */ React__default.createElement("div", {
36042
+ className: "horizontal top server-group-title sticky-header-3"
36043
+ }, /* @__PURE__ */ React__default.createElement("div", {
36044
+ className: "horizontal section-title flex-1"
36045
+ }, /* @__PURE__ */ React__default.createElement(MultiSelectCheckbox, {
35253
36046
  ...props
35254
36047
  }), /* @__PURE__ */ React__default.createElement(CloudProviderIcon, {
35255
36048
  ...props
@@ -35268,7 +36061,7 @@ let ServerGroupHeader = class extends React__default.Component {
35268
36061
  })));
35269
36062
  }
35270
36063
  };
35271
- ServerGroupHeader = __decorateClass$h([
36064
+ ServerGroupHeader = __decorateClass$g([
35272
36065
  Overridable("serverGroups.pod.header")
35273
36066
  ], ServerGroupHeader);
35274
36067
 
@@ -36124,15 +36917,15 @@ const ServerGroupNamePreview = ({
36124
36917
  }, "Go to details for ", latestServerGroupName)))))));
36125
36918
  };
36126
36919
 
36127
- var __defProp$g = Object.defineProperty;
36128
- var __getOwnPropDesc$g = Object.getOwnPropertyDescriptor;
36129
- var __decorateClass$g = (decorators, target, key, kind) => {
36130
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$g(target, key) : target;
36920
+ var __defProp$f = Object.defineProperty;
36921
+ var __getOwnPropDesc$f = Object.getOwnPropertyDescriptor;
36922
+ var __decorateClass$f = (decorators, target, key, kind) => {
36923
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$f(target, key) : target;
36131
36924
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
36132
36925
  if (decorator = decorators[i])
36133
36926
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
36134
36927
  if (kind && result)
36135
- __defProp$g(target, key, result);
36928
+ __defProp$f(target, key, result);
36136
36929
  return result;
36137
36930
  };
36138
36931
  let ServerGroupDetailsField = class extends React__default.Component {
@@ -36167,7 +36960,7 @@ let ServerGroupDetailsField = class extends React__default.Component {
36167
36960
  }, /* @__PURE__ */ React__default.createElement("span", null, errors.freeFormDetails))));
36168
36961
  }
36169
36962
  };
36170
- ServerGroupDetailsField = __decorateClass$g([
36963
+ ServerGroupDetailsField = __decorateClass$f([
36171
36964
  Overridable("serverGroup.configure.detailsField")
36172
36965
  ], ServerGroupDetailsField);
36173
36966
 
@@ -36311,7 +37104,7 @@ class ServerGroupDetails extends React__default.Component {
36311
37104
  width: "36px"
36312
37105
  }), /* @__PURE__ */ React__default.createElement("h3", {
36313
37106
  className: "horizontal middle space-between flex-1"
36314
- }, serverGroup.name, showEntityTags && /* @__PURE__ */ React__default.createElement(EntityNotifications, {
37107
+ }, serverGroup.displayName ? serverGroup.displayName : serverGroup.name, showEntityTags && /* @__PURE__ */ React__default.createElement(EntityNotifications, {
36315
37108
  entity: serverGroup,
36316
37109
  application: app,
36317
37110
  placement: "bottom",
@@ -36817,15 +37610,15 @@ module(SERVER_GROUP_MANAGER_DATA_SOURCE, []).run([
36817
37610
  }
36818
37611
  ]);
36819
37612
 
36820
- var __defProp$f = Object.defineProperty;
36821
- var __getOwnPropDesc$f = Object.getOwnPropertyDescriptor;
36822
- var __decorateClass$f = (decorators, target, key, kind) => {
36823
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$f(target, key) : target;
37613
+ var __defProp$e = Object.defineProperty;
37614
+ var __getOwnPropDesc$e = Object.getOwnPropertyDescriptor;
37615
+ var __decorateClass$e = (decorators, target, key, kind) => {
37616
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$e(target, key) : target;
36824
37617
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
36825
37618
  if (decorator = decorators[i])
36826
37619
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
36827
37620
  if (kind && result)
36828
- __defProp$f(target, key, result);
37621
+ __defProp$e(target, key, result);
36829
37622
  return result;
36830
37623
  };
36831
37624
  let ServerGroupManagerDetails = class extends React__default.Component {
@@ -36833,7 +37626,7 @@ let ServerGroupManagerDetails = class extends React__default.Component {
36833
37626
  return /* @__PURE__ */ React__default.createElement("h3", null, "Server Group Manager Details");
36834
37627
  }
36835
37628
  };
36836
- ServerGroupManagerDetails = __decorateClass$f([
37629
+ ServerGroupManagerDetails = __decorateClass$e([
36837
37630
  Overridable("serverGroupManager.details")
36838
37631
  ], ServerGroupManagerDetails);
36839
37632
 
@@ -36843,7 +37636,7 @@ module(SERVER_GROUP_MANAGER_STATES, [APPLICATION_STATE_PROVIDER]).config([
36843
37636
  (applicationStateProvider) => {
36844
37637
  const serverGroupManagerDetails = {
36845
37638
  name: "serverGroupManager",
36846
- url: "/serverGroupManagerDetails/:provider/:accountId/:region/:serverGroupManager",
37639
+ url: "/serverGroupManagerDetails/:provider/:accountId/:region/:name",
36847
37640
  views: {
36848
37641
  "detail@../insight": {
36849
37642
  component: ServerGroupManagerDetails,
@@ -36857,7 +37650,7 @@ module(SERVER_GROUP_MANAGER_STATES, [APPLICATION_STATE_PROVIDER]).config([
36857
37650
  data: {
36858
37651
  pageTitleDetails: {
36859
37652
  title: "Server Group Manager Details",
36860
- nameParam: "serverGroupManager",
37653
+ nameParam: "name",
36861
37654
  accountParam: "accountId",
36862
37655
  regionParam: "region"
36863
37656
  },
@@ -36908,7 +37701,7 @@ class ServerGroupManagerTag extends React__default.Component {
36908
37701
  accountId: serverGroupManager.account,
36909
37702
  region: serverGroupManager.region,
36910
37703
  provider: serverGroupManager.cloudProvider,
36911
- serverGroupManager: serverGroupManager.name
37704
+ name: serverGroupManager.name
36912
37705
  };
36913
37706
  }
36914
37707
  }
@@ -37203,870 +37996,454 @@ styleInject(css_248z$12);
37203
37996
  class CustomBanner extends React__default.Component {
37204
37997
  constructor() {
37205
37998
  super(...arguments);
37206
- this.state = {
37207
- applicationName: null,
37208
- bannerConfig: null
37209
- };
37210
- }
37211
- componentDidMount() {
37212
- this.locationChangeUnsubscribe = ReactInjector.$uiRouter.transitionService.onSuccess({}, () => this.updateApplication());
37213
- }
37214
- updateApplication() {
37215
- const applicationName = get(ReactInjector, "$stateParams.application");
37216
- if (applicationName !== this.state.applicationName) {
37217
- this.setState({
37218
- applicationName,
37219
- bannerConfig: null
37220
- });
37221
- if (applicationName) {
37222
- ApplicationReader.getApplicationAttributes(applicationName).then((attributes) => {
37223
- this.updateBannerConfig(attributes);
37224
- }).catch(noop);
37225
- }
37226
- }
37227
- }
37228
- updateBannerConfig(attributes) {
37229
- const bannerConfigs = get(attributes, "customBanners") || [];
37230
- const bannerConfig = bannerConfigs.find((config) => config.enabled) || null;
37231
- this.setState({
37232
- bannerConfig
37233
- });
37234
- }
37235
- render() {
37236
- const { bannerConfig } = this.state;
37237
- if (bannerConfig == null) {
37238
- return null;
37239
- }
37240
- return /* @__PURE__ */ React__default.createElement("div", {
37241
- className: "custom-banner",
37242
- style: {
37243
- background: bannerConfig.backgroundColor,
37244
- color: bannerConfig.textColor
37245
- }
37246
- }, /* @__PURE__ */ React__default.createElement(Markdown, {
37247
- message: bannerConfig.text
37248
- }));
37249
- }
37250
- componentWillUnmount() {
37251
- this.locationChangeUnsubscribe();
37252
- }
37253
- }
37254
-
37255
- var css_248z$11 = ".Toastify__toast-container .Toastify__toast {\n color: var(--color-text-primary);\n}\n.Toastify__toast-container .Toastify__toast-body {\n overflow: hidden;\n overflow-wrap: break-word;\n}\n.Toastify__toast-container .Toastify__toast--info {\n background-color: var(--color-status-info-light);\n}\n.Toastify__toast-container .Toastify__toast--info .Toastify__close-button {\n color: var(--color-dovegray);\n}\n.Toastify__toast-container .Toastify__toast--warning {\n background-color: var(--color-status-warning-light);\n}\n.Toastify__toast-container .Toastify__toast--warning .Toastify__close-button {\n color: var(--color-dovegray);\n}\n.Toastify__toast-container .Toastify__toast--error {\n color: var(--color-white);\n}\n";
37256
- styleInject(css_248z$11);
37257
-
37258
- const Notifier = () => {
37259
- return /* @__PURE__ */ React__default.createElement(ToastContainer, {
37260
- position: "bottom-right",
37261
- autoClose: false,
37262
- newestOnTop: true,
37263
- closeOnClick: false
37264
- });
37265
- };
37266
-
37267
- const SpinnakerContainer = ({ authenticating, routing }) => /* @__PURE__ */ React.createElement(SpinErrorBoundary, {
37268
- category: "SpinnakerContainer"
37269
- }, /* @__PURE__ */ React.createElement(RecoilRoot, null, /* @__PURE__ */ React.createElement("div", {
37270
- className: "spinnaker-container grid-container"
37271
- }, !authenticating && routing && /* @__PURE__ */ React.createElement("div", {
37272
- className: "transition-overlay"
37273
- }, /* @__PURE__ */ React.createElement(Spinner, {
37274
- size: "medium"
37275
- })), /* @__PURE__ */ React.createElement("div", {
37276
- className: "navbar-inverse grid-header"
37277
- }, /* @__PURE__ */ React.createElement(CustomBanner, null), /* @__PURE__ */ React.createElement(UIRouterContextComponent, null, /* @__PURE__ */ React.createElement(SpinnakerHeader, null))), /* @__PURE__ */ React.createElement("div", {
37278
- className: "spinnaker-content grid-contents"
37279
- }, !authenticating && /* @__PURE__ */ React.createElement(UIView, {
37280
- name: "main"
37281
- }))), /* @__PURE__ */ React.createElement(Notifier, null)));
37282
-
37283
- const SPINNAKER_CONTAINER_COMPONENT = "spinnaker.core.container.component";
37284
- module(SPINNAKER_CONTAINER_COMPONENT, []).component("spinnakerContainer", react2angular(withErrorBoundary(SpinnakerContainer, "spinnakerContainer"), ["authenticating", "routing"]));
37285
-
37286
- const APPLICATION_BOOTSTRAP_MODULE = "spinnaker.core.applicationBootstrap";
37287
- const bootstrapModule = module(APPLICATION_BOOTSTRAP_MODULE, [
37288
- OVERRIDE_REGISTRY,
37289
- SPINNAKER_CONTAINER_COMPONENT
37290
- ]);
37291
-
37292
- const paramChangedHelper = (paramName, changedHandler) => {
37293
- return (transition) => {
37294
- const previousValue = transition.params("from")[paramName];
37295
- const newValue = transition.params("to")[paramName];
37296
- if (previousValue === newValue) {
37297
- return null;
37298
- }
37299
- return changedHandler(newValue, previousValue);
37300
- };
37301
- };
37302
-
37303
- bootstrapModule.config([
37304
- "$logProvider",
37305
- ($logProvider) => {
37306
- $logProvider.debugEnabled(SETTINGS.debugEnabled);
37307
- }
37308
- ]);
37309
- bootstrapModule.config([
37310
- "$httpProvider",
37311
- ($httpProvider) => {
37312
- $httpProvider.defaults.headers.patch = {
37313
- "Content-Type": "application/json;charset=utf-8"
37314
- };
37315
- }
37316
- ]);
37317
- bootstrapModule.config([
37318
- "$compileProvider",
37319
- ($compileProvider) => {
37320
- $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|slack|ssh):/);
37321
- }
37322
- ]);
37323
- bootstrapModule.config([
37324
- "$locationProvider",
37325
- ($locationProvider) => {
37326
- $locationProvider.hashPrefix("");
37327
- $locationProvider.html5Mode({
37328
- enabled: SETTINGS.feature.html5Routing,
37329
- rewriteLinks: false,
37330
- requireBase: false
37331
- });
37332
- }
37333
- ]);
37334
-
37335
- bootstrapModule.run([
37336
- "$rootScope",
37337
- "$state",
37338
- ($rootScope, $state) => {
37339
- $rootScope.feature = SETTINGS.feature;
37340
- $rootScope.$state = $state;
37341
- }
37342
- ]);
37343
- bootstrapModule.run([
37344
- "cacheInitializer",
37345
- (cacheInitializer) => {
37346
- cacheInitializer.initialize();
37347
- }
37348
- ]);
37349
-
37350
- const template$1 = `
37351
- <spinnaker-container authenticating="$ctrl.authenticating" routing="$ctrl.routing"></spinnaker-container>
37352
- `;
37353
- class SpinnakerController {
37354
- constructor($rootScope) {
37355
- this.feature = SETTINGS.feature;
37356
- this.authenticating = $rootScope.authenticating;
37357
- this.routing = $rootScope.routing;
37358
- }
37359
- }
37360
- SpinnakerController.$inject = ["$rootScope"];
37361
- bootstrapModule.component("spinnaker", {
37362
- template: template$1,
37363
- controller: SpinnakerController
37364
- });
37365
-
37366
- bootstrapModule.run([
37367
- "$uiRouter",
37368
- "$log",
37369
- ($uiRouter, $log) => {
37370
- const subscription = $uiRouter.globals.start$.subscribe((transition) => {
37371
- const details = {
37372
- transition,
37373
- toState: transition.to(),
37374
- toParams: transition.params("to"),
37375
- fromState: transition.from(),
37376
- fromParams: transition.params("from")
37377
- };
37378
- $log.debug("$stateChangeStart", details);
37379
- const success = () => $log.debug("$stateChangeSuccess", details);
37380
- const failure = (error) => $log.debug("$stateChangeError", { ...details, error });
37381
- transition.promise.then(success, failure);
37382
- });
37383
- $uiRouter.disposable({ dispose: () => subscription.unsubscribe() });
37384
- }
37385
- ]);
37386
-
37387
- bootstrapModule.run([
37388
- "$uiRouter",
37389
- ($uiRouter) => {
37390
- const changeTraceSetting = (newValue) => {
37391
- const trace = $uiRouter.trace;
37392
- trace.disable();
37393
- if (typeof newValue === "string") {
37394
- if (newValue.toUpperCase() === "TRUE") {
37395
- trace.enable(Category.TRANSITION);
37396
- } else if (newValue.toUpperCase() === "ALL") {
37397
- trace.enable();
37398
- } else {
37399
- const traceValues = newValue.split(",").map((str) => str.trim().toUpperCase());
37400
- trace.enable(...traceValues);
37401
- }
37402
- }
37403
- };
37404
- $uiRouter.transitionService.onBefore({}, paramChangedHelper("trace", changeTraceSetting));
37405
- }
37406
- ]);
37407
-
37408
- bootstrapModule.config([
37409
- "$uibTooltipProvider",
37410
- ($uibTooltipProvider) => {
37411
- $uibTooltipProvider.options({
37412
- appendToBody: true
37413
- });
37414
- $uibTooltipProvider.setTriggers({
37415
- "mouseenter focus": "mouseleave blur"
37416
- });
37417
- }
37418
- ]);
37419
- bootstrapModule.config([
37420
- "$uibModalProvider",
37421
- ($uibModalProvider) => {
37422
- $uibModalProvider.options.backdrop = "static";
37423
- $uibModalProvider.options.keyboard = false;
37424
- }
37425
- ]);
37426
-
37427
- bootstrapModule.config([
37428
- "$uiRouterProvider",
37429
- ($uiRouterProvider) => {
37430
- $uiRouterProvider.plugin(UIRouterRxPlugin);
37431
- }
37432
- ]);
37433
-
37434
- bootstrapModule.run([
37435
- "$uiRouter",
37436
- ($uiRouter) => {
37437
- let visualizerEnabled = "false";
37438
- let VisualizerPlugin = null;
37439
- function loadVisualizer() {
37440
- const collapseGlobs = ["home.*", "home.*.application.*", "home.*.application.insight.*"].map((globStr) => new Glob(globStr));
37441
- const collapsedStates = $uiRouter.stateRegistry.get().filter((state) => collapseGlobs.some((glob) => glob.matches(state.name)));
37442
- collapsedStates.forEach((state) => state.$$state()._collapsed = true);
37443
- return import('@uirouter/visualizer').then((vis) => VisualizerPlugin = vis.Visualizer).then(createVisualizer);
37444
- }
37445
- function createVisualizer() {
37446
- if (visualizerEnabled !== "true") {
37447
- return;
37448
- }
37449
- destroyVisualizer();
37450
- if (VisualizerPlugin) {
37451
- $uiRouter.plugin(VisualizerPlugin);
37452
- } else {
37453
- loadVisualizer();
37454
- }
37455
- }
37456
- function destroyVisualizer() {
37457
- const plugin = $uiRouter.getPlugin("visualizer");
37458
- plugin && $uiRouter.dispose(plugin);
37459
- }
37460
- function toggleVisualizer(trans) {
37461
- const enabled = trans.paramsChanged().vis;
37462
- if (enabled === void 0) {
37463
- return null;
37464
- }
37465
- if (enabled === visualizerEnabled) {
37466
- return trans.targetState().withParams({ vis: void 0 });
37467
- }
37468
- visualizerEnabled = enabled;
37469
- if (enabled === "true") {
37470
- createVisualizer();
37471
- } else if (enabled === "false") {
37472
- destroyVisualizer();
37473
- }
37474
- return trans.targetState().withParams({ vis: void 0 });
37475
- }
37476
- window.vis = createVisualizer;
37477
- $uiRouter.transitionService.onStart({}, toggleVisualizer);
37478
- }
37479
- ]);
37480
-
37481
- uiSelectDecorator.$inject = ["$provide"];
37482
- function uiSelectDecorator($provide) {
37483
- $provide.decorator("uiSelectMultipleDirective", [
37484
- "$delegate",
37485
- "$timeout",
37486
- function($delegate, $timeout) {
37487
- const [uiSelect] = $delegate;
37488
- const originalLink = uiSelect.link;
37489
- const SELECT_EVENT_KEY = "uis:select";
37490
- uiSelect.link = function(scope, _element, _attrs, ctrls) {
37491
- originalLink.apply(this, arguments);
37492
- const [$select] = ctrls;
37493
- scope.$$listeners[SELECT_EVENT_KEY] = [];
37494
- scope.$on(SELECT_EVENT_KEY, function(event, item) {
37495
- if ($select.selected.length >= $select.limit) {
37496
- return;
37497
- }
37498
- if (!event.defaultPrevented) {
37499
- $select.selected.push(item);
37500
- const locals = {
37501
- [$select.parserResult.itemName]: item
37502
- };
37503
- $timeout(function() {
37504
- if ($select.onSelectCallback) {
37505
- $select.onSelectCallback(scope, {
37506
- $item: item,
37507
- $model: $select.parserResult.modelMapper(scope, locals)
37508
- });
37509
- }
37510
- });
37511
- scope.$selectMultiple.updateModel();
37512
- }
37513
- });
37514
- };
37515
- return $delegate;
37516
- }
37517
- ]);
37518
- $provide.decorator("uiSelectMinErr", [
37519
- "$delegate",
37520
- function($delegate) {
37521
- return function handledError() {
37522
- const original = $delegate;
37523
- if (arguments.length === 3) {
37524
- if (arguments[0] === "choices" && arguments[1] === `Expected multiple .ui-select-choices-row but got '{0}'.` && arguments[2] === 0) {
37525
- throw new Error("IGNORE", "IGNORE");
37526
- }
37527
- }
37528
- return original.apply(this, arguments);
37529
- };
37530
- }
37531
- ]);
37532
- $provide.decorator("$exceptionHandler", [
37533
- "$delegate",
37534
- function($delegate) {
37535
- return function(exception, cause) {
37536
- if (exception && exception.message === "IGNORE") {
37537
- return;
37538
- }
37539
- if (Array.isArray(exception) && exception.length && exception[0] instanceof Error) {
37540
- exception.forEach((e) => $delegate(e, cause));
37541
- } else {
37542
- $delegate(exception, cause);
37543
- }
37544
- };
37545
- }
37546
- ]);
37547
- }
37548
- bootstrapModule.config(uiSelectDecorator);
37549
- bootstrapModule.config([
37550
- "uiSelectConfig",
37551
- (uiSelectConfig) => {
37552
- uiSelectConfig.theme = "select2";
37553
- uiSelectConfig.appendToBody = true;
37554
- }
37555
- ]);
37556
-
37557
- class ApplicationSearchResultType extends SearchResultType {
37558
- constructor() {
37559
- super(...arguments);
37560
- this.id = "applications";
37561
- this.order = 1;
37562
- this.displayName = "Applications";
37563
- this.iconClass = "far fa-window-maximize";
37564
- this.cols = {
37565
- APPLICATION: { key: "application", label: "Name" },
37566
- ACCOUNT: { key: "accounts", label: "Account" },
37567
- EMAIL: { key: "email" }
37568
- };
37569
- this.TabComponent = DefaultSearchResultTab;
37570
- this.HeaderComponent = () => /* @__PURE__ */ React__default.createElement(SearchTableHeader, null, /* @__PURE__ */ React__default.createElement(HeaderCell, {
37571
- col: this.cols.APPLICATION
37572
- }), /* @__PURE__ */ React__default.createElement(HeaderCell, {
37573
- col: this.cols.ACCOUNT
37574
- }), /* @__PURE__ */ React__default.createElement(HeaderCell, {
37575
- col: this.cols.EMAIL
37576
- }));
37577
- this.DataComponent = ({ resultSet }) => {
37578
- const itemKeyFn = (item) => item.application;
37579
- const itemSortFn = (a, b) => a.application.localeCompare(b.application);
37580
- const results = resultSet.results.slice().sort(itemSortFn);
37581
- return /* @__PURE__ */ React__default.createElement(SearchTableBody, null, results.map((item) => /* @__PURE__ */ React__default.createElement(SearchTableRow, {
37582
- key: itemKeyFn(item)
37583
- }, /* @__PURE__ */ React__default.createElement(HrefCell, {
37584
- item,
37585
- col: this.cols.APPLICATION
37586
- }), /* @__PURE__ */ React__default.createElement(AccountCell, {
37587
- item,
37588
- col: this.cols.ACCOUNT
37589
- }), /* @__PURE__ */ React__default.createElement(BasicCell, {
37590
- item,
37591
- col: this.cols.EMAIL
37592
- }))));
37999
+ this.state = {
38000
+ applicationName: null,
38001
+ bannerConfig: null
37593
38002
  };
37594
38003
  }
37595
- displayFormatter(searchResult) {
37596
- return searchResult.application;
38004
+ componentDidMount() {
38005
+ this.locationChangeUnsubscribe = ReactInjector.$uiRouter.transitionService.onSuccess({}, () => this.updateApplication());
37597
38006
  }
37598
- }
37599
- searchResultTypeRegistry.register(new ApplicationSearchResultType());
37600
-
37601
- const ApplicationTable = ({ currentSort, toggleSort, applications }) => /* @__PURE__ */ React__default.createElement("table", {
37602
- className: "table table-hover"
37603
- }, /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("th", {
37604
- style: { width: "18%" }
37605
- }, /* @__PURE__ */ React__default.createElement(SortToggle, {
37606
- currentSort,
37607
- onChange: toggleSort,
37608
- label: "Name",
37609
- sortKey: "name"
37610
- })), /* @__PURE__ */ React__default.createElement("th", {
37611
- style: { width: "15%" }
37612
- }, /* @__PURE__ */ React__default.createElement(SortToggle, {
37613
- currentSort,
37614
- onChange: toggleSort,
37615
- label: "Created",
37616
- sortKey: "createTs"
37617
- })), /* @__PURE__ */ React__default.createElement("th", {
37618
- style: { width: "15%" }
37619
- }, /* @__PURE__ */ React__default.createElement(SortToggle, {
37620
- currentSort,
37621
- onChange: toggleSort,
37622
- label: "Updated",
37623
- sortKey: "updateTs"
37624
- })), /* @__PURE__ */ React__default.createElement("th", {
37625
- style: { width: "15%" }
37626
- }, /* @__PURE__ */ React__default.createElement(SortToggle, {
37627
- currentSort,
37628
- onChange: toggleSort,
37629
- label: "Owner",
37630
- sortKey: "email"
37631
- })), /* @__PURE__ */ React__default.createElement("th", null, /* @__PURE__ */ React__default.createElement(SortToggle, {
37632
- currentSort,
37633
- onChange: toggleSort,
37634
- label: "Account(s)",
37635
- sortKey: "accounts"
37636
- })), SETTINGS.feature.slack && /* @__PURE__ */ React__default.createElement("th", {
37637
- style: { width: "22%" }
37638
- }, "Slack Channel"), /* @__PURE__ */ React__default.createElement("th", {
37639
- style: { width: "22%" }
37640
- }, "Description"))), /* @__PURE__ */ React__default.createElement("tbody", null, applications.map((app) => {
37641
- var _a;
37642
- const appName = app.name.toLowerCase();
37643
- return /* @__PURE__ */ React__default.createElement(UISref, {
37644
- key: appName,
37645
- to: ".application",
37646
- params: { application: appName }
37647
- }, /* @__PURE__ */ React__default.createElement("tr", {
37648
- className: "clickable"
37649
- }, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(UISref, {
37650
- to: ".application",
37651
- params: { application: appName }
37652
- }, /* @__PURE__ */ React__default.createElement("a", null, appName))), /* @__PURE__ */ React__default.createElement("td", null, timestamp(app.createTs)), /* @__PURE__ */ React__default.createElement("td", null, timestamp(app.updateTs)), /* @__PURE__ */ React__default.createElement("td", null, app.email), /* @__PURE__ */ React__default.createElement("td", null, app.accounts), SETTINGS.feature.slack && /* @__PURE__ */ React__default.createElement("td", null, (_a = app.slackChannel) == null ? void 0 : _a.name), /* @__PURE__ */ React__default.createElement("td", null, app.description)));
37653
- })));
37654
-
37655
- const PaginationControls = ({ onPageChanged, activePage, totalPages }) => {
37656
- const Item = (props) => /* @__PURE__ */ React__default.createElement("li", {
37657
- className: `${props.isActive ? "active" : ""} ${props.disabled ? "disabled" : ""}`
37658
- }, /* @__PURE__ */ React__default.createElement("a", {
37659
- className: `${!props.disabled ? "clickable" : ""}`,
37660
- onClick: props.onClick
37661
- }, props.value));
37662
- const Paging = createUltimatePagination({
37663
- WrapperComponent: Pagination,
37664
- itemTypeToComponent: {
37665
- [ITEM_TYPES.PAGE]: ({ value, isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37666
- value,
37667
- isActive,
37668
- onClick
37669
- }),
37670
- [ITEM_TYPES.ELLIPSIS]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37671
- value: `\u2026`,
37672
- disabled: isActive,
37673
- onClick
37674
- }),
37675
- [ITEM_TYPES.FIRST_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37676
- value: `\xAB`,
37677
- disabled: isActive,
37678
- onClick
37679
- }),
37680
- [ITEM_TYPES.PREVIOUS_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37681
- value: `\u2039`,
37682
- disabled: isActive,
37683
- onClick
37684
- }),
37685
- [ITEM_TYPES.NEXT_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37686
- value: `\u203A`,
37687
- disabled: isActive,
37688
- onClick
37689
- }),
37690
- [ITEM_TYPES.LAST_PAGE_LINK]: ({ isActive, onClick }) => /* @__PURE__ */ React__default.createElement(Item, {
37691
- value: `\xBB`,
37692
- disabled: isActive,
37693
- onClick
37694
- })
37695
- }
37696
- });
37697
- return /* @__PURE__ */ React__default.createElement(Paging, {
37698
- onChange: onPageChanged,
37699
- currentPage: activePage,
37700
- totalPages
37701
- });
37702
- };
37703
-
37704
- var __defProp$e = Object.defineProperty;
37705
- var __getOwnPropDesc$e = Object.getOwnPropertyDescriptor;
37706
- var __decorateClass$e = (decorators, target, key, kind) => {
37707
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$e(target, key) : target;
37708
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
37709
- if (decorator = decorators[i])
37710
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
37711
- if (kind && result)
37712
- __defProp$e(target, key, result);
37713
- return result;
37714
- };
37715
- let InsightMenu = class extends React__default.Component {
37716
- constructor(props) {
37717
- super(props);
37718
- this.createProject = () => ConfigureProjectModal.show().then((result) => {
37719
- this.$state.go("home.project.dashboard", { project: result.name });
37720
- }).catch(() => {
37721
- });
37722
- this.createApplication = () => {
37723
- this.$uibModal.open({
37724
- scope: this.$rootScope.$new(),
37725
- templateUrl: this.overrideRegistry.getTemplate("createApplicationModal", "core/src/application/modal/newapplication.html"),
37726
- resolve: {
37727
- name: () => ""
37728
- },
37729
- controller: this.overrideRegistry.getController("CreateApplicationModalCtrl"),
37730
- controllerAs: "newAppModal"
37731
- }).result.then(this.routeToApplication).catch(() => {
38007
+ updateApplication() {
38008
+ const applicationName = get(ReactInjector, "$stateParams.application");
38009
+ if (applicationName !== this.state.applicationName) {
38010
+ this.setState({
38011
+ applicationName,
38012
+ bannerConfig: null
37732
38013
  });
37733
- };
37734
- this.routeToApplication = (app) => {
37735
- this.$state.go("home.applications.application", { application: app.name });
37736
- };
37737
- this.refreshAllCaches = () => {
37738
- if (this.state.refreshingCache) {
37739
- return;
38014
+ if (applicationName) {
38015
+ ApplicationReader.getApplicationAttributes(applicationName).then((attributes) => {
38016
+ this.updateBannerConfig(attributes);
38017
+ }).catch(noop);
37740
38018
  }
37741
- this.setState({ refreshingCache: true });
37742
- this.cacheInitializer.refreshCaches().then(() => {
37743
- this.setState({ refreshingCache: false });
37744
- });
37745
- };
37746
- this.state = {};
37747
- this.$state = ReactInjector.$state;
37748
- this.$uibModal = ModalInjector.modalService;
37749
- this.$rootScope = ReactInjector.$rootScope;
37750
- this.overrideRegistry = ReactInjector.overrideRegistry;
37751
- this.cacheInitializer = ReactInjector.cacheInitializer;
38019
+ }
38020
+ }
38021
+ updateBannerConfig(attributes) {
38022
+ const bannerConfigs = get(attributes, "customBanners") || [];
38023
+ const bannerConfig = bannerConfigs.find((config) => config.enabled) || null;
38024
+ this.setState({
38025
+ bannerConfig
38026
+ });
37752
38027
  }
37753
38028
  render() {
37754
- const { createApp, createProject, refreshCaches } = this.props;
37755
- const refreshMarkup = this.state.refreshingCache ? /* @__PURE__ */ React__default.createElement("span", null, /* @__PURE__ */ React__default.createElement("span", {
37756
- className: "fa fa-sync-alt fa-spin"
37757
- }), " Refreshing...") : /* @__PURE__ */ React__default.createElement("span", null, "Refresh all caches");
38029
+ const { bannerConfig } = this.state;
38030
+ if (bannerConfig == null) {
38031
+ return null;
38032
+ }
37758
38033
  return /* @__PURE__ */ React__default.createElement("div", {
37759
- id: "insight-menu"
37760
- }, createProject && /* @__PURE__ */ React__default.createElement(Button$1, {
37761
- bsStyle: createApp ? "default" : "primary",
37762
- href: "javascript:void(0)",
37763
- onClick: this.createProject,
37764
- style: { marginRight: createApp ? "5px" : "" }
37765
- }, "Create Project"), createApp && /* @__PURE__ */ React__default.createElement(Button$1, {
37766
- bsStyle: "primary",
37767
- href: "javascript:void(0)",
37768
- onClick: this.createApplication,
37769
- style: { marginRight: refreshCaches ? "5px" : "" }
37770
- }, "Create Application"), refreshCaches && /* @__PURE__ */ React__default.createElement(Button$1, {
37771
- href: "javascript:void(0)",
37772
- onClick: this.refreshAllCaches
37773
- }, refreshMarkup));
38034
+ className: "custom-banner",
38035
+ style: {
38036
+ background: bannerConfig.backgroundColor,
38037
+ color: bannerConfig.textColor
38038
+ }
38039
+ }, /* @__PURE__ */ React__default.createElement(Markdown, {
38040
+ message: bannerConfig.text
38041
+ }));
37774
38042
  }
37775
- };
37776
- InsightMenu.defaultProps = { createApp: true, createProject: true, refreshCaches: true };
37777
- InsightMenu = __decorateClass$e([
37778
- Overridable("createInsightMenu")
37779
- ], InsightMenu);
37780
- window.angular.module("ng").run(["$templateCache", function(templateCache) {
37781
- templateCache.put("core/src/application/modal/newapplication.html", `<div class="modal-page">
37782
- <modal-close dismiss="$dismiss()"></modal-close>
37783
- <div class="modal-header">
37784
- <h4 class="modal-title">New Application</h4>
37785
- </div>
37786
- <div ng-if="newAppModal.state.initializing" style="height: 200px">
37787
- <loading-spinner size="'medium'"></loading-spinner>
37788
- </div>
37789
- <div ng-if="newAppModal.state.initializeFailed" style="...">
37790
- <div
37791
- class="horizontal middle center heading-4"
37792
- style="padding-left: 15px; padding-right: 15px; margin-bottom: 250px; height: 150px"
37793
- >
37794
- <i class="fa fa-exclamation-triangle" style="padding-right: 8px"></i>
37795
- <span>
37796
- Error initializing dialog. Check that your gate endpoint is accessible. Further information on troubleshooting
37797
- this error is available <a href="https://www.spinnaker.io/setup/quickstart/faq/">here</a>.
37798
- </span>
37799
- </div>
37800
- </div>
37801
- <form
37802
- role="form"
37803
- class="container-fluid"
37804
- novalidate
37805
- name="newApplicationForm"
37806
- ng-if="!(newAppModal.state.initializing || newAppModal.state.initializeFailed)"
37807
- >
37808
- <div class="modal-body">
37809
- <div class="form-group row">
37810
- <div class="col-sm-3 sm-label-right">Name *</div>
37811
- <div class="col-sm-9">
37812
- <input
37813
- type="text"
37814
- autofocus
37815
- name="name"
37816
- class="form-control input-sm"
37817
- data-purpose="application-name"
37818
- ng-model="newAppModal.application.name"
37819
- placeholder="Enter an application name"
37820
- validate-unique="newAppModal.data.appNameList"
37821
- ng-model-options="{allowInvalid: true}"
37822
- validate-application-name
37823
- cloud-providers="newAppModal.application.cloudProviders"
37824
- required
37825
- />
37826
- </div>
37827
- </div>
37828
-
37829
- <application-name-validation-messages
37830
- name="newAppModal.application.name"
37831
- cloud-providers="newAppModal.application.cloudProviders"
37832
- ></application-name-validation-messages>
37833
-
37834
- <div class="form-group row slide-in" ng-if="newApplicationForm.name.$error.validateUnique">
37835
- <div class="col-sm-9 col-sm-offset-3 error-message">
37836
- <span>Application name must be unique.</span>
37837
- </div>
37838
- </div>
37839
-
37840
- <div class="form-group row">
37841
- <div class="col-sm-3 sm-label-right">Owner Email *</div>
37842
- <div class="col-sm-9">
37843
- <input
37844
- type="email"
37845
- name="email"
37846
- class="form-control input-sm"
37847
- data-purpose="application-email"
37848
- ng-model="newAppModal.application.email"
37849
- placeholder="Enter an email address"
37850
- required
37851
- />
37852
- </div>
37853
- </div>
37854
-
37855
- <div class="form-group row slide-in" ng-if="newApplicationForm.email.$dirty && newApplicationForm.email.$invalid">
37856
- <div class="col-sm-9 col-sm-offset-3 error-message">
37857
- <span>Please enter a valid email address</span>
37858
- </div>
37859
- </div>
38043
+ componentWillUnmount() {
38044
+ this.locationChangeUnsubscribe();
38045
+ }
38046
+ }
37860
38047
 
37861
- <div class="form-group row">
37862
- <div class="col-sm-3 sm-label-right">Repo Type</div>
37863
- <div class="col-sm-9">
37864
- <select
37865
- class="form-control input-sm"
37866
- ng-options="repoType for repoType in newAppModal.data.gitSources"
37867
- ng-model="newAppModal.application.repoType"
37868
- >
37869
- <option value="">Select Repo Type</option>
37870
- </select>
37871
- </div>
37872
- </div>
37873
- <div class="form-group row" ng-if="newAppModal.application.repoType">
37874
- <div class="col-sm-3 sm-label-right">Repo Project</div>
37875
- <div class="col-sm-9">
37876
- <input
37877
- type="text"
37878
- class="form-control input-sm"
37879
- ng-model="newAppModal.application.repoProjectKey"
37880
- placeholder="Enter your source repository project name"
37881
- />
37882
- </div>
37883
- </div>
37884
- <div class="form-group row" ng-if="newAppModal.application.repoType">
37885
- <div class="col-sm-3 sm-label-right">Repo Name</div>
37886
- <div class="col-sm-9">
37887
- <input
37888
- type="text"
37889
- class="form-control input-sm"
37890
- ng-model="newAppModal.application.repoSlug"
37891
- placeholder="Enter your source repository name (not the URL)"
37892
- pattern="^((?!://).)*$"
37893
- name="repoSlug"
37894
- />
37895
- </div>
37896
- </div>
38048
+ var css_248z$11 = ".Toastify__toast-container .Toastify__toast {\n color: var(--color-text-primary);\n}\n.Toastify__toast-container .Toastify__toast-body {\n overflow: hidden;\n overflow-wrap: break-word;\n}\n.Toastify__toast-container .Toastify__toast--info {\n background-color: var(--color-status-info-light);\n}\n.Toastify__toast-container .Toastify__toast--info .Toastify__close-button {\n color: var(--color-dovegray);\n}\n.Toastify__toast-container .Toastify__toast--warning {\n background-color: var(--color-status-warning-light);\n}\n.Toastify__toast-container .Toastify__toast--warning .Toastify__close-button {\n color: var(--color-dovegray);\n}\n.Toastify__toast-container .Toastify__toast--error {\n color: var(--color-white);\n}\n";
38049
+ styleInject(css_248z$11);
37897
38050
 
37898
- <div class="form-group row slide-in" ng-messages="newApplicationForm.repoSlug.$error">
37899
- <div class="col-sm-9 col-sm-offset-3 error-message" ng-message="pattern">
37900
- Enter your source repository name (not the URL).
37901
- </div>
37902
- </div>
38051
+ const Notifier = () => {
38052
+ return /* @__PURE__ */ React__default.createElement(ToastContainer, {
38053
+ position: "bottom-right",
38054
+ autoClose: false,
38055
+ newestOnTop: true,
38056
+ closeOnClick: false
38057
+ });
38058
+ };
37903
38059
 
37904
- <chaos-monkey-new-application-config
37905
- application-config="newAppModal.application"
37906
- ></chaos-monkey-new-application-config>
38060
+ const SpinnakerContainer = ({ authenticating, routing }) => /* @__PURE__ */ React.createElement(SpinErrorBoundary, {
38061
+ category: "SpinnakerContainer"
38062
+ }, /* @__PURE__ */ React.createElement(RecoilRoot, null, /* @__PURE__ */ React.createElement("div", {
38063
+ className: "spinnaker-container grid-container"
38064
+ }, !authenticating && routing && /* @__PURE__ */ React.createElement("div", {
38065
+ className: "transition-overlay"
38066
+ }, /* @__PURE__ */ React.createElement(Spinner, {
38067
+ size: "medium"
38068
+ })), /* @__PURE__ */ React.createElement("div", {
38069
+ className: "navbar-inverse grid-header"
38070
+ }, /* @__PURE__ */ React.createElement(CustomBanner, null), /* @__PURE__ */ React.createElement(UIRouterContextComponent, null, /* @__PURE__ */ React.createElement(SpinnakerHeader, null))), /* @__PURE__ */ React.createElement("div", {
38071
+ className: "spinnaker-content grid-contents"
38072
+ }, !authenticating && /* @__PURE__ */ React.createElement(UIView, {
38073
+ name: "main"
38074
+ }))), /* @__PURE__ */ React.createElement(Notifier, null)));
37907
38075
 
37908
- <render-if-feature feature="pagerDuty">
37909
- <pager-duty-select-field component="newAppModal.application"></pager-duty-select-field>
37910
- </render-if-feature>
38076
+ const SPINNAKER_CONTAINER_COMPONENT = "spinnaker.core.container.component";
38077
+ module(SPINNAKER_CONTAINER_COMPONENT, []).component("spinnakerContainer", react2angular(withErrorBoundary(SpinnakerContainer, "spinnakerContainer"), ["authenticating", "routing"]));
37911
38078
 
37912
- <render-if-feature feature="slack">
37913
- <slack-channel-selector
37914
- channel="newAppModal.application.slackChannel"
37915
- callback="newAppModal.setAttribute"
37916
- ></slack-channel-selector>
37917
- </render-if-feature>
38079
+ const APPLICATION_BOOTSTRAP_MODULE = "spinnaker.core.applicationBootstrap";
38080
+ const bootstrapModule = module(APPLICATION_BOOTSTRAP_MODULE, [
38081
+ OVERRIDE_REGISTRY,
38082
+ SPINNAKER_CONTAINER_COMPONENT
38083
+ ]);
37918
38084
 
37919
- <div class="form-group row">
37920
- <div class="col-sm-3 sm-label-right">Description</div>
37921
- <div class="col-sm-9">
37922
- <textarea
37923
- class="form-control input-sm"
37924
- ng-model="newAppModal.application.description"
37925
- placeholder="Enter a description"
37926
- data-purpose="application-description"
37927
- >
37928
- </textarea>
37929
- </div>
37930
- </div>
38085
+ const paramChangedHelper = (paramName, changedHandler) => {
38086
+ return (transition) => {
38087
+ const previousValue = transition.params("from")[paramName];
38088
+ const newValue = transition.params("to")[paramName];
38089
+ if (previousValue === newValue) {
38090
+ return null;
38091
+ }
38092
+ return changedHandler(newValue, previousValue);
38093
+ };
38094
+ };
37931
38095
 
37932
- <div class="form-group row" ng-if="newAppModal.data.cloudProviders.length > 1">
37933
- <div class="col-md-3 sm-label-right">Cloud Providers</div>
37934
- <div class="col-md-5">
37935
- <ui-select multiple ng-model="newAppModal.application.cloudProviders" class="form-control input-sm">
37936
- <ui-select-match> {{$item}} </ui-select-match>
37937
- <ui-select-choices repeat="provider in newAppModal.data.cloudProviders | filter: $select.search">
37938
- {{provider}}
37939
- </ui-select-choices>
37940
- </ui-select>
37941
- </div>
37942
- </div>
38096
+ bootstrapModule.config([
38097
+ "$logProvider",
38098
+ ($logProvider) => {
38099
+ $logProvider.debugEnabled(SETTINGS.debugEnabled);
38100
+ }
38101
+ ]);
38102
+ bootstrapModule.config([
38103
+ "$httpProvider",
38104
+ ($httpProvider) => {
38105
+ $httpProvider.defaults.headers.patch = {
38106
+ "Content-Type": "application/json;charset=utf-8"
38107
+ };
38108
+ }
38109
+ ]);
38110
+ bootstrapModule.config([
38111
+ "$compileProvider",
38112
+ ($compileProvider) => {
38113
+ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|slack|ssh):/);
38114
+ }
38115
+ ]);
38116
+ bootstrapModule.config([
38117
+ "$locationProvider",
38118
+ ($locationProvider) => {
38119
+ $locationProvider.hashPrefix("");
38120
+ $locationProvider.html5Mode({
38121
+ enabled: SETTINGS.feature.html5Routing,
38122
+ rewriteLinks: false,
38123
+ requireBase: false
38124
+ });
38125
+ }
38126
+ ]);
37943
38127
 
37944
- <application-provider-fields
37945
- cloud-providers="newAppModal.data.cloudProviders"
37946
- application="newAppModal.application"
37947
- >
37948
- </application-provider-fields>
38128
+ bootstrapModule.run([
38129
+ "$rootScope",
38130
+ "$state",
38131
+ ($rootScope, $state) => {
38132
+ $rootScope.feature = SETTINGS.feature;
38133
+ $rootScope.$state = $state;
38134
+ }
38135
+ ]);
38136
+ bootstrapModule.run([
38137
+ "cacheInitializer",
38138
+ (cacheInitializer) => {
38139
+ cacheInitializer.initialize();
38140
+ }
38141
+ ]);
37949
38142
 
37950
- <div class="form-group row">
37951
- <div class="col-sm-3 sm-label-right">Instance Health</div>
37952
- <div class="col-sm-9 sm-control-field checkbox">
37953
- <label>
37954
- <input type="checkbox" ng-model="newAppModal.application.platformHealthOnly" />
37955
- Consider only cloud provider health when executing tasks
37956
- <help-field key="application.platformHealthOnly"></help-field>
37957
- </label>
37958
- </div>
37959
- </div>
38143
+ const template$1 = `
38144
+ <spinnaker-container authenticating="$ctrl.authenticating" routing="$ctrl.routing"></spinnaker-container>
38145
+ `;
38146
+ class SpinnakerController {
38147
+ constructor($rootScope) {
38148
+ this.feature = SETTINGS.feature;
38149
+ this.authenticating = $rootScope.authenticating;
38150
+ this.routing = $rootScope.routing;
38151
+ }
38152
+ }
38153
+ SpinnakerController.$inject = ["$rootScope"];
38154
+ bootstrapModule.component("spinnaker", {
38155
+ template: template$1,
38156
+ controller: SpinnakerController
38157
+ });
37960
38158
 
37961
- <div class="form-group row">
37962
- <div class="col-sm-3 sm-label-right"></div>
37963
- <div class="col-sm-9 sm-control-field checkbox">
37964
- <label>
37965
- <input
37966
- type="checkbox"
37967
- ng-model="newAppModal.application.platformHealthOnlyShowOverride"
37968
- ng-click="newAppModal.updateCloudProviderHealthWarning()"
37969
- />
37970
- Show health override option for each operation
37971
- <help-field key="application.showPlatformHealthOverride"></help-field>
37972
- </label>
37973
- </div>
37974
- </div>
38159
+ bootstrapModule.run([
38160
+ "$uiRouter",
38161
+ "$log",
38162
+ ($uiRouter, $log) => {
38163
+ const subscription = $uiRouter.globals.start$.subscribe((transition) => {
38164
+ const details = {
38165
+ transition,
38166
+ toState: transition.to(),
38167
+ toParams: transition.params("to"),
38168
+ fromState: transition.from(),
38169
+ fromParams: transition.params("from")
38170
+ };
38171
+ $log.debug("$stateChangeStart", details);
38172
+ const success = () => $log.debug("$stateChangeSuccess", details);
38173
+ const failure = (error) => $log.debug("$stateChangeError", { ...details, error });
38174
+ transition.promise.then(success, failure);
38175
+ });
38176
+ $uiRouter.disposable({ dispose: () => subscription.unsubscribe() });
38177
+ }
38178
+ ]);
37975
38179
 
37976
- <div class="col-md-12" ng-if="newAppModal.data.showOverrideWarning">
37977
- <div class="alert alert-warning">
37978
- <p>
37979
- <i class="fa fa-exclamation-triangle"></i>
37980
- {{newAppModal.data.showOverrideWarning}}
37981
- </p>
37982
- <p class="text-right">
37983
- <a
37984
- class="btn btn-sm btn-default dirty-flag-dismiss"
37985
- href
37986
- ng-click="newAppModal.data.showOverrideWarning = null"
37987
- >Okay</a
37988
- >
37989
- </p>
37990
- </div>
37991
- </div>
38180
+ bootstrapModule.run([
38181
+ "$uiRouter",
38182
+ ($uiRouter) => {
38183
+ const changeTraceSetting = (newValue) => {
38184
+ const trace = $uiRouter.trace;
38185
+ trace.disable();
38186
+ if (typeof newValue === "string") {
38187
+ if (newValue.toUpperCase() === "TRUE") {
38188
+ trace.enable(Category.TRANSITION);
38189
+ } else if (newValue.toUpperCase() === "ALL") {
38190
+ trace.enable();
38191
+ } else {
38192
+ const traceValues = newValue.split(",").map((str) => str.trim().toUpperCase());
38193
+ trace.enable(...traceValues);
38194
+ }
38195
+ }
38196
+ };
38197
+ $uiRouter.transitionService.onBefore({}, paramChangedHelper("trace", changeTraceSetting));
38198
+ }
38199
+ ]);
37992
38200
 
37993
- <div class="form-group row">
37994
- <div class="col-sm-3 sm-label-right">
37995
- Instance Port
37996
- <help-field key="application.instance.port"></help-field>
37997
- </div>
37998
- <div class="col-sm-2">
37999
- <input
38000
- type="number"
38001
- min="0"
38002
- max="65536"
38003
- class="form-control input-sm"
38004
- ng-model="newAppModal.application.instancePort"
38005
- name="instancePort"
38006
- />
38007
- </div>
38008
- </div>
38201
+ bootstrapModule.config([
38202
+ "$uibTooltipProvider",
38203
+ ($uibTooltipProvider) => {
38204
+ $uibTooltipProvider.options({
38205
+ appendToBody: true
38206
+ });
38207
+ $uibTooltipProvider.setTriggers({
38208
+ "mouseenter focus": "mouseleave blur"
38209
+ });
38210
+ }
38211
+ ]);
38212
+ bootstrapModule.config([
38213
+ "$uibModalProvider",
38214
+ ($uibModalProvider) => {
38215
+ $uibModalProvider.options.backdrop = "static";
38216
+ $uibModalProvider.options.keyboard = false;
38217
+ }
38218
+ ]);
38009
38219
 
38010
- <div class="form-group row">
38011
- <div class="col-sm-3 sm-label-right">Pipeline Behavior</div>
38012
- <div class="col-sm-9 sm-control-field checkbox">
38013
- <label>
38014
- <input type="checkbox" ng-model="editApp.applicationAttributes.enableRestartRunningExecutions" />
38015
- Enable restarting running pipelines
38016
- </label>
38017
- <help-field key="application.enableRestartRunningExecutions"></help-field>
38018
- <label>
38019
- <input type="checkbox" ng-model="editApp.applicationAttributes.enableRerunActiveExecutions" />
38020
- Enable re-run button on active pipelines
38021
- </label>
38022
- <help-field key="application.enableRerunActiveExecutions"></help-field>
38023
- </div>
38024
- </div>
38220
+ bootstrapModule.config([
38221
+ "$uiRouterProvider",
38222
+ ($uiRouterProvider) => {
38223
+ $uiRouterProvider.plugin(UIRouterRxPlugin);
38224
+ }
38225
+ ]);
38025
38226
 
38026
- <render-if-feature feature="fiatEnabled">
38027
- <div class="form-group row">
38028
- <div class="col-sm-3 sm-label-right">Permissions <help-field key="application.permissions"></help-field></div>
38029
- <div class="col-sm-9">
38030
- <permissions-configurer
38031
- permissions="newAppModal.application.permissions"
38032
- on-permissions-change="newAppModal.handlePermissionsChange"
38033
- required-group-membership="newAppModal.application.requiredGroupMembership"
38034
- >
38035
- </permissions-configurer>
38036
- </div>
38037
- </div>
38038
- </render-if-feature>
38227
+ bootstrapModule.run([
38228
+ "$uiRouter",
38229
+ ($uiRouter) => {
38230
+ let visualizerEnabled = "false";
38231
+ let VisualizerPlugin = null;
38232
+ function loadVisualizer() {
38233
+ const collapseGlobs = ["home.*", "home.*.application.*", "home.*.application.insight.*"].map((globStr) => new Glob(globStr));
38234
+ const collapsedStates = $uiRouter.stateRegistry.get().filter((state) => collapseGlobs.some((glob) => glob.matches(state.name)));
38235
+ collapsedStates.forEach((state) => state.$$state()._collapsed = true);
38236
+ return import('@uirouter/visualizer').then((vis) => VisualizerPlugin = vis.Visualizer).then(createVisualizer);
38237
+ }
38238
+ function createVisualizer() {
38239
+ if (visualizerEnabled !== "true") {
38240
+ return;
38241
+ }
38242
+ destroyVisualizer();
38243
+ if (VisualizerPlugin) {
38244
+ $uiRouter.plugin(VisualizerPlugin);
38245
+ } else {
38246
+ loadVisualizer();
38247
+ }
38248
+ }
38249
+ function destroyVisualizer() {
38250
+ const plugin = $uiRouter.getPlugin("visualizer");
38251
+ plugin && $uiRouter.dispose(plugin);
38252
+ }
38253
+ function toggleVisualizer(trans) {
38254
+ const enabled = trans.paramsChanged().vis;
38255
+ if (enabled === void 0) {
38256
+ return null;
38257
+ }
38258
+ if (enabled === visualizerEnabled) {
38259
+ return trans.targetState().withParams({ vis: void 0 });
38260
+ }
38261
+ visualizerEnabled = enabled;
38262
+ if (enabled === "true") {
38263
+ createVisualizer();
38264
+ } else if (enabled === "false") {
38265
+ destroyVisualizer();
38266
+ }
38267
+ return trans.targetState().withParams({ vis: void 0 });
38268
+ }
38269
+ window.vis = createVisualizer;
38270
+ $uiRouter.transitionService.onStart({}, toggleVisualizer);
38271
+ }
38272
+ ]);
38039
38273
 
38040
- <div class="form-group row slide-in" ng-if="newAppModal.state.errorMessages.length">
38041
- <div class="col-md-12">
38042
- <div class="alert alert-danger">
38043
- <div ng-repeat="errorMessage in newAppModal.state.errorMessages">
38044
- <status-glyph item="{isFailed: true}"></status-glyph> {{errorMessage}}
38045
- </div>
38046
- </div>
38047
- </div>
38048
- </div>
38274
+ uiSelectDecorator.$inject = ["$provide"];
38275
+ function uiSelectDecorator($provide) {
38276
+ $provide.decorator("uiSelectMultipleDirective", [
38277
+ "$delegate",
38278
+ "$timeout",
38279
+ function($delegate, $timeout) {
38280
+ const [uiSelect] = $delegate;
38281
+ const originalLink = uiSelect.link;
38282
+ const SELECT_EVENT_KEY = "uis:select";
38283
+ uiSelect.link = function(scope, _element, _attrs, ctrls) {
38284
+ originalLink.apply(this, arguments);
38285
+ const [$select] = ctrls;
38286
+ scope.$$listeners[SELECT_EVENT_KEY] = [];
38287
+ scope.$on(SELECT_EVENT_KEY, function(event, item) {
38288
+ if ($select.selected.length >= $select.limit) {
38289
+ return;
38290
+ }
38291
+ if (!event.defaultPrevented) {
38292
+ $select.selected.push(item);
38293
+ const locals = {
38294
+ [$select.parserResult.itemName]: item
38295
+ };
38296
+ $timeout(function() {
38297
+ if ($select.onSelectCallback) {
38298
+ $select.onSelectCallback(scope, {
38299
+ $item: item,
38300
+ $model: $select.parserResult.modelMapper(scope, locals)
38301
+ });
38302
+ }
38303
+ });
38304
+ scope.$selectMultiple.updateModel();
38305
+ }
38306
+ });
38307
+ };
38308
+ return $delegate;
38309
+ }
38310
+ ]);
38311
+ $provide.decorator("uiSelectMinErr", [
38312
+ "$delegate",
38313
+ function($delegate) {
38314
+ return function handledError() {
38315
+ const original = $delegate;
38316
+ if (arguments.length === 3) {
38317
+ if (arguments[0] === "choices" && arguments[1] === `Expected multiple .ui-select-choices-row but got '{0}'.` && arguments[2] === 0) {
38318
+ throw new Error("IGNORE", "IGNORE");
38319
+ }
38320
+ }
38321
+ return original.apply(this, arguments);
38322
+ };
38323
+ }
38324
+ ]);
38325
+ $provide.decorator("$exceptionHandler", [
38326
+ "$delegate",
38327
+ function($delegate) {
38328
+ return function(exception, cause) {
38329
+ if (exception && exception.message === "IGNORE") {
38330
+ return;
38331
+ }
38332
+ if (Array.isArray(exception) && exception.length && exception[0] instanceof Error) {
38333
+ exception.forEach((e) => $delegate(e, cause));
38334
+ } else {
38335
+ $delegate(exception, cause);
38336
+ }
38337
+ };
38338
+ }
38339
+ ]);
38340
+ }
38341
+ bootstrapModule.config(uiSelectDecorator);
38342
+ bootstrapModule.config([
38343
+ "uiSelectConfig",
38344
+ (uiSelectConfig) => {
38345
+ uiSelectConfig.theme = "select2";
38346
+ uiSelectConfig.appendToBody = true;
38347
+ }
38348
+ ]);
38049
38349
 
38050
- <div class="form-group row">
38051
- <div class="col-md-12">
38052
- <em>* Required</em>
38053
- </div>
38054
- </div>
38055
- </div>
38350
+ class ApplicationSearchResultType extends SearchResultType {
38351
+ constructor() {
38352
+ super(...arguments);
38353
+ this.id = "applications";
38354
+ this.order = 1;
38355
+ this.displayName = "Applications";
38356
+ this.iconClass = "far fa-window-maximize";
38357
+ this.cols = {
38358
+ APPLICATION: { key: "application", label: "Name" },
38359
+ ACCOUNT: { key: "accounts", label: "Account" },
38360
+ EMAIL: { key: "email" }
38361
+ };
38362
+ this.TabComponent = DefaultSearchResultTab;
38363
+ this.HeaderComponent = () => /* @__PURE__ */ React__default.createElement(SearchTableHeader, null, /* @__PURE__ */ React__default.createElement(HeaderCell, {
38364
+ col: this.cols.APPLICATION
38365
+ }), /* @__PURE__ */ React__default.createElement(HeaderCell, {
38366
+ col: this.cols.ACCOUNT
38367
+ }), /* @__PURE__ */ React__default.createElement(HeaderCell, {
38368
+ col: this.cols.EMAIL
38369
+ }));
38370
+ this.DataComponent = ({ resultSet }) => {
38371
+ const itemKeyFn = (item) => item.application;
38372
+ const itemSortFn = (a, b) => a.application.localeCompare(b.application);
38373
+ const results = resultSet.results.slice().sort(itemSortFn);
38374
+ return /* @__PURE__ */ React__default.createElement(SearchTableBody, null, results.map((item) => /* @__PURE__ */ React__default.createElement(SearchTableRow, {
38375
+ key: itemKeyFn(item)
38376
+ }, /* @__PURE__ */ React__default.createElement(HrefCell, {
38377
+ item,
38378
+ col: this.cols.APPLICATION
38379
+ }), /* @__PURE__ */ React__default.createElement(AccountCell, {
38380
+ item,
38381
+ col: this.cols.ACCOUNT
38382
+ }), /* @__PURE__ */ React__default.createElement(BasicCell, {
38383
+ item,
38384
+ col: this.cols.EMAIL
38385
+ }))));
38386
+ };
38387
+ }
38388
+ displayFormatter(searchResult) {
38389
+ return searchResult.application;
38390
+ }
38391
+ }
38392
+ searchResultTypeRegistry.register(new ApplicationSearchResultType());
38056
38393
 
38057
- <div class="modal-footer">
38058
- <a href class="btn btn-default" ng-click="$dismiss()">Cancel</a>
38059
- <submit-button
38060
- is-new="true"
38061
- is-disabled="newApplicationForm.$invalid || newAppModal.state.submitting || newAppModal.data.showOverrideWarning || newAppModal.state.permissionsInvalid"
38062
- submitting="newAppModal.state.submitting"
38063
- on-click="newAppModal.submit()"
38064
- ></submit-button>
38065
- </div>
38066
- </form>
38067
- </div>
38068
- `);
38069
- }]);
38394
+ const ApplicationTable = ({ currentSort, toggleSort, applications }) => /* @__PURE__ */ React__default.createElement("table", {
38395
+ className: "table table-hover"
38396
+ }, /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("th", {
38397
+ style: { width: "18%" }
38398
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
38399
+ currentSort,
38400
+ onChange: toggleSort,
38401
+ label: "Name",
38402
+ sortKey: "name"
38403
+ })), /* @__PURE__ */ React__default.createElement("th", {
38404
+ style: { width: "15%" }
38405
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
38406
+ currentSort,
38407
+ onChange: toggleSort,
38408
+ label: "Created",
38409
+ sortKey: "createTs"
38410
+ })), /* @__PURE__ */ React__default.createElement("th", {
38411
+ style: { width: "15%" }
38412
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
38413
+ currentSort,
38414
+ onChange: toggleSort,
38415
+ label: "Updated",
38416
+ sortKey: "updateTs"
38417
+ })), /* @__PURE__ */ React__default.createElement("th", {
38418
+ style: { width: "15%" }
38419
+ }, /* @__PURE__ */ React__default.createElement(SortToggle, {
38420
+ currentSort,
38421
+ onChange: toggleSort,
38422
+ label: "Owner",
38423
+ sortKey: "email"
38424
+ })), /* @__PURE__ */ React__default.createElement("th", null, /* @__PURE__ */ React__default.createElement(SortToggle, {
38425
+ currentSort,
38426
+ onChange: toggleSort,
38427
+ label: "Account(s)",
38428
+ sortKey: "accounts"
38429
+ })), SETTINGS.feature.slack && /* @__PURE__ */ React__default.createElement("th", {
38430
+ style: { width: "22%" }
38431
+ }, "Slack Channel"), /* @__PURE__ */ React__default.createElement("th", {
38432
+ style: { width: "22%" }
38433
+ }, "Description"))), /* @__PURE__ */ React__default.createElement("tbody", null, applications.map((app) => {
38434
+ var _a;
38435
+ const appName = app.name.toLowerCase();
38436
+ return /* @__PURE__ */ React__default.createElement(UISref, {
38437
+ key: appName,
38438
+ to: ".application",
38439
+ params: { application: appName }
38440
+ }, /* @__PURE__ */ React__default.createElement("tr", {
38441
+ className: "clickable"
38442
+ }, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(UISref, {
38443
+ to: ".application",
38444
+ params: { application: appName }
38445
+ }, /* @__PURE__ */ React__default.createElement("a", null, appName))), /* @__PURE__ */ React__default.createElement("td", null, timestamp(app.createTs)), /* @__PURE__ */ React__default.createElement("td", null, timestamp(app.updateTs)), /* @__PURE__ */ React__default.createElement("td", null, app.email), /* @__PURE__ */ React__default.createElement("td", null, app.accounts), SETTINGS.feature.slack && /* @__PURE__ */ React__default.createElement("td", null, (_a = app.slackChannel) == null ? void 0 : _a.name), /* @__PURE__ */ React__default.createElement("td", null, app.description)));
38446
+ })));
38070
38447
 
38071
38448
  var css_248z$10 = ".applications {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n overflow-y: hidden;\n}\n";
38072
38449
  styleInject(css_248z$10);
@@ -42661,7 +43038,8 @@ class ServerGroupManager extends React__default.Component {
42661
43038
  accountId: serverGroups[0].account,
42662
43039
  region: serverGroups[0].region,
42663
43040
  provider: serverGroups[0].cloudProvider,
42664
- serverGroupManager: manager
43041
+ serverGroupManager: manager,
43042
+ name: manager
42665
43043
  };
42666
43044
  return ReactInjector.$state.includes("**.serverGroupManager", params);
42667
43045
  };
@@ -42674,7 +43052,8 @@ class ServerGroupManager extends React__default.Component {
42674
43052
  accountId: serverGroups[0].account,
42675
43053
  region: serverGroups[0].region,
42676
43054
  provider: serverGroups[0].cloudProvider,
42677
- serverGroupManager: manager
43055
+ serverGroupManager: manager,
43056
+ name: manager
42678
43057
  });
42679
43058
  };
42680
43059
  this.buildHealthCounts = () => {
@@ -52918,7 +53297,7 @@ const _BakeHelmConfigForm = class extends React__default.Component {
52918
53297
  this.overrideChanged = (overrides) => {
52919
53298
  this.props.formik.setFieldValue("overrides", overrides);
52920
53299
  };
52921
- this.state = { gitRepoArtifactAccountNames: [] };
53300
+ this.state = { gitRepoArtifactAccountNames: [], helmImageArtifactAccountNames: [] };
52922
53301
  }
52923
53302
  componentDidMount() {
52924
53303
  const stage = this.props.formik.values;
@@ -52940,7 +53319,8 @@ const _BakeHelmConfigForm = class extends React__default.Component {
52940
53319
  }
52941
53320
  AccountService.getArtifactAccounts().then((artifactAccounts) => {
52942
53321
  this.setState({
52943
- gitRepoArtifactAccountNames: artifactAccounts.filter((account) => account.types.some((type) => ArtifactTypePatterns.GIT_REPO.test(type))).map((account) => account.name)
53322
+ gitRepoArtifactAccountNames: artifactAccounts.filter((account) => account.types.some((type) => ArtifactTypePatterns.GIT_REPO.test(type))).map((account) => account.name),
53323
+ helmImageArtifactAccountNames: artifactAccounts.filter((account) => account.types.some((type) => ArtifactTypePatterns.HELM_IMAGE.test(type))).map((account) => account.name)
52944
53324
  });
52945
53325
  });
52946
53326
  }
@@ -52992,7 +53372,7 @@ const _BakeHelmConfigForm = class extends React__default.Component {
52992
53372
  onExpectedArtifactSelected: (artifact) => this.onTemplateArtifactSelected(artifact, 0),
52993
53373
  pipeline: this.props.pipeline,
52994
53374
  stage
52995
- }), this.state.gitRepoArtifactAccountNames.includes(this.getInputArtifact(stage, 0).account) && /* @__PURE__ */ React__default.createElement(StageConfigField, {
53375
+ }), (this.state.gitRepoArtifactAccountNames.includes(this.getInputArtifact(stage, 0).account) || this.state.helmImageArtifactAccountNames.includes(this.getInputArtifact(stage, 0).account)) && /* @__PURE__ */ React__default.createElement(StageConfigField, {
52996
53376
  label: "Helm Chart File Path",
52997
53377
  helpKey: "pipeline.config.bake.manifest.helm.chartFilePath"
52998
53378
  }, /* @__PURE__ */ React__default.createElement(TextInput, {
@@ -53073,7 +53453,7 @@ const _BakeHelmConfigForm = class extends React__default.Component {
53073
53453
  }
53074
53454
  };
53075
53455
  let BakeHelmConfigForm = _BakeHelmConfigForm;
53076
- BakeHelmConfigForm.excludedArtifactTypes = excludeAllTypesExcept(ArtifactTypePatterns.BITBUCKET_FILE, ArtifactTypePatterns.CUSTOM_OBJECT, ArtifactTypePatterns.EMBEDDED_BASE64, ArtifactTypePatterns.GCS_OBJECT, ArtifactTypePatterns.GIT_REPO, ArtifactTypePatterns.GITHUB_FILE, ArtifactTypePatterns.GITLAB_FILE, ArtifactTypePatterns.S3_OBJECT, ArtifactTypePatterns.HELM_CHART, ArtifactTypePatterns.HTTP_FILE, ArtifactTypePatterns.ORACLE_OBJECT);
53456
+ BakeHelmConfigForm.excludedArtifactTypes = excludeAllTypesExcept(ArtifactTypePatterns.BITBUCKET_FILE, ArtifactTypePatterns.CUSTOM_OBJECT, ArtifactTypePatterns.EMBEDDED_BASE64, ArtifactTypePatterns.GCS_OBJECT, ArtifactTypePatterns.GIT_REPO, ArtifactTypePatterns.GITHUB_FILE, ArtifactTypePatterns.GITLAB_FILE, ArtifactTypePatterns.S3_OBJECT, ArtifactTypePatterns.HELM_CHART, ArtifactTypePatterns.HTTP_FILE, ArtifactTypePatterns.ORACLE_OBJECT, ArtifactTypePatterns.HELM_IMAGE);
53077
53457
 
53078
53458
  const _BakeHelmfileConfigForm = class extends React__default.Component {
53079
53459
  constructor(props) {
@@ -63726,10 +64106,34 @@ class ExecutionGroups extends React__default.Component {
63726
64106
  const { groups = [], container, showingDetails } = this.state;
63727
64107
  const hasGroups = groups.length > 0;
63728
64108
  const className = `row pipelines executions ${showingDetails ? "showing-details" : ""}`;
63729
- const allGroups = (groups || []).filter((g) => {
64109
+ const allExecutionIds = groups.flatMap((group) => group.executions.map((e) => e.id));
64110
+ const uniqueIds = new Set(allExecutionIds);
64111
+ const hasDuplicates = allExecutionIds.length !== uniqueIds.size;
64112
+ let processedGroups;
64113
+ if (hasDuplicates) {
64114
+ const processedExecutionIds = new Set();
64115
+ const deduplicatedGroups = groups.map((group) => ({
64116
+ ...group,
64117
+ executions: [...group.executions],
64118
+ runningExecutions: [...group.runningExecutions]
64119
+ }));
64120
+ deduplicatedGroups.forEach((group) => {
64121
+ group.executions = group.executions.filter((execution) => {
64122
+ if (processedExecutionIds.has(execution.id))
64123
+ return false;
64124
+ processedExecutionIds.add(execution.id);
64125
+ return true;
64126
+ });
64127
+ group.runningExecutions = group.runningExecutions.filter((execution) => group.executions.some((e) => e.id === execution.id));
64128
+ });
64129
+ processedGroups = deduplicatedGroups.filter((group) => group.executions.length > 0);
64130
+ } else {
64131
+ processedGroups = groups;
64132
+ }
64133
+ const allGroups = (processedGroups || []).filter((g) => {
63730
64134
  var _a;
63731
64135
  return ((_a = g == null ? void 0 : g.config) == null ? void 0 : _a.migrationStatus) === "Started";
63732
- }).concat(groups.filter((g) => {
64136
+ }).concat(processedGroups.filter((g) => {
63733
64137
  var _a;
63734
64138
  return ((_a = g == null ? void 0 : g.config) == null ? void 0 : _a.migrationStatus) !== "Started";
63735
64139
  }));
@@ -68229,33 +68633,6 @@ module(CORE_NOTIFICATION_NOTIFICATIONS_MODULE, [NOTIFICATION_LIST]).run(() => {
68229
68633
  });
68230
68634
  });
68231
68635
 
68232
- function anyFieldFilter() {
68233
- return function(items, props) {
68234
- let out = [];
68235
- if (Array.isArray(items)) {
68236
- items.forEach(function(item) {
68237
- let itemMatches = false;
68238
- const keys = Object.keys(props);
68239
- for (const prop of keys) {
68240
- const text = props[prop].toLowerCase();
68241
- if (item[prop] && item[prop].toString().toLowerCase().includes(text)) {
68242
- itemMatches = true;
68243
- break;
68244
- }
68245
- }
68246
- if (itemMatches) {
68247
- out.push(item);
68248
- }
68249
- });
68250
- } else {
68251
- out = items;
68252
- }
68253
- return out;
68254
- };
68255
- }
68256
- const ANY_FIELD_FILTER = "spinnaker.core.presentation.anyFieldFilter";
68257
- module(ANY_FIELD_FILTER, []).filter("anyFieldFilter", anyFieldFilter);
68258
-
68259
68636
  class AutoScrollController {
68260
68637
  constructor($timeout) {
68261
68638
  this.$timeout = $timeout;
@@ -69148,89 +69525,8 @@ window.angular.module("ng").run(["$templateCache", function(templateCache) {
69148
69525
  `);
69149
69526
  }]);
69150
69527
 
69151
- const CORE_PROJECTS_PROJECTS_CONTROLLER = "spinnaker.projects.controller";
69152
- module(CORE_PROJECTS_PROJECTS_CONTROLLER, [
69153
- UIROUTER_ANGULARJS,
69154
- ANY_FIELD_FILTER,
69155
- CORE_PRESENTATION_SORTTOGGLE_SORTTOGGLE_DIRECTIVE,
69156
- INSIGHT_MENU_DIRECTIVE
69157
- ]).component("projectInsightMenu", react2angular(withErrorBoundary(InsightMenu, "projectInsightMenu"), [
69158
- "createApp",
69159
- "createProject",
69160
- "refreshCaches"
69161
- ])).controller("ProjectsCtrl", [
69162
- "$scope",
69163
- "$uibModal",
69164
- "$log",
69165
- "$filter",
69166
- function($scope, $uibModal, $log, $filter) {
69167
- const projectsViewStateCache = ViewStateCache.get("projects") || ViewStateCache.createCache("projects", { version: 1 });
69168
- function cacheViewState() {
69169
- projectsViewStateCache.put("#global", $scope.viewState);
69170
- }
69171
- function initializeViewState() {
69172
- $scope.viewState = projectsViewStateCache.get("#global") || {
69173
- sortModel: { key: "name" },
69174
- projectFilter: ""
69175
- };
69176
- }
69177
- $scope.projectsLoaded = false;
69178
- $scope.projectFilter = "";
69179
- $scope.menuActions = [
69180
- {
69181
- displayName: "Create Project",
69182
- action: function() {
69183
- ConfigureProjectModal.show().catch(() => {
69184
- });
69185
- }
69186
- }
69187
- ];
69188
- this.filterProjects = function filterProjects() {
69189
- const filtered = $filter("anyFieldFilter")($scope.projects, {
69190
- name: $scope.viewState.projectFilter,
69191
- email: $scope.viewState.projectFilter
69192
- });
69193
- const sorted = $filter("orderBy")(filtered, $scope.viewState.sortModel.key);
69194
- $scope.filteredProjects = sorted;
69195
- this.resetPaginator();
69196
- };
69197
- this.resultPage = function resultPage() {
69198
- const pagination = $scope.pagination;
69199
- const allFiltered = $scope.filteredProjects;
69200
- const start = (pagination.currentPage - 1) * pagination.itemsPerPage;
69201
- const end = pagination.currentPage * pagination.itemsPerPage;
69202
- if (!allFiltered || !allFiltered.length) {
69203
- return [];
69204
- }
69205
- if (allFiltered.length < pagination.itemsPerPage) {
69206
- return allFiltered;
69207
- }
69208
- if (allFiltered.length < end) {
69209
- return allFiltered.slice(start);
69210
- }
69211
- return allFiltered.slice(start, end);
69212
- };
69213
- this.resetPaginator = function resetPaginator() {
69214
- $scope.pagination = {
69215
- currentPage: 1,
69216
- itemsPerPage: 12,
69217
- maxSize: 12
69218
- };
69219
- };
69220
- const ctrl = this;
69221
- ProjectReader.listProjects().then(function(projects) {
69222
- $scope.projects = projects;
69223
- ctrl.filterProjects();
69224
- $scope.projectsLoaded = true;
69225
- });
69226
- $scope.$watch("viewState", cacheViewState, true);
69227
- initializeViewState();
69228
- }
69229
- ]);
69230
-
69231
69528
  const PROJECTS_STATES_CONFIG = "spinnaker.core.projects.state.config";
69232
69529
  module(PROJECTS_STATES_CONFIG, [
69233
- CORE_PROJECTS_PROJECTS_CONTROLLER,
69234
69530
  CORE_PROJECTS_DASHBOARD_DASHBOARD_CONTROLLER,
69235
69531
  APPLICATION_STATE_PROVIDER,
69236
69532
  STATE_CONFIG_PROVIDER
@@ -69296,9 +69592,8 @@ module(PROJECTS_STATES_CONFIG, [
69296
69592
  url: "/projects",
69297
69593
  views: {
69298
69594
  "main@": {
69299
- templateUrl: "core/src/projects/projects.html",
69300
- controller: "ProjectsCtrl",
69301
- controllerAs: "ctrl"
69595
+ component: Projects,
69596
+ $type: "react"
69302
69597
  }
69303
69598
  },
69304
69599
  data: {
@@ -69357,96 +69652,6 @@ window.angular.module("ng").run(["$templateCache", function(templateCache) {
69357
69652
  </div>
69358
69653
  `);
69359
69654
  }]);
69360
- window.angular.module("ng").run(["$templateCache", function(templateCache) {
69361
- templateCache.put("core/src/projects/projects.html", `<div class="infrastructure">
69362
- <div class="infrastructure-section search-header">
69363
- <div class="container">
69364
- <h2 class="header-section">
69365
- <span class="search-label">Projects</span>
69366
- <input
69367
- type="search"
69368
- placeholder="Search projects"
69369
- class="form-control input-md"
69370
- focus
69371
- ng-model="viewState.projectFilter"
69372
- ng-change="ctrl.filterProjects()"
69373
- />
69374
- </h2>
69375
- <div class="header-actions">
69376
- <project-insight-menu create-app="false" create-project="true" refresh-caches="false" />
69377
- </div>
69378
- </div>
69379
- </div>
69380
- <div class="container">
69381
- <div ng-if="!projectsLoaded" class="horizontal center middle" style="margin-bottom: 250px; height: 100px">
69382
- <loading-spinner size="'small'"></loading-spinner>
69383
- </div>
69384
- <table ng-if="projectsLoaded" class="table table-hover">
69385
- <thead>
69386
- <tr>
69387
- <th
69388
- width="20%"
69389
- sort-toggle
69390
- key="name"
69391
- label="Name"
69392
- sort-model="viewState.sortModel"
69393
- on-change="ctrl.filterProjects()"
69394
- ></th>
69395
- <th
69396
- width="20%"
69397
- sort-toggle
69398
- key="createTs"
69399
- label="Created"
69400
- sort-model="viewState.sortModel"
69401
- on-change="ctrl.filterProjects()"
69402
- ></th>
69403
- <th
69404
- width="20%"
69405
- sort-toggle
69406
- key="updateTs"
69407
- label="Updated"
69408
- sort-model="viewState.sortModel"
69409
- on-change="ctrl.filterProjects()"
69410
- ></th>
69411
- <th
69412
- width="25%"
69413
- sort-toggle
69414
- key="email"
69415
- label="Owner"
69416
- sort-model="viewState.sortModel"
69417
- on-change="ctrl.filterProjects()"
69418
- ></th>
69419
- </tr>
69420
- </thead>
69421
- <tbody>
69422
- <tr
69423
- class="clickable"
69424
- ng-repeat="project in ctrl.resultPage()"
69425
- ui-sref="home.project.dashboard({project: project.name.toLowerCase()})"
69426
- >
69427
- <td>
69428
- <a href ui-sref="home.project.dashboard({project: project.name.toLowerCase()})">
69429
- {{ project.name.toLowerCase() }}
69430
- </a>
69431
- </td>
69432
- <td>{{ project.createTs | timestamp }}</td>
69433
- <td>{{ project.updateTs | timestamp }}</td>
69434
- <td>{{ project.email }}</td>
69435
- </tr>
69436
- </tbody>
69437
- </table>
69438
- <ul
69439
- uib-pagination
69440
- ng-if="projectsLoaded"
69441
- items-per-page="pagination.itemsPerPage"
69442
- total-items="filteredProjects.length"
69443
- max-size="pagination.maxSize"
69444
- ng-model="pagination.currentPage"
69445
- ></ul>
69446
- </div>
69447
- </div>
69448
- `);
69449
- }]);
69450
69655
 
69451
69656
  const CORE_PROJECTS_PROJECTS_MODULE = "spinnaker.projects";
69452
69657
  module(CORE_PROJECTS_PROJECTS_MODULE, [PROJECTS_STATES_CONFIG]);
@@ -71811,5 +72016,5 @@ module(CORE_MODULE, [
71811
72016
  initialize();
71812
72017
  });
71813
72018
 
71814
- export { API, APPLICATION_STATE_PROVIDER, ARTIFACT_ACCOUNT_SELECTOR_COMPONENT_REACT, ARTIFACT_TYPE_EMBEDDED, ARTIFACT_TYPE_REMOTE, AccountCell, AccountSelectInput, AccountService, AccountTag, AddEntityTagLinks, Alerts, AngularJSAdapter, AppListExtractor, Application, ApplicationContext, ApplicationContextProvider, ApplicationDataSource, ApplicationDataSourceRegistry, ApplicationIcon, ApplicationModelBuilder, ApplicationNameValidator, ApplicationReader, ApplicationStateProvider, ApplicationWriter, Applications$1 as Applications, ApplicationsPickerInput, ArtifactAccountSelector, ArtifactIcon, ArtifactIconList, ArtifactIconService, ArtifactList, ArtifactReferenceService, ArtifactTypePatterns, AsgActionExecutionDetailsSection, AuthenticationInitializer, AuthenticationService, BakeExecutionLabel, BakeryReader, BannerContainer, BannerContainerContent, BaseBuildTriggerTemplate, BasicCell, BreakString, BuildServiceType, CACHE_INITIALIZER_SERVICE, CLUSTER_MATCHES_COMPONENT, CLUSTER_SERVICE, CONFIG_SECTION_FOOTER, CORE_MANAGED_MANAGED_MODULE, CORE_MODULE, CacheInitializerService, CapacityDetailsSection, CategorizedNotifications, CertificateReader, CheckboxInput, ChecklistInput, CloudMetricsReader, CloudProviderIcon, CloudProviderLabel, CloudProviderLogo, CloudProviderRegistry, ClusterFilterService, ClusterMatcher, ClusterMatches, ClusterPodTitleWrapper, ClusterService, ClusterState, ClusterTargetBuilder, Clusters, CollapsibleElement, CollapsibleSection, CollapsibleSectionStateCache, CollapsibleSectionStateCacheInternal, ConfigSectionFooter, ConfigSectionFooterController, ConfigureProjectModal, ConfirmationModalService, ConsoleOutputLink, CopyToClipboard, CoreModalInject, CoreReactInject, AdditionalFields$3 as CoreRedBlackAdditionalFields, CreateFunctionButton, CreateLoadBalancerButton, CreatePipelineModal, CurrentCapacity, CustomLabels, DELIVERY_KEY, DEPLOY_INITIALIZER_COMPONENT, DIFF_MODULE, DayPickerInput, DebugTiming, DebugTimingCumulative, DeckCacheFactory, DefaultClusterMatcher, DefaultPodNameProvider, DefaultSearchResultTab, DeleteType, DeployInitializer, DeployInitializerController, DeployingIntoManagedClusterWarning, DeploymentStrategyRegistrar, DeploymentStrategyRegistry, DeploymentStrategySelector, DeprecatedRequestBuilder, DesiredCapacity, Details, DiffView, EXECUTION_ARTIFACT_TAB, EXECUTION_DETAILS_SECTION_SERVICE, EXECUTION_SERVICE, EXPECTED_ARTIFACT_EDITOR_COMPONENT_REACT, EXPECTED_ARTIFACT_SELECTOR_COMPONENT_REACT, EXPECTED_ARTIFACT_SOURCE_SELECTOR_COMPONENT_REACT, EditNotificationModal, EntityName, EntityNotifications, EntitySource, EntityTagEditor, EntityTagWriter, EntityTagsReader, EventBus, Execution$1 as Execution, ExecutionArtifactTab, ExecutionBarLabel, ExecutionDetailsSection, ExecutionDetailsSectionNav, ExecutionDetailsSectionService, ExecutionDetailsTasks, ExecutionFilterModel, ExecutionMarkerIcon, ExecutionService, ExecutionState, ExecutionStepDetails, ExecutionsTransformer, ExpectedArtifactEditor, ExpectedArtifactModal, ExpectedArtifactSelector, ExpectedArtifactSelectorViewController, ExpectedArtifactService, ExpectedArtifactSourceSelector, ExpressionError, ExpressionInput, ExpressionPreview, FORM_VALIDATION_VALIDATABLE_FIELD_IS_VALID_SHORT_CIRCUIT, FUNCTION_READ_SERVICE, Filter, FilterCheckbox$1 as FilterCheckbox, FilterCollapse, FilterModelService, FilterSearch, FilterSection, FilterTags, FilterTypeRegistry, Filters$1 as Filters, FirewallLabels, FormField, FormValidator, FormValidatorField, FormikExpressionField, FormikExpressionRegexField, FormikForm, FormikFormField, FormikSpelContext, FormikSpelContextProvider, FormikStageConfig, FunctionDetails, FunctionReader, FunctionState, FunctionWriter, GlobalSearch, GroupedNotificationList, HeaderCell, Health, HealthCounts, HealthCountsCell, HelpContentsRegistry, HelpField, HelpMenu, HelpTextExpandedContext, HoverablePopover, HrefCell, IMAGE_READER, IMAGE_SOURCE_SELECTOR_COMPONENT, INFRASTRUCTURE_CACHE_CONFIG, INFRASTRUCTURE_KEY, INFRASTRUCTURE_SEARCH_SERVICE, INSTANCE_TYPE_SERVICE, IconTooltip, IgorService, ImageList, ImageReader, InfrastructureCaches, InfrastructureCachesInternal, InfrastructureSearchService, InfrastructureSearcher, InstanceActions, InstanceDetails, InstanceDetailsCmp, InstanceDetailsHeader, InstanceDetailsPane, InstanceInsights, InstanceLinks, InstanceLoadBalancerHealth, InstanceReader, InstanceTypeService, InstanceWriter, InvalidAPIResponse, JobEventBasedPodNameProvider, JobManifestPodLogs, JobStageExecutionLogs, JsonEditor, JsonUtils, Key, LINK_WITH_CLIPBOARD, LOAD_BALANCER_READ_SERVICE, LabelComponent, LabeledValue, LabeledValueList, LayoutConsumer, LayoutContext, LayoutProvider, LinkWithClipboard, LoadBalancerClusterContainer, LoadBalancerDataUtils, LoadBalancerInstances, LoadBalancerReader, LoadBalancerServerGroup, LoadBalancerState, LoadBalancerWriter, LoadBalancers$2 as LoadBalancers, LoadBalancersTagWrapper, MANAGED_RESOURCES_DATA_SOURCE, MANAGED_RESOURCE_DETAILS_INDICATOR, ManagedMenuItem, ManagedReader, ManagedResourceDetailsIndicator, ManagedResourceStatus, ManagedResourceStatusIndicator, ManagedWriter, ManifestReader, ManifestWriter, ManifestYaml, ManualExecutionModal, MapEditor, MapEditorInput, MapPair, Markdown, MinMaxDesiredChanges, Modal, ModalBody, ModalClose, ModalFooter, ModalHeader, ModalInjector, ModalWizard, MultiSelectCheckbox, NOTIFICATION_LIST, NameUtils, NavigationCategoryRegistry, NetworkReader, NgAppEngineDeployArtifactDelegate, NgAppengineConfigArtifactDelegate, NgBakeManifestArtifactDelegate, NgGCEImageArtifactDelegate, NgGenericArtifactDelegate, NgReact, NgReactInjector, NotificationCategories, NotificationCategory, NotificationDetails$1 as NotificationDetails, NotificationList, NotificationSelector, NotificationTransformer, NotificationsList, NotifierService, NumberInput$1 as NumberInput, NumberList, OVERRIDE_REGISTRY, OrchestratedItemTransformer, Overridable, OverrideRegistry, Overrides, PAGER_DUTY_SELECT_FIELD_COMPONENT, PAGER_DUTY_TAG_COMPONENT, PAGE_TITLE_SERVICE, PLUGINS_MODULE, PRECONFIGUREDJOB_STAGE, PROVIDER_SERVICE_DELEGATE, PageNavigator, PageSection, PageTitleService, PagerDutyReader, PagerDutySelectFieldController, PagerDutyTagComponentController, PagerDutyWriter, PipelineConfigService, PipelineConfigValidator, PipelineRegistry, PipelineStageExecutionDetails, PipelineTemplateReader, PipelineTemplateV2Service, PipelineTemplates, Pipelines$1 as Pipelines, PlatformHealthOverride, PlatformHealthOverrideInput, PlatformHealthOverrideMessage, PluginRegistry, PreconfiguredJobExecutionDetails, PreconfiguredJobReader, PreconfiguredJobStageConfig, ProjectAttributes, ProjectHeader, ProjectReader, ProjectWriter, ProviderSelectionService, ProviderServiceDelegate, PubsubSubscriptionReader, REACT_MODULE, RECENT_HISTORY_SERVICE, RENDER_IF_FEATURE, REST, ROBOT_TO_HUMAN_FILTER, RadioButtonInput, ReactInject, ReactInjector, ReactModal, ReactSelectInput, RecentHistoryService, RegionSelectField, RegionSelectInput, RegistrationQueue, Registry, RenderOutputFile, RenderWhenVisible, RequestBuilder, ResponsiveFieldLayout, RetryService, RunAsUserInput, RunningTasks$1 as RunningTasks, SECURITY_GROUP_READER, SERVER_GROUP_COMMAND_BUILDER_SERVICE, SERVER_GROUP_COMMAND_REGISTRY_PROVIDER, SERVER_GROUP_CONFIGURATION_SERVICE, SERVER_GROUP_MANAGER_DATA_SOURCE, SERVER_GROUP_MANAGER_STATES, SERVER_GROUP_WRITER, SETTINGS, SLACK_COMPONENT, STAGE_ARTIFACT_SELECTOR_COMPONENT_REACT, STATE_CONFIG_PROVIDER, STATE_EVENTS, SchedulerFactory, ScopeClusterSelector, ScrollToService, Search, SearchFilterTypeRegistry, SearchResultType, SearchResultTypeRegistry, SearchResults, SearchService, SearchStatus, SearchTableBody, SearchTableHeader, SearchTableRow, SecurityGroupReader, SecurityGroupState, SecurityGroupWriter, SelectInput, SequenceAndBuildAndImages, ServerGroup$1 as ServerGroup, ServerGroupCommandBuilderService, ServerGroupCommandRegistry, ServerGroupConfigurationService, ServerGroupDetails, ServerGroupDetailsField, ServerGroupDetailsWrapper, ServerGroupHeader, ServerGroupManagerReader, ServerGroupManagerTag, ServerGroupNamePreview, ServerGroupReader, ServerGroupTemplates, ServerGroupWarningMessageService, ServerGroupWriter, ServiceAccountReader, ServicesReader, ShowUserData, SimpleSpelInput, SingleLineString, SlackReader, SortToggle, SpInput, SpanDropdownTrigger, SpelAwareInputMode, SpelInput, SpelNumberInput, SpelService, SpelText, SpelToggle, SpinErrorBoundary, SpinFormik, Spinner, StageArtifactSelector, StageArtifactSelectorDelegate, StageConfigField, StageConstants, StageExecutionLogs, StageFailureMessage, StageFailureMessages, StageSummary, StandardFieldLayout, StateConfigProvider, StateEvents, StorageAccountReader, StringsAsOptions, SubmitButton, SubnetReader, SubnetTag, TIME_FORMATTERS, TabBoundary, Table, TableCell, TableRow, Tag, TagList, TaskExecutor, TaskMatcher, TaskMonitor, TaskMonitorModal, TaskMonitorWrapper, TaskReader, TaskReason, TetheredCreatable, TetheredSelect, TextAreaInput, TextInput, TitusExecutionLogs, ToggleButtonGroup, ToggleSize, Tooltip, TriggerTemplate, Triggers$1 as Triggers, UI_ROUTER_REACT_ERROR_BOUNDARY, UUIDGenerator, UrlBuilder, UrlBuilderRegistry, UrlParser, UserMenu, UserVerification, V2ModalWizard, V2_MODAL_WIZARD_COMPONENT, VIEW_CHANGES_LINK, ValidationMessage, Validators, VersionChecker, ViewChangesLink, ViewScalingActivitiesLink, ViewStateCache, ViewStateCacheInternal, WatchValue, WizardModal, WizardPage, WizardStepLabel, WorkerPool, YAML_EDITOR_COMPONENT, YamlEditor, addManagedResourceMetadataToLoadBalancers, addManagedResourceMetadataToSecurityGroups, addManagedResourceMetadataToServerGroups, applySuspendedStatuses, arePropsEqual, asyncMessage, booleanParamType, categorizeValidationMessage, categorizeValidationMessages, categoryLabels, composeValidators, confirmNotManaged, createFakeReactSyntheticEvent, createFieldValidator, decodeUnicodeBase64, defaultExcludedArtifactTypes, digestDependentFilters, duration, errorMessage, evaluateExpression, excludeAllTypesExcept, filterModelConfig$1 as filterModelConfig, filterObjectValues, firstDefined, getBakedArtifacts, getContentReference, getGridColumnsStyle, getKindName, getResourceKindForLoadBalancerType, infoMessage, initialize, invalidContentMessage, inverseBooleanParamType, isStringArray, logger, makePreconfiguredJobStage, makeRequestBuilderConfig, messageMessage, minimalNativeTableLayout, navigationCategoryRegistry, noop, now, orEmptyString, overridableComponent, overrideRegistrationQueue, overridesComponent, parseSpelExpressions, reactSelectOnBlurAdapter, reactSelectOnChangeAdapter, reactSelectValidationErrorStyle, registerManagedDeliveryPlugin, registerPluginExtensions, relativeTime, renderContent, resourceManager, robotToHuman, robotToHumanFilter, searchResultTypeRegistry, setMatchingResourceSummary, showModal, sortKeyParamType, spelNumberCheck, standardGridTableLayout, successMessage, taskMatcher, timeDiffToString, timePickerTime, timestamp, toIPromise, toMarkdown, toggleResourcePause, traverseObject, trueKeyObjectParamType, useApplicationContext, useApplicationContextSafe, useContainerClassNames, useData, useDataSource, useDebouncedValue, useDeepObjectDiff, useEscapeKeyPressed, useEventListener, useForceUpdate, useFormInputValueMapper, useInternalValidator, useInterval, useIsMobile, useIsMountedRef, useLatestCallback, useLatestPromise, useMountStatusRef, useObservable, useObservableValue, usePollingData, usePrevious, useSaveRestoreMutuallyExclusiveFields, useValidationData, validationClassName, verticalNavExpandedAtom, warningMessage, withErrorBoundary, yamlDocumentsToString, yamlStringToDocuments };
72019
+ export { API, APPLICATION_STATE_PROVIDER, ARTIFACT_ACCOUNT_SELECTOR_COMPONENT_REACT, ARTIFACT_TYPE_EMBEDDED, ARTIFACT_TYPE_REMOTE, AccountCell, AccountSelectInput, AccountService, AccountTag, AddEntityTagLinks, Alerts, AngularJSAdapter, AppListExtractor, Application, ApplicationContext, ApplicationContextProvider, ApplicationDataSource, ApplicationDataSourceRegistry, ApplicationIcon, ApplicationModelBuilder, ApplicationNameValidator, ApplicationReader, ApplicationStateProvider, ApplicationWriter, Applications$1 as Applications, ApplicationsPickerInput, ArtifactAccountSelector, ArtifactIcon, ArtifactIconList, ArtifactIconService, ArtifactList, ArtifactReferenceService, ArtifactTypePatterns, AsgActionExecutionDetailsSection, AuthenticationInitializer, AuthenticationService, BakeExecutionLabel, BakeryReader, BannerContainer, BannerContainerContent, BaseBuildTriggerTemplate, BasicCell, BreakString, BuildServiceType, CACHE_INITIALIZER_SERVICE, CLUSTER_MATCHES_COMPONENT, CLUSTER_SERVICE, CONFIG_SECTION_FOOTER, CORE_MANAGED_MANAGED_MODULE, CORE_MODULE, CacheInitializerService, CapacityDetailsSection, CategorizedNotifications, CertificateReader, CheckboxInput, ChecklistInput, CloudMetricsReader, CloudProviderIcon, CloudProviderLabel, CloudProviderLogo, CloudProviderRegistry, ClusterFilterService, ClusterMatcher, ClusterMatches, ClusterPodTitleWrapper, ClusterService, ClusterState, ClusterTargetBuilder, Clusters, CollapsibleElement, CollapsibleSection, CollapsibleSectionStateCache, CollapsibleSectionStateCacheInternal, ConfigSectionFooter, ConfigSectionFooterController, ConfigureProjectModal, ConfirmationModalService, ConsoleOutputLink, CopyToClipboard, CoreModalInject, CoreReactInject, AdditionalFields$3 as CoreRedBlackAdditionalFields, CreateFunctionButton, CreateLoadBalancerButton, CreatePipelineModal, CurrentCapacity, CustomLabels, DELIVERY_KEY, DEPLOY_INITIALIZER_COMPONENT, DIFF_MODULE, DayPickerInput, DebugTiming, DebugTimingCumulative, DeckCacheFactory, DefaultClusterMatcher, DefaultPodNameProvider, DefaultSearchResultTab, DeleteType, DeployInitializer, DeployInitializerController, DeployingIntoManagedClusterWarning, DeploymentStrategyRegistrar, DeploymentStrategyRegistry, DeploymentStrategySelector, DeprecatedRequestBuilder, DesiredCapacity, Details, DiffView, EXECUTION_ARTIFACT_TAB, EXECUTION_DETAILS_SECTION_SERVICE, EXECUTION_SERVICE, EXPECTED_ARTIFACT_EDITOR_COMPONENT_REACT, EXPECTED_ARTIFACT_SELECTOR_COMPONENT_REACT, EXPECTED_ARTIFACT_SOURCE_SELECTOR_COMPONENT_REACT, EditNotificationModal, EntityName, EntityNotifications, EntitySource, EntityTagEditor, EntityTagWriter, EntityTagsReader, EventBus, Execution$1 as Execution, ExecutionArtifactTab, ExecutionBarLabel, ExecutionDetailsSection, ExecutionDetailsSectionNav, ExecutionDetailsSectionService, ExecutionDetailsTasks, ExecutionFilterModel, ExecutionMarkerIcon, ExecutionService, ExecutionState, ExecutionStepDetails, ExecutionsTransformer, ExpectedArtifactEditor, ExpectedArtifactModal, ExpectedArtifactSelector, ExpectedArtifactSelectorViewController, ExpectedArtifactService, ExpectedArtifactSourceSelector, ExpressionError, ExpressionInput, ExpressionPreview, FORM_VALIDATION_VALIDATABLE_FIELD_IS_VALID_SHORT_CIRCUIT, FUNCTION_READ_SERVICE, Feature, FeatureFlagsContext, FeaturesProvider, Filter, FilterCheckbox$1 as FilterCheckbox, FilterCollapse, FilterModelService, FilterSearch, FilterSection, FilterTags, FilterTypeRegistry, Filters$1 as Filters, FirewallLabels, FormField, FormValidator, FormValidatorField, FormikExpressionField, FormikExpressionRegexField, FormikForm, FormikFormField, FormikSpelContext, FormikSpelContextProvider, FormikStageConfig, FunctionDetails, FunctionReader, FunctionState, FunctionWriter, GlobalSearch, GroupedNotificationList, HeaderCell, Health, HealthCounts, HealthCountsCell, HelpContentsRegistry, HelpField, HelpMenu, HelpTextExpandedContext, HoverablePopover, HrefCell, IMAGE_READER, IMAGE_SOURCE_SELECTOR_COMPONENT, INFRASTRUCTURE_CACHE_CONFIG, INFRASTRUCTURE_KEY, INFRASTRUCTURE_SEARCH_SERVICE, INSTANCE_TYPE_SERVICE, IconTooltip, IfFeatureEnabled, IgorService, ImageList, ImageReader, InfrastructureCaches, InfrastructureCachesInternal, InfrastructureSearchService, InfrastructureSearcher, InstanceActions, InstanceDetails, InstanceDetailsCmp, InstanceDetailsHeader, InstanceDetailsPane, InstanceInsights, InstanceLinks, InstanceLoadBalancerHealth, InstanceReader, InstanceTypeService, InstanceWriter, InvalidAPIResponse, JobEventBasedPodNameProvider, JobManifestPodLogs, JobStageExecutionLogs, JsonEditor, JsonUtils, Key, LINK_WITH_CLIPBOARD, LOAD_BALANCER_READ_SERVICE, LabelComponent, LabeledValue, LabeledValueList, LayoutConsumer, LayoutContext, LayoutProvider, LinkWithClipboard, LoadBalancerClusterContainer, LoadBalancerDataUtils, LoadBalancerInstances, LoadBalancerReader, LoadBalancerServerGroup, LoadBalancerState, LoadBalancerWriter, LoadBalancers$2 as LoadBalancers, LoadBalancersTagWrapper, MANAGED_RESOURCES_DATA_SOURCE, MANAGED_RESOURCE_DETAILS_INDICATOR, ManagedMenuItem, ManagedReader, ManagedResourceDetailsIndicator, ManagedResourceStatus, ManagedResourceStatusIndicator, ManagedWriter, ManifestReader, ManifestWriter, ManifestYaml, ManualExecutionModal, MapEditor, MapEditorInput, MapPair, Markdown, MinMaxDesiredChanges, Modal, ModalBody, ModalClose, ModalFooter, ModalHeader, ModalInjector, ModalWizard, MultiSelectCheckbox, NOTIFICATION_LIST, NameUtils, NavigationCategoryRegistry, NetworkReader, NgAppEngineDeployArtifactDelegate, NgAppengineConfigArtifactDelegate, NgBakeManifestArtifactDelegate, NgGCEImageArtifactDelegate, NgGenericArtifactDelegate, NgReact, NgReactInjector, NotificationCategories, NotificationCategory, NotificationDetails$1 as NotificationDetails, NotificationList, NotificationSelector, NotificationTransformer, NotificationsList, NotifierService, NumberInput$1 as NumberInput, NumberList, OVERRIDE_REGISTRY, OrchestratedItemTransformer, Overridable, OverrideRegistry, Overrides, PAGER_DUTY_SELECT_FIELD_COMPONENT, PAGER_DUTY_TAG_COMPONENT, PAGE_TITLE_SERVICE, PLUGINS_MODULE, PRECONFIGUREDJOB_STAGE, PROVIDER_SERVICE_DELEGATE, PageNavigator, PageSection, PageTitleService, PagerDutyReader, PagerDutySelectFieldController, PagerDutyTagComponentController, PagerDutyWriter, PipelineConfigService, PipelineConfigValidator, PipelineRegistry, PipelineStageExecutionDetails, PipelineTemplateReader, PipelineTemplateV2Service, PipelineTemplates, Pipelines$1 as Pipelines, PlatformHealthOverride, PlatformHealthOverrideInput, PlatformHealthOverrideMessage, PluginRegistry, PreconfiguredJobExecutionDetails, PreconfiguredJobReader, PreconfiguredJobStageConfig, ProjectAttributes, ProjectHeader, ProjectReader, ProjectWriter, Projects, ProviderSelectionService, ProviderServiceDelegate, PubsubSubscriptionReader, REACT_MODULE, RECENT_HISTORY_SERVICE, RENDER_IF_FEATURE, REST, ROBOT_TO_HUMAN_FILTER, RadioButtonInput, ReactInject, ReactInjector, ReactModal, ReactSelectInput, RecentHistoryService, RegionSelectField, RegionSelectInput, RegistrationQueue, Registry, RenderOutputFile, RenderWhenVisible, RequestBuilder, ResponsiveFieldLayout, RetryService, RunAsUserInput, RunningTasks$1 as RunningTasks, SECURITY_GROUP_READER, SERVER_GROUP_COMMAND_BUILDER_SERVICE, SERVER_GROUP_COMMAND_REGISTRY_PROVIDER, SERVER_GROUP_CONFIGURATION_SERVICE, SERVER_GROUP_MANAGER_DATA_SOURCE, SERVER_GROUP_MANAGER_STATES, SERVER_GROUP_WRITER, SETTINGS, SLACK_COMPONENT, STAGE_ARTIFACT_SELECTOR_COMPONENT_REACT, STATE_CONFIG_PROVIDER, STATE_EVENTS, SchedulerFactory, ScopeClusterSelector, ScrollToService, Search, SearchFilterTypeRegistry, SearchResultType, SearchResultTypeRegistry, SearchResults, SearchService, SearchStatus, SearchTableBody, SearchTableHeader, SearchTableRow, SecurityGroupReader, SecurityGroupState, SecurityGroupWriter, SelectInput, SequenceAndBuildAndImages, ServerGroup$1 as ServerGroup, ServerGroupCommandBuilderService, ServerGroupCommandRegistry, ServerGroupConfigurationService, ServerGroupDetails, ServerGroupDetailsField, ServerGroupDetailsWrapper, ServerGroupHeader, ServerGroupManagerDetails, ServerGroupManagerReader, ServerGroupManagerTag, ServerGroupNamePreview, ServerGroupReader, ServerGroupTemplates, ServerGroupWarningMessageService, ServerGroupWriter, ServiceAccountReader, ServicesReader, ShowUserData, SimpleSpelInput, SingleLineString, SlackReader, SortToggle, SpInput, SpanDropdownTrigger, SpelAwareInputMode, SpelInput, SpelNumberInput, SpelService, SpelText, SpelToggle, SpinErrorBoundary, SpinFormik, Spinner, StageArtifactSelector, StageArtifactSelectorDelegate, StageConfigField, StageConstants, StageExecutionLogs, StageFailureMessage, StageFailureMessages, StageSummary, StandardFieldLayout, StateConfigProvider, StateEvents, StorageAccountReader, StringsAsOptions, SubmitButton, SubnetReader, SubnetTag, TIME_FORMATTERS, TabBoundary, Table, TableCell, TableRow, Tag, TagList, TaskExecutor, TaskMatcher, TaskMonitor, TaskMonitorModal, TaskMonitorWrapper, TaskReader, TaskReason, TetheredCreatable, TetheredSelect, TextAreaInput, TextInput, TitusExecutionLogs, ToggleButtonGroup, ToggleSize, Tooltip, TriggerTemplate, Triggers$1 as Triggers, UI_ROUTER_REACT_ERROR_BOUNDARY, UUIDGenerator, UrlBuilder, UrlBuilderRegistry, UrlParser, UserMenu, UserVerification, V2ModalWizard, V2_MODAL_WIZARD_COMPONENT, VIEW_CHANGES_LINK, ValidationMessage, Validators, VersionChecker, ViewChangesLink, ViewScalingActivitiesLink, ViewStateCache, ViewStateCacheInternal, WatchValue, WizardModal, WizardPage, WizardStepLabel, WorkerPool, YAML_EDITOR_COMPONENT, YamlEditor, addManagedResourceMetadataToLoadBalancers, addManagedResourceMetadataToSecurityGroups, addManagedResourceMetadataToServerGroups, applySuspendedStatuses, arePropsEqual, asyncMessage, booleanParamType, categorizeValidationMessage, categorizeValidationMessages, categoryLabels, composeValidators, confirmNotManaged, createFakeReactSyntheticEvent, createFieldValidator, decodeUnicodeBase64, defaultExcludedArtifactTypes, digestDependentFilters, duration, errorMessage, evaluateExpression, excludeAllTypesExcept, filterModelConfig$1 as filterModelConfig, filterObjectValues, firstDefined, getBakedArtifacts, getContentReference, getGridColumnsStyle, getKindName, getResourceKindForLoadBalancerType, infoMessage, initialize, invalidContentMessage, inverseBooleanParamType, isStringArray, logger, makePreconfiguredJobStage, makeRequestBuilderConfig, messageMessage, minimalNativeTableLayout, navigationCategoryRegistry, noop, now, orEmptyString, overridableComponent, overrideRegistrationQueue, overridesComponent, parseNum, parseSpelExpressions, reactSelectOnBlurAdapter, reactSelectOnChangeAdapter, reactSelectValidationErrorStyle, registerManagedDeliveryPlugin, registerPluginExtensions, relativeTime, renderContent, resourceManager, robotToHuman, robotToHumanFilter, searchResultTypeRegistry, setMatchingResourceSummary, showModal, sortKeyParamType, spelNumberCheck, standardGridTableLayout, successMessage, taskMatcher, timeDiffToString, timePickerTime, timestamp, toIPromise, toMarkdown, toggleResourcePause, traverseObject, trueKeyObjectParamType, useApplicationContext, useApplicationContextSafe, useContainerClassNames, useData, useDataSource, useDebouncedValue, useDeepObjectDiff, useEscapeKeyPressed, useEventListener, useFeature, useFeatures, useForceUpdate, useFormInputValueMapper, useInternalValidator, useInterval, useIsMobile, useIsMountedRef, useLatestCallback, useLatestPromise, useMountStatusRef, useObservable, useObservableValue, usePollingData, usePrevious, useSaveRestoreMutuallyExclusiveFields, useValidationData, validationClassName, verticalNavExpandedAtom, warningMessage, withErrorBoundary, withFeature, yamlDocumentsToString, yamlStringToDocuments };
71815
72020
  //# sourceMappingURL=index.js.map