iguazio.dashboard-controls 0.37.17 → 0.37.21

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 (21) hide show
  1. package/dist/i18n/en/common.json +1 -0
  2. package/dist/i18n/en/functions.json +2 -3
  3. package/dist/js/iguazio.dashboard-controls.js +9343 -9295
  4. package/dist/less/iguazio.dashboard-controls.less +3519 -3519
  5. package/package.json +1 -1
  6. package/src/i18n/en/common.json +1 -0
  7. package/src/i18n/en/functions.json +2 -3
  8. package/src/igz_controls/components/navigation-tabs/navigation-tabs.service.js +6 -5
  9. package/src/igz_controls/components/size/size.component.js +28 -6
  10. package/src/igz_controls/services/table-size.service.js +13 -9
  11. package/src/igz_controls/services/validation.service.js +10 -19
  12. package/src/nuclio/functions/function-collapsing-row/function-collapsing-row.component.js +2 -0
  13. package/src/nuclio/functions/function-collapsing-row/function-collapsing-row.tpl.html +14 -0
  14. package/src/nuclio/functions/function-collapsing-row/function-version-row/function-version-row.component.js +1 -0
  15. package/src/nuclio/functions/function-collapsing-row/function-version-row/function-version-row.tpl.html +13 -0
  16. package/src/nuclio/functions/functions.component.js +22 -0
  17. package/src/nuclio/functions/functions.service.js +1 -0
  18. package/src/nuclio/functions/functions.tpl.html +7 -0
  19. package/src/nuclio/functions/version/version-configuration/tabs/version-configuration-annotations/version-configuration-annotations.component.js +1 -1
  20. package/src/nuclio/functions/version/version-configuration/tabs/version-configuration-environment-variables/version-configuration-environment-variables.tpl.html +1 -1
  21. package/src/nuclio/functions/version/version.component.js +47 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iguazio.dashboard-controls",
3
- "version": "0.37.17",
3
+ "version": "0.37.21",
4
4
  "main": "dist/js/iguazio.dashboard-controls.js",
5
5
  "description": "Collection of resources (such as CSS styles, fonts and images) and AngularJs 1.x components and services to share among different Iguazio repos.",
6
6
  "repository": {
@@ -246,6 +246,7 @@
246
246
  "GET_VERSIONS": "Get versions",
247
247
  "GO_TO_CONTAINING_FOLDER": "Go to containing folder",
248
248
  "GPU": "GPU",
249
+ "GPU_CORES": "GPU (cores)",
249
250
  "GROUP": "Group",
250
251
  "GROUPS": "Groups",
251
252
  "GUIDE_SCREEN": "Guide Screen",
@@ -88,7 +88,6 @@
88
88
  "EDIT_PROJECT": "Edit Project",
89
89
  "ENDPOINT": "Endpoint",
90
90
  "ENTER_HOST_TO_SEE_ENDPOINT": "Enter host to see endpoint",
91
- "ENVIRONMENT_VARIABLES": "Environment Variables",
92
91
  "ERROR_MSG": {
93
92
  "COULD_NOT_READ_FILE": "Could not read file...",
94
93
  "CREATE_FUNCTION_EVENT": "Error occurred while creating the new function event.",
@@ -182,8 +181,7 @@
182
181
  "NO_LOGS_HAVE_BEEN_FOUND": "No logs have been found...",
183
182
  "NODE_SELECTORS": "Node selector",
184
183
  "NORMAL": "Normal",
185
- "NOT_START_WITH_FORBIDDEN_WORDS_ANNOTATION": "Must not start with 'kubernetes.io', 'k8s.io'",
186
- "NOT_START_WITH_FORBIDDEN_WORDS_LABEL": "Must not start with 'kubernetes.io', 'k8s.io' or 'nuclio.io'",
184
+ "NOT_START_WITH_FORBIDDEN_WORDS": "Must not start with 'kubernetes.io', 'k8s.io'",
187
185
  "NOT_YET_DEPLOYED": "Not yet deployed",
188
186
  "OAUTH2": "OAuth2",
189
187
  "ONBUILD_IMAGE": "Onbuild image",
@@ -378,6 +376,7 @@
378
376
  "UNSPECIFIED_FIELD_NAME": "Unspecified field name",
379
377
  "URL_NOT_EXPOSED": "URL not exposed",
380
378
  "V3IO": "V3IO",
379
+ "V3IO_INVALID_REPLICAS_MSG": "V3io_stream trigger requires min and max replicas to be the same",
381
380
  "VIEW_YAML": "View YAML",
382
381
  "VOLUMES": "Volumes",
383
382
  "ALWAYS_WAIT_FOR_READINESS_TIMEOUT_EXPIRATION": "Always wait for readiness-timeout expiration",
@@ -123,11 +123,6 @@
123
123
  tabName: $i18next.t('common:NODES', {lng: lng}),
124
124
  uiRoute: 'app.cluster.nodes',
125
125
  capability: 'clusters.nodes'
126
- },
127
- {
128
- tabName: $i18next.t('common:SUPPORT_LOGS', {lng: lng}),
129
- uiRoute: 'app.cluster.support-logs',
130
- capability: 'clusters.collectLogs'
131
126
  }
132
127
  ];
133
128
 
@@ -161,6 +156,12 @@
161
156
  id: 'app',
162
157
  uiRoute: 'app.clusters.app',
163
158
  capability: 'clusters'
159
+ },
160
+ {
161
+ tabName: $i18next.t('common:SUPPORT_LOGS', {lng: lng}),
162
+ id: 'support-logs',
163
+ uiRoute: 'app.clusters.support-logs',
164
+ capability: 'clusters.collectLogs'
164
165
  }
165
166
  ];
166
167
  }
@@ -1,4 +1,4 @@
1
- /* eslint complexity: ["error", 14] */
1
+ /* eslint complexity: ["error", 15] */
2
2
  (function () {
3
3
  'use strict';
4
4
 
@@ -32,6 +32,7 @@
32
32
 
33
33
  var CPU_TYPES = ['nodes', 'clusters'];
34
34
  var CPU_CORES_TYPES = ['services_cpu', 'functions_cpu'];
35
+ var GPU_CORES_TYPES = ['services_gpu', 'functions_gpu'];
35
36
  var SIZE_TYPES = ['containers', 'storage-pools', 'tenants', 'services_memory', 'functions_memory'];
36
37
  var COUNT_TYPES = ['functions_events'];
37
38
 
@@ -75,17 +76,19 @@
75
76
 
76
77
  ctrl.metricType = isCpu() ? 'cpuLineChartData' :
77
78
  isCpuCores() ? 'cpuCoresLineChartData' :
79
+ isGpuCores() ? 'gpuCoresLineChartData' :
78
80
  isSize() ? 'sizeLineChartData' :
79
81
  'countLineChartData' ;
80
82
 
81
83
  ctrl.displayValueWithTooltip = lodash.includes(['containers', 'tenants'], ctrl.type);
82
- ctrl.justDisplayValue = lodash.includes(['clusters', 'nodes', 'functions_cpu', 'functions_memory',
83
- 'functions_events', 'services_cpu', 'services_memory'], ctrl.type);
84
+ ctrl.justDisplayValue = lodash.includes(['clusters', 'nodes', 'functions_cpu', 'functions_gpu',
85
+ 'functions_memory', 'functions_events', 'services_cpu', 'services_gpu', 'services_memory'], ctrl.type);
84
86
 
85
87
  ctrl.displayValueClasses = {
86
88
  'short': lodash.includes(['functions_memory', 'services_memory'], ctrl.type),
87
89
  'shorten': lodash.includes(['functions_events'], ctrl.type),
88
- 'shortest': lodash.includes(['clusters', 'nodes', 'services_cpu', 'functions_cpu'], ctrl.type)
90
+ 'shortest': lodash.includes(['clusters', 'nodes', 'services_cpu', 'services_gpu', 'functions_cpu',
91
+ 'functions_gpu'], ctrl.type)
89
92
  };
90
93
 
91
94
  lodash.defaults(ctrl.entity.ui, {
@@ -367,6 +370,7 @@
367
370
  '0';
368
371
  var metricName = isCpu() ? 'cpu.idle' :
369
372
  isCpuCores() ? 'cpu.cores' :
373
+ isGpuCores() ? 'gpu.cores' :
370
374
  isSize() ? 'size' :
371
375
  'count';
372
376
  var value = ctrl.entity.ui.metrics[metricName];
@@ -375,7 +379,7 @@
375
379
 
376
380
  return lodash.isNil(value) ? defaultValue :
377
381
  isCpu() ? $filter('number')(value > 0 ? 100 - value : 0, 0) + '%' :
378
- isCpuCores() ? $filter('scale')(value, 0, 'nanos') :
382
+ (isCpuCores() || isGpuCores()) ? $filter('scale')(value, 0, 'nanos') :
379
383
  isSize() ? $filter('bytes')(value, 2) + sizePercentage :
380
384
  $filter('scale')(value);
381
385
  }
@@ -417,6 +421,14 @@
417
421
  return lodash.includes(CPU_CORES_TYPES, ctrl.type);
418
422
  }
419
423
 
424
+ /**
425
+ * Determines whether this chart is for GPU cores
426
+ * @returns {boolean} `true` if this chart is for GPU cores or `false` otherwise
427
+ */
428
+ function isGpuCores() {
429
+ return lodash.includes(GPU_CORES_TYPES, ctrl.type);
430
+ }
431
+
420
432
  /**
421
433
  * Defines if max quota value and max point in chart data has difference less than 20%
422
434
  * @returns {boolean}
@@ -443,7 +455,7 @@
443
455
  */
444
456
  function isTooltipEnabled() {
445
457
  return lodash.includes(['containers', 'storage-pools', 'tenants', 'services_memory', 'services_cpu',
446
- 'functions_memory', 'functions_cpu', 'functions_events'], ctrl.type);
458
+ 'services_gpu', 'functions_memory', 'functions_cpu', 'functions_gpu', 'functions_events'], ctrl.type);
447
459
  }
448
460
 
449
461
  /**
@@ -456,9 +468,11 @@
456
468
  'containers': prepareSizeData,
457
469
  'nodes': prepareCpuData,
458
470
  'functions_cpu': prepareCpuCoresData,
471
+ 'functions_gpu': prepareGpuCoresData,
459
472
  'functions_memory': prepareSizeData,
460
473
  'functions_events': prepareCountData,
461
474
  'services_cpu': prepareCpuData,
475
+ 'services_gpu': prepareGpuData,
462
476
  'services_memory': prepareSizeData,
463
477
  'storage-pools': prepareStoragePoolsData,
464
478
  'storage-pools_containers': prepareStoragePoolsContainersData,
@@ -475,6 +489,14 @@
475
489
  lodash.defaults(ctrl.entity.ui.metrics, {'cpu.cores': 0});
476
490
  }
477
491
 
492
+ function prepareGpuCoresData() {
493
+ lodash.defaults(ctrl.entity.ui.metrics, {'gpu.cores': 0});
494
+ }
495
+
496
+ function prepareGpuData() {
497
+ lodash.defaults(ctrl.entity.ui.metrics, {'gpu.idle': 0});
498
+ }
499
+
478
500
  function prepareSizeData() {
479
501
  lodash.defaults(ctrl.entity.ui.metrics, {size: 0});
480
502
  }
@@ -155,15 +155,15 @@
155
155
  };
156
156
  var functionsTableColSizes = {
157
157
  headerName: {
158
- default: '12-5',
158
+ default: '10',
159
159
  demo: '10'
160
160
  },
161
161
  rowName: {
162
- default: '12-5',
162
+ default: '10',
163
163
  demo: '10'
164
164
  },
165
165
  status: {
166
- default: '12-5',
166
+ default: '10',
167
167
  demo: '10'
168
168
  },
169
169
  replicas: {
@@ -183,16 +183,20 @@
183
183
  demo: '10'
184
184
  },
185
185
  cpuCores: {
186
- default: '15',
187
- demo: '15'
186
+ default: '12-5',
187
+ demo: '12-5'
188
188
  },
189
189
  metricsSize: {
190
- default: '15',
191
- demo: '15'
190
+ default: '12-5',
191
+ demo: '12-5'
192
+ },
193
+ gpuCores: {
194
+ default: '12-5',
195
+ demo: '12-5'
192
196
  },
193
197
  metricsCount: {
194
- default: '15',
195
- demo: '15'
198
+ default: '12-5',
199
+ demo: '12-5'
196
200
  }
197
201
  };
198
202
 
@@ -294,6 +294,12 @@
294
294
  $i18next.t('common:BEGIN_END_WITH', { lng: lng }) + ': a–z, 0–9',
295
295
  pattern: /^([a-z0-9]([^/]*[a-z0-9])?\/)?[^/]+$/
296
296
  },
297
+ {
298
+ name: 'prefixNotStart',
299
+ label: '[' + $i18next.t('functions:PREFIX', { lng: lng }) + '] ' +
300
+ $i18next.t('functions:NOT_START_WITH_FORBIDDEN_WORDS', { lng: lng }),
301
+ pattern: /^(?!kubernetes\.io\/)(?!k8s\.io\/)/
302
+ },
297
303
  {
298
304
  name: 'prefixMaxLength',
299
305
  label: '[' + $i18next.t('functions:PREFIX', { lng: lng }) + '] ' +
@@ -324,6 +330,7 @@
324
330
  generateRule.validCharacters('a-z A-Z 0-9 - _ .'),
325
331
  generateRule.beginNotWith('0-9 .')
326
332
  ],
333
+ prefixedQualifiedName: commonRules.prefixedQualifiedName,
327
334
  qualifiedName: [
328
335
  generateRule.validCharacters('a-z A-Z 0-9 - _ .'),
329
336
  generateRule.beginEndWith('a-z A-Z 0-9'),
@@ -351,25 +358,9 @@
351
358
  generateRule.length({ max: lengths.function.name })
352
359
  ),
353
360
  label: {
354
- key: commonRules.prefixedQualifiedName.concat(
355
- {
356
- name: 'prefixNotStart',
357
- label: '[' + $i18next.t('functions:PREFIX', {lng: lng}) + '] ' +
358
- $i18next.t('functions:NOT_START_WITH_FORBIDDEN_WORDS_LABEL', {lng: lng}),
359
- pattern: /^(?!kubernetes\.io\/)(?!k8s\.io\/)(?!nuclio\.io\/)/
360
- },
361
- generateRule.length({
362
- max: lengths.function.label.key
363
- }))
364
- },
365
- annotation: {
366
- key: commonRules.prefixedQualifiedName.concat(
367
- {
368
- name: 'prefixNotStart',
369
- label: '[' + $i18next.t('functions:PREFIX', {lng: lng}) + '] ' +
370
- $i18next.t('functions:NOT_START_WITH_FORBIDDEN_WORDS_ANNOTATION', {lng: lng}),
371
- pattern: /^(?!kubernetes\.io\/)(?!k8s\.io\/)/
372
- })
361
+ key: commonRules.prefixedQualifiedName.concat(generateRule.length({
362
+ max: lengths.function.label.key
363
+ }))
373
364
  },
374
365
  itemPath: [generateRule.length({ max: lengths.function.itemPath })],
375
366
  subscriptionQoS: [
@@ -36,6 +36,7 @@
36
36
  ctrl.functionActions = [];
37
37
  ctrl.functionNameTooltip = '';
38
38
  ctrl.isFunctionCollapsed = true;
39
+ ctrl.nuclioFunctionsGpu = encodeURI(FunctionsService.nuclioFunctionsGpu);
39
40
  ctrl.runtimes = {
40
41
  'golang': 'Go',
41
42
  'python:2.7': 'Python 2.7',
@@ -104,6 +105,7 @@
104
105
  metrics: {
105
106
  count: null,
106
107
  'cpu.idle': null,
108
+ 'gpu.idle': null,
107
109
  size: null
108
110
  }
109
111
  }
@@ -110,6 +110,20 @@
110
110
  </div>
111
111
  </igz-element-loading-status>
112
112
 
113
+ <igz-element-loading-status class="common-table-cell element-loading-status-wrapper"
114
+ data-name="{{$ctrl.nuclioFunctionsGpu}}-{{$ctrl.function.metadata.name}}"
115
+ data-loading-status-size="small"
116
+ data-ng-class="[$ctrl.getFunctionsTableColSize('gpuCores')]">
117
+ <igz-size data-ng-if="!$ctrl.function.ui.error[$ctrl.nuclioFunctionsGpu] && $ctrl.isFunctionCollapsed"
118
+ data-type="functions_gpu"
119
+ data-entity="$ctrl.function"
120
+ data-test-id="functions.item-gpu">
121
+ </igz-size>
122
+ <div data-ng-if="$ctrl.function.ui.error[$ctrl.nuclioFunctionsGpu] && $ctrl.isFunctionCollapsed">
123
+ {{$ctrl.function.ui.error[$ctrl.nuclioFunctionsGpu]}}
124
+ </div>
125
+ </igz-element-loading-status>
126
+
113
127
  <igz-element-loading-status class="common-table-cell element-loading-status-wrapper"
114
128
  data-name="nuclio_processor_handled_events_total-{{$ctrl.function.metadata.name}}"
115
129
  data-loading-status-size="small"
@@ -24,6 +24,7 @@
24
24
  var ctrl = this;
25
25
  var lng = i18next.language;
26
26
 
27
+ ctrl.nuclioFunctionsGpu = encodeURI(FunctionsService.nuclioFunctionsGpu);
27
28
  ctrl.versionActions = [];
28
29
  ctrl.runtimes = {
29
30
  'golang': 'Go',
@@ -70,6 +70,19 @@
70
70
  </div>
71
71
  </igz-element-loading-status>
72
72
 
73
+ <igz-element-loading-status class="common-table-cell element-loading-status-wrapper"
74
+ data-name="{{$ctrl.nuclioFunctionsGpu}}-{{$ctrl.function.metadata.name}}"
75
+ data-loading-status-size="small"
76
+ data-ng-class="[$ctrl.getFunctionsTableColSize('gpuCores')]">
77
+ <igz-size data-ng-if="!$ctrl.function.ui.error.kube_metrics_server_pods_gpu_utilization && !$ctrl.isFunctionCollapsed"
78
+ data-type="functions_gpu"
79
+ data-entity="$ctrl.function">
80
+ </igz-size>
81
+ <div data-ng-if="$ctrl.function.ui.error.kube_metrics_server_pods_gpu_utilization">
82
+ {{$ctrl.function.ui.error.kube_metrics_server_pods_gpu_utilization}}
83
+ </div>
84
+ </igz-element-loading-status>
85
+
73
86
  <igz-element-loading-status class="common-table-cell element-loading-status-wrapper"
74
87
  data-name="nuclio_processor_handled_events_total-{{$ctrl.function.metadata.name}}"
75
88
  data-loading-status-size="small"
@@ -33,6 +33,7 @@
33
33
 
34
34
  var METRICS = {
35
35
  FUNCTION_CPU: 'nuclio_function_cpu',
36
+ FUNCTION_GPU: encodeURI(FunctionsService.nuclioFunctionsGpu),
36
37
  FUNCTION_MEMORY: 'nuclio_function_mem',
37
38
  FUNCTION_EVENTS: 'nuclio_processor_handled_events_total'
38
39
  };
@@ -94,6 +95,11 @@
94
95
  value: 'ui.metrics.size',
95
96
  active: false
96
97
  },
98
+ {
99
+ label: $i18next.t('common:GPU_CORES', { lng: lng }),
100
+ value: 'ui.metrics[\'gpu.cores\']',
101
+ active: false
102
+ },
97
103
  {
98
104
  label: $i18next.t('functions:INVOCATION', { lng: lng }) + ' #',
99
105
  value: 'ui.metrics.count',
@@ -505,6 +511,7 @@
505
511
  if (!isRefresh) {
506
512
  $timeout(function () {
507
513
  hideSpinners(METRICS.FUNCTION_CPU);
514
+ hideSpinners(METRICS.FUNCTION_GPU);
508
515
  hideSpinners(METRICS.FUNCTION_MEMORY);
509
516
  hideSpinners(METRICS.FUNCTION_EVENTS);
510
517
  });
@@ -705,6 +712,11 @@
705
712
  .then(parseData.bind(null, args.metric))
706
713
  .catch(handleError.bind(null, args.metric));
707
714
 
715
+ args.metric = METRICS.FUNCTION_GPU;
716
+ ctrl.getStatistics(args)
717
+ .then(parseData.bind(null, args.metric))
718
+ .catch(handleError.bind(null, args.metric));
719
+
708
720
  args.metric = METRICS.FUNCTION_MEMORY;
709
721
  ctrl.getStatistics(args)
710
722
  .then(parseData.bind(null, args.metric))
@@ -821,6 +833,15 @@
821
833
  })
822
834
  }
823
835
  });
836
+ } else if (type === METRICS.FUNCTION_GPU) {
837
+ lodash.merge(aFunction.ui, {
838
+ metrics: {
839
+ 'gpu.cores': latestValue,
840
+ gpuCoresLineChartData: lodash.map(funcValues, function (dataPoint) {
841
+ return [dataPoint[0] * 1000, Number(dataPoint[1])]; // [time, value]
842
+ })
843
+ }
844
+ });
824
845
  } else { // type === METRICS.FUNCTION_COUNT
825
846
  lodash.merge(aFunction.ui, {
826
847
  metrics: {
@@ -838,6 +859,7 @@
838
859
 
839
860
  // if the column values have just been updated, and the table is sorted by this column - update sort
840
861
  if (type === METRICS.FUNCTION_CPU && ctrl.sortedColumnName === 'ui.metrics[\'cpu.cores\']' ||
862
+ type === METRICS.FUNCTION_GPU && ctrl.sortedColumnName === 'ui.metrics[\'gpu.cores\']' ||
841
863
  type === METRICS.FUNCTION_MEMORY && ctrl.sortedColumnName === 'ui.metrics.size' ||
842
864
  type === METRICS.FUNCTION_EVENTS &&
843
865
  lodash.includes(['ui.metrics.invocationPerSec', 'ui.metrics.count'], ctrl.sortedColumnName)) {
@@ -7,6 +7,7 @@
7
7
  function FunctionsService($i18next, i18next, lodash, ngDialog, ConfigService, DialogsService) {
8
8
  var self = {
9
9
  checkedItem: '',
10
+ nuclioFunctionsGpu: 'kube_metrics_server_pods_gpu_utilization * on (pod) group_left(function_name)(nuclio_function_pod_labels)',
10
11
  getClassesList: getClassesList,
11
12
  getHandler: getHandler,
12
13
  getDisplayStatus: getDisplayStatus,
@@ -127,6 +127,13 @@
127
127
  {{ 'common:MEMORY' | i18next }}
128
128
  <span class="sort-arrow"></span>
129
129
  </div>
130
+ <div class="common-table-cell sortable"
131
+ data-ng-class="[$ctrl.getColumnSortingClasses('ui.metrics[\'gpu.cores\']', $ctrl.sortedColumnName, $ctrl.isReverseSorting),
132
+ $ctrl.getFunctionsTableColSize('gpuCores')]"
133
+ data-ng-click="$ctrl.sortTableByColumn('ui.metrics[\'gpu.cores\']')">
134
+ {{ 'common:GPU_CORES' | i18next }}
135
+ <span class="sort-arrow"></span>
136
+ </div>
130
137
  <div class="common-table-cell sortable"
131
138
  data-ng-class="[$ctrl.getColumnSortingClasses('ui.metrics.count', $ctrl.sortedColumnName, $ctrl.isReverseSorting),
132
139
  $ctrl.getFunctionsTableColSize('metricsCount')]"
@@ -39,7 +39,7 @@
39
39
  name: $i18next.t('functions:TOOLTIP.ANNOTATION', { lng: lng })
40
40
  });
41
41
  ctrl.validationRules = {
42
- key: ValidationService.getValidationRules('function.annotation.key', [
42
+ key: ValidationService.getValidationRules('k8s.prefixedQualifiedName', [
43
43
  {
44
44
  name: 'uniqueness',
45
45
  label: $i18next.t('functions:UNIQUENESS', { lng: lng }),
@@ -1,5 +1,5 @@
1
1
  <div class="ncl-version-configuration-environment-variables">
2
- <div class="title">{{ 'functions:ENVIRONMENT_VARIABLES' | i18next }}</div>
2
+ <div class="title">{{ 'common:ENVIRONMENT_VARIABLES' | i18next }}</div>
3
3
  <form name="$ctrl.environmentVariablesForm" class="resources-wrapper" novalidate>
4
4
  <div class="igz-scrollable-container scrollable-environment-variables"
5
5
  data-ng-scrollbars
@@ -223,54 +223,61 @@
223
223
  */
224
224
  function deployButtonClick(event, version) {
225
225
  if (!ctrl.isDeployDisabled) {
226
- ctrl.isFunctionDeployed = false;
227
- $rootScope.$broadcast('deploy-function-version', { event: event });
228
-
229
226
  var versionCopy = lodash.omit(angular.isDefined(version) ? version : ctrl.version, ['status', 'ui']);
227
+ var isV3ioExists = Object.values(versionCopy.spec.triggers).find(function (trigger) {
228
+ return trigger.kind === 'v3ioStream'
229
+ });
230
230
 
231
- // set `nuclio.io/project-name` label to relate this function to its project
232
- lodash.set(versionCopy, ['metadata', 'labels', 'nuclio.io/project-name'], ctrl.project.metadata.name);
233
- lodash.set(versionCopy, 'spec.build.mode', 'alwaysBuild');
231
+ if (versionCopy.spec.maxReplicas !== versionCopy.spec.minReplicas && isV3ioExists) {
232
+ DialogsService.alert($i18next.t('functions:V3IO_INVALID_REPLICAS_MSG', {lng: lng}));
233
+ } else {
234
+ ctrl.isFunctionDeployed = false;
235
+ $rootScope.$broadcast('deploy-function-version', { event: event });
234
236
 
235
- ctrl.isTestResultShown = false;
236
- ctrl.deployResult.shown = false;
237
- ctrl.deployResult.collapsed = true;
238
- ctrl.isSplashShowed.value = true;
237
+ // set `nuclio.io/project-name` label to relate this function to its project
238
+ lodash.set(versionCopy, ['metadata', 'labels', 'nuclio.io/project-name'], ctrl.project.metadata.name);
239
+ lodash.set(versionCopy, 'spec.build.mode', 'alwaysBuild');
239
240
 
240
- var isVersionDeployed = VersionHelperService.isVersionDeployed(ctrl.version);
241
- var method = isVersionDeployed || ctrl.version.ui.overwrite ? ctrl.updateVersion : ctrl.createVersion;
241
+ ctrl.isTestResultShown = false;
242
+ ctrl.deployResult.shown = false;
243
+ ctrl.deployResult.collapsed = true;
244
+ ctrl.isSplashShowed.value = true;
242
245
 
243
- method({ version: versionCopy, projectId: ctrl.project.metadata.name })
244
- .then(function () {
245
- pollFunctionState();
246
+ var isVersionDeployed = VersionHelperService.isVersionDeployed(ctrl.version);
247
+ var method = isVersionDeployed || ctrl.version.ui.overwrite ? ctrl.updateVersion : ctrl.createVersion;
246
248
 
247
- $timeout(function () {
248
- $rootScope.$broadcast('igzWatchWindowResize::resize');
249
- });
250
- })
251
- .catch(function (error) {
252
- var defaultMsg = $i18next.t('common:ERROR_MSG.UNKNOWN_ERROR', { lng: lng });
253
-
254
- if (error.status === 409 && isVersionDeployed) {
255
- return FunctionsService.openVersionOverwriteDialog()
256
- .then(function () {
257
- deployButtonClick(event, lodash.omit(ctrl.version, 'metadata.resourceVersion'));
258
- })
259
- .catch(function () {
249
+ method({ version: versionCopy, projectId: ctrl.project.metadata.name })
250
+ .then(function () {
251
+ pollFunctionState();
252
+
253
+ $timeout(function () {
254
+ $rootScope.$broadcast('igzWatchWindowResize::resize');
255
+ });
256
+ })
257
+ .catch(function (error) {
258
+ var defaultMsg = $i18next.t('common:ERROR_MSG.UNKNOWN_ERROR', { lng: lng });
259
+
260
+ if (error.status === 409 && isVersionDeployed) {
261
+ return FunctionsService.openVersionOverwriteDialog()
262
+ .then(function () {
263
+ deployButtonClick(event, lodash.omit(ctrl.version, 'metadata.resourceVersion'));
264
+ })
265
+ .catch(function () {
266
+ ctrl.isFunctionDeployed = true;
267
+ });
268
+ } else if (error.status === 404 && method === ctrl.updateVersion) {
269
+ clearVersionStatus(ctrl.version);
270
+ return deployButtonClick(event, version);
271
+ } else {
272
+ return DialogsService.alert(lodash.get(error, 'data.error', defaultMsg)).then(function () {
260
273
  ctrl.isFunctionDeployed = true;
261
274
  });
262
- } else if (error.status === 404 && method === ctrl.updateVersion) {
263
- clearVersionStatus(ctrl.version);
264
- return deployButtonClick(event, version);
265
- } else {
266
- return DialogsService.alert(lodash.get(error, 'data.error', defaultMsg)).then(function () {
267
- ctrl.isFunctionDeployed = true;
268
- });
269
- }
270
- })
271
- .finally(function () {
272
- ctrl.isSplashShowed.value = false;
273
- });
275
+ }
276
+ })
277
+ .finally(function () {
278
+ ctrl.isSplashShowed.value = false;
279
+ });
280
+ }
274
281
  }
275
282
  }
276
283