@devtron-labs/devtron-fe-common-lib 0.0.33-beta-1 → 0.0.33-beta-4

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.
@@ -1,4 +1,4 @@
1
- import { TeamList, ResponseType, DeploymentNodeType } from './Types';
1
+ import { TeamList, ResponseType, DeploymentNodeType, CDMaterialServiceEnum, CDMaterialServiceQueryParams, CDMaterialResponseType } from './Types';
2
2
  export declare const getTeamListMin: () => Promise<TeamList>;
3
3
  interface UserRole extends ResponseType {
4
4
  result?: {
@@ -13,7 +13,7 @@ export declare const SourceTypeMap: {
13
13
  };
14
14
  export declare function getUserRole(appName?: string): Promise<UserRole>;
15
15
  export declare function setImageTags(request: any, pipelineId: number, artifactId: number): Promise<ResponseType>;
16
- export declare const getCDMaterials: (cdMaterialId: any, stageType: DeploymentNodeType, abortSignal: AbortSignal, isApprovalNode?: boolean, imageTag?: string) => Promise<any>;
16
+ export declare const genericCDMaterialsService: (serviceType: CDMaterialServiceEnum, cdMaterialID: number, stage: DeploymentNodeType, signal: AbortSignal, queryParams?: CDMaterialServiceQueryParams) => Promise<CDMaterialResponseType>;
17
17
  export declare function extractImage(image: string): string;
18
18
  export declare function createGitCommitUrl(url: string, revision: string): string;
19
19
  export {};
@@ -19,6 +19,7 @@ export declare const ROUTES: {
19
19
  PROJECT_LIST_MIN: string;
20
20
  USER_CHECK_ROLE: string;
21
21
  IMAGE_TAGGING: string;
22
+ CD_MATERIAL_GET: string;
22
23
  };
23
24
  export declare enum KEY_VALUE {
24
25
  KEY = "key",
@@ -223,6 +223,25 @@ export interface CDMaterialType {
223
223
  imageReleaseTags?: ReleaseTag[];
224
224
  artifactStatus?: string;
225
225
  filterState: FilterStates;
226
+ scanToolId?: number;
227
+ }
228
+ export declare enum CDMaterialServiceEnum {
229
+ ROLLBACK = "rollback",
230
+ CD_MATERIALS = "cd-materials"
231
+ }
232
+ export declare enum CDMaterialResourceQuery {
233
+ PENDING_APPROVAL = "PENDING_APPROVAL"
234
+ }
235
+ export declare enum CDMaterialFilterQuery {
236
+ RESOURCE = "ELIGIBLE_RESOURCES",
237
+ ALL = "ALL_RESOURCES"
238
+ }
239
+ export interface CDMaterialServiceQueryParams {
240
+ search?: string;
241
+ offset?: number;
242
+ size?: number;
243
+ resource?: CDMaterialResourceQuery;
244
+ filter?: CDMaterialFilterQuery;
226
245
  }
227
246
  export interface CommonNodeAttr {
228
247
  connectingCiPipelineId?: number;
@@ -329,16 +348,20 @@ export interface FilterConditionsListType {
329
348
  description: string;
330
349
  conditions: FilterConditionsInfo[];
331
350
  }
332
- export interface CDMaterialResponseType {
351
+ export interface CDMaterialsApprovalInfo {
333
352
  approvalUsers: string[];
334
- materials: any[];
335
353
  userApprovalConfig: UserApprovalConfigType;
336
354
  requestedUserId: number;
355
+ }
356
+ export interface CDMaterialsMetaInfo {
337
357
  tagsEditable: boolean;
338
358
  appReleaseTagNames: string[];
339
359
  hideImageTaggingHardDelete: boolean;
340
360
  resourceFilters?: FilterConditionsListType[];
341
361
  }
362
+ export interface CDMaterialResponseType extends CDMaterialsMetaInfo, CDMaterialsApprovalInfo {
363
+ materials: CDMaterialType[];
364
+ }
342
365
  export interface InputDetailType {
343
366
  label: string;
344
367
  defaultValue: string;
package/dist/index.js CHANGED
@@ -44,6 +44,7 @@ var ROUTES = {
44
44
  PROJECT_LIST_MIN: 'team/autocomplete',
45
45
  USER_CHECK_ROLE: 'user/check/roles',
46
46
  IMAGE_TAGGING: 'app/image-tagging',
47
+ CD_MATERIAL_GET: 'app/cd-pipeline'
47
48
  };
48
49
  exports.KEY_VALUE = void 0;
49
50
  (function (KEY_VALUE) {
@@ -430,6 +431,20 @@ exports.FilterStates = void 0;
430
431
  FilterStates[FilterStates["BLOCKED"] = 1] = "BLOCKED";
431
432
  FilterStates[FilterStates["ERROR"] = 2] = "ERROR";
432
433
  })(exports.FilterStates || (exports.FilterStates = {}));
434
+ exports.CDMaterialServiceEnum = void 0;
435
+ (function (CDMaterialServiceEnum) {
436
+ CDMaterialServiceEnum["ROLLBACK"] = "rollback";
437
+ CDMaterialServiceEnum["CD_MATERIALS"] = "cd-materials";
438
+ })(exports.CDMaterialServiceEnum || (exports.CDMaterialServiceEnum = {}));
439
+ exports.CDMaterialResourceQuery = void 0;
440
+ (function (CDMaterialResourceQuery) {
441
+ CDMaterialResourceQuery["PENDING_APPROVAL"] = "PENDING_APPROVAL";
442
+ })(exports.CDMaterialResourceQuery || (exports.CDMaterialResourceQuery = {}));
443
+ exports.CDMaterialFilterQuery = void 0;
444
+ (function (CDMaterialFilterQuery) {
445
+ CDMaterialFilterQuery["RESOURCE"] = "ELIGIBLE_RESOURCES";
446
+ CDMaterialFilterQuery["ALL"] = "ALL_RESOURCES";
447
+ })(exports.CDMaterialFilterQuery || (exports.CDMaterialFilterQuery = {}));
433
448
  exports.DeploymentAppTypes = void 0;
434
449
  (function (DeploymentAppTypes) {
435
450
  DeploymentAppTypes["HELM"] = "helm";
@@ -10076,7 +10091,7 @@ function CustomInput(_a) {
10076
10091
  return (jsxRuntime.jsxs("div", __assign({ className: "flex column left top" }, { children: [jsxRuntime.jsx("label", __assign({ className: "form__label ".concat(labelClassName) }, { children: label })), jsxRuntime.jsx("input", { "data-testid": dataTestid, type: type, name: name, autoComplete: "off", className: "form__input", onChange: function (e) {
10077
10092
  e.persist();
10078
10093
  onChange(e);
10079
- }, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, value: value, disabled: disabled, tabIndex: tabIndex }), handleError(error).map(function (err) { return (jsxRuntime.jsxs("div", __assign({ className: "form__error" }, { children: [jsxRuntime.jsx(SvgIcWarning, { className: "form__icon form__icon--error" }), err] }))); })] })));
10094
+ }, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, value: value, disabled: disabled, tabIndex: tabIndex }), handleError(error).map(function (err) { return (jsxRuntime.jsxs("div", __assign({ className: "form__error" }, { children: [jsxRuntime.jsx(SvgIcWarning, { className: "form__icon form__icon--error" }), err] }), err)); })] })));
10080
10095
  }
10081
10096
  function handleUTCTime(ts, isRelativeTime) {
10082
10097
  if (isRelativeTime === void 0) { isRelativeTime = false; }
@@ -22671,12 +22686,6 @@ var getTeamListMin = function () {
22671
22686
  };
22672
22687
  });
22673
22688
  };
22674
- var stageMap = {
22675
- PRECD: 'PRE',
22676
- CD: 'DEPLOY',
22677
- POSTCD: 'POST',
22678
- APPROVAL: 'APPROVAL',
22679
- };
22680
22689
  var SourceTypeMap = {
22681
22690
  BranchFixed: 'SOURCE_TYPE_BRANCH_FIXED',
22682
22691
  WEBHOOK: 'WEBHOOK',
@@ -22688,77 +22697,161 @@ function getUserRole(appName) {
22688
22697
  function setImageTags(request, pipelineId, artifactId) {
22689
22698
  return post("".concat(ROUTES.IMAGE_TAGGING, "/").concat(pipelineId, "/").concat(artifactId), request);
22690
22699
  }
22691
- // FIXME: This is only returning materials to cater the case of search in approval but it should be a common function service coming from dashboard.
22692
- var getCDMaterials = function (cdMaterialId, stageType, abortSignal, isApprovalNode, imageTag) {
22693
- var URL = (!imageTag) ? "app/cd-pipeline/".concat(cdMaterialId, "/material?stage=").concat(stageMap[stageType]) : "app/cd-pipeline/".concat(cdMaterialId, "/material?stage=").concat(stageMap[stageType], "&search=").concat(imageTag);
22694
- return get(URL, {
22695
- signal: abortSignal,
22696
- }).then(function (response) {
22700
+ var processURL = function (url, params) {
22701
+ var validParams = Object.keys(params).filter(function (key) {
22702
+ return params[key] != null;
22703
+ });
22704
+ if (!validParams.length) {
22705
+ return url;
22706
+ }
22707
+ var queryString = validParams
22708
+ .map(function (key) {
22709
+ if (Array.isArray(params[key])) {
22710
+ return "".concat(key, "=").concat(params[key].join(','));
22711
+ }
22712
+ return "".concat(key, "=").concat(params[key]);
22713
+ })
22714
+ .join('&');
22715
+ return "".concat(url, "?").concat(queryString);
22716
+ };
22717
+ var cdMaterialListModal = function (artifacts, offset, artifactId, artifactStatus) {
22718
+ if (!artifacts || !artifacts.length)
22719
+ return [];
22720
+ var markFirstSelected = offset === 1;
22721
+ var startIndex = offset - 1;
22722
+ var isImageMarked = false;
22723
+ var materials = artifacts.map(function (material, index) {
22697
22724
  var _a;
22698
- var artifacts = (_a = response.result.ci_artifacts) !== null && _a !== void 0 ? _a : [];
22699
- if (!response.result) {
22700
- return {
22701
- materials: [],
22702
- };
22725
+ var artifactStatusValue = '';
22726
+ var filterState = (_a = material.filterState) !== null && _a !== void 0 ? _a : exports.FilterStates.ALLOWED;
22727
+ if (artifactId && artifactStatus && material.id === artifactId) {
22728
+ artifactStatusValue = artifactStatus;
22703
22729
  }
22704
- else {
22705
- var materials = artifacts.map(function (material, index) {
22706
- var _a;
22707
- var artifactStatusValue = '';
22708
- var filterState = (_a = material.filterState) !== null && _a !== void 0 ? _a : exports.FilterStates.ALLOWED;
22709
- return {
22710
- index: index,
22711
- id: material.id,
22712
- deployedTime: material.deployed_time
22713
- ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
22714
- : 'Not Deployed',
22715
- deployedBy: material.deployedBy,
22716
- wfrId: material.wfrId,
22717
- image: extractImage(material.image),
22718
- showChanges: false,
22719
- vulnerabilities: [],
22720
- buildTime: material.build_time || '',
22721
- tab: CDModalTab.Changes,
22722
- showSourceInfo: false,
22723
- deployed: material.deployed || false,
22724
- latest: material.latest || false,
22725
- vulnerabilitiesLoading: true,
22726
- scanned: material.scanned,
22727
- scanEnabled: material.scanEnabled,
22728
- isSelected: !material.vulnerable && filterState === exports.FilterStates.ALLOWED && index === 0,
22729
- vulnerable: material.vulnerable,
22730
- runningOnParentCd: material.runningOnParentCd,
22731
- artifactStatus: artifactStatusValue,
22732
- userApprovalMetadata: material.userApprovalMetadata,
22733
- triggeredBy: material.triggeredBy,
22734
- isVirtualEnvironment: material.isVirtualEnvironment,
22735
- imageComment: material.imageComment,
22736
- imageReleaseTags: material.imageReleaseTags,
22737
- materialInfo: material.material_info
22738
- ? material.material_info.map(function (mat) {
22739
- return {
22740
- modifiedTime: mat.modifiedTime ? moment(mat.modifiedTime).format("ddd, DD MMM YYYY, hh:mm A") : '',
22741
- commitLink: createGitCommitUrl(mat.url, mat.revision),
22742
- author: mat.author || '',
22743
- message: mat.message || '',
22744
- revision: mat.revision || '',
22745
- tag: mat.tag || '',
22746
- webhookData: mat.webhookData || '',
22747
- url: mat.url || '',
22748
- branch: (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
22749
- ? material.ciConfigureSourceValue
22750
- : mat.branch) || '',
22751
- type: material.ciConfigureSourceType || '',
22752
- };
22753
- })
22754
- : [],
22755
- filterState: filterState,
22756
- };
22757
- });
22758
- return {
22759
- materials: materials
22760
- };
22730
+ var selectImage = !isImageMarked && markFirstSelected && filterState === exports.FilterStates.ALLOWED ? !material.vulnerable : false;
22731
+ if (selectImage) {
22732
+ isImageMarked = true;
22761
22733
  }
22734
+ return {
22735
+ index: startIndex + index,
22736
+ id: material.id,
22737
+ deployedTime: material.deployed_time
22738
+ ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
22739
+ : 'Not Deployed',
22740
+ deployedBy: material.deployedBy,
22741
+ wfrId: material.wfrId,
22742
+ tab: CDModalTab.Changes,
22743
+ image: extractImage(material.image),
22744
+ showChanges: false,
22745
+ vulnerabilities: [],
22746
+ buildTime: material.build_time || '',
22747
+ isSelected: selectImage,
22748
+ showSourceInfo: false,
22749
+ deployed: material.deployed || false,
22750
+ latest: material.latest || false,
22751
+ vulnerabilitiesLoading: true,
22752
+ scanned: material.scanned,
22753
+ scanEnabled: material.scanEnabled,
22754
+ vulnerable: material.vulnerable,
22755
+ runningOnParentCd: material.runningOnParentCd,
22756
+ artifactStatus: artifactStatusValue,
22757
+ userApprovalMetadata: material.userApprovalMetadata,
22758
+ triggeredBy: material.triggeredBy,
22759
+ isVirtualEnvironment: material.isVirtualEnvironment,
22760
+ imageComment: material.imageComment,
22761
+ imageReleaseTags: material.imageReleaseTags,
22762
+ // It is going to be null but required in type so can't remove
22763
+ lastExecution: material.lastExecution,
22764
+ materialInfo: material.material_info
22765
+ ? material.material_info.map(function (mat) {
22766
+ return {
22767
+ modifiedTime: mat.modifiedTime
22768
+ ? moment(mat.modifiedTime).format('ddd, DD MMM YYYY, hh:mm A')
22769
+ : '',
22770
+ commitLink: createGitCommitUrl(mat.url, mat.revision),
22771
+ author: mat.author || '',
22772
+ message: mat.message || '',
22773
+ revision: mat.revision || '',
22774
+ tag: mat.tag || '',
22775
+ webhookData: mat.webhookData || '',
22776
+ url: mat.url || '',
22777
+ branch: (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
22778
+ ? material.ciConfigureSourceValue
22779
+ : mat.branch) || '',
22780
+ type: material.ciConfigureSourceType || '',
22781
+ };
22782
+ })
22783
+ : [],
22784
+ filterState: filterState,
22785
+ };
22786
+ });
22787
+ return materials;
22788
+ };
22789
+ var processCDMaterialsApprovalInfo = function (enableApproval, cdMaterialsResult) {
22790
+ if (!enableApproval) {
22791
+ return {
22792
+ approvalUsers: [],
22793
+ userApprovalConfig: null,
22794
+ requestedUserId: 0,
22795
+ };
22796
+ }
22797
+ return {
22798
+ approvalUsers: cdMaterialsResult.approvalUsers,
22799
+ userApprovalConfig: cdMaterialsResult.userApprovalConfig,
22800
+ requestedUserId: cdMaterialsResult.requestedUserId,
22801
+ };
22802
+ };
22803
+ var processCDMaterialsMetaInfo = function (cdMaterialsResult) {
22804
+ var _a;
22805
+ if (!cdMaterialsResult) {
22806
+ return {
22807
+ tagsEditable: false,
22808
+ appReleaseTagNames: [],
22809
+ hideImageTaggingHardDelete: false,
22810
+ resourceFilters: [],
22811
+ };
22812
+ }
22813
+ return {
22814
+ appReleaseTagNames: cdMaterialsResult.appReleaseTagNames,
22815
+ tagsEditable: cdMaterialsResult.tagsEditable,
22816
+ hideImageTaggingHardDelete: cdMaterialsResult.hideImageTaggingHardDelete,
22817
+ resourceFilters: (_a = cdMaterialsResult.resourceFilters) !== null && _a !== void 0 ? _a : [],
22818
+ };
22819
+ };
22820
+ var processCDMaterialServiceResponse = function (cdMaterialsResult, stage, offset, filter) {
22821
+ if (!cdMaterialsResult) {
22822
+ return __assign(__assign({ materials: [] }, processCDMaterialsMetaInfo(cdMaterialsResult)), processCDMaterialsApprovalInfo(false, cdMaterialsResult));
22823
+ }
22824
+ var materials = cdMaterialListModal(cdMaterialsResult.ci_artifacts, offset !== null && offset !== void 0 ? offset : 1, cdMaterialsResult.latest_wf_artifact_id, cdMaterialsResult.latest_wf_artifact_status);
22825
+ var approvalInfo = processCDMaterialsApprovalInfo(stage === exports.DeploymentNodeType.CD || stage === exports.DeploymentNodeType.APPROVAL, cdMaterialsResult);
22826
+ var metaInfo = processCDMaterialsMetaInfo(cdMaterialsResult);
22827
+ // TODO: On update of service would remove from here
22828
+ var filteredMaterials = filter && filter === exports.CDMaterialFilterQuery.RESOURCE
22829
+ ? materials.filter(function (material) {
22830
+ return material.filterState === exports.FilterStates.ALLOWED;
22831
+ })
22832
+ : materials;
22833
+ return __assign(__assign({ materials: filteredMaterials }, approvalInfo), metaInfo);
22834
+ };
22835
+ var getSanitizedQueryParams = function (queryParams) {
22836
+ queryParams.filter; var rest = __rest(queryParams, ["filter"]);
22837
+ return rest;
22838
+ };
22839
+ var genericCDMaterialsService = function (serviceType, cdMaterialID, stage, signal, queryParams) {
22840
+ if (queryParams === void 0) { queryParams = {}; }
22841
+ // TODO: On update of service would remove from here
22842
+ var manipulatedParams = getSanitizedQueryParams(queryParams);
22843
+ var URL;
22844
+ switch (serviceType) {
22845
+ case exports.CDMaterialServiceEnum.ROLLBACK:
22846
+ URL = processURL("".concat(ROUTES.CD_MATERIAL_GET, "/").concat(cdMaterialID, "/material/rollback"), manipulatedParams);
22847
+ break;
22848
+ // Meant for handling getCDMaterialList
22849
+ default:
22850
+ URL = processURL("".concat(ROUTES.CD_MATERIAL_GET, "/").concat(cdMaterialID, "/material"), __assign(__assign({}, manipulatedParams), { stage: stage }));
22851
+ break;
22852
+ }
22853
+ return get(URL, { signal: signal }).then(function (response) {
22854
+ return processCDMaterialServiceResponse(response.result, stage, manipulatedParams.offset, manipulatedParams.filter);
22762
22855
  });
22763
22856
  };
22764
22857
  function extractImage(image) {
@@ -23140,6 +23233,7 @@ var ImageTagsContainer = function (_a) {
23140
23233
  var _o = __read(React.useState(false), 2), isSuperAdmin = _o[0], setSuperAdmin = _o[1];
23141
23234
  var _p = __read(React.useState(''), 2), descriptionValidationMessage = _p[0], setDescriptionValidationMessage = _p[1];
23142
23235
  var _q = __read(React.useState(''), 2), textInput = _q[0], setTextInput = _q[1];
23236
+ var _r = __read(React.useState(false), 2), loading = _r[0], setLoading = _r[1];
23143
23237
  React.useEffect(function () {
23144
23238
  initialise();
23145
23239
  }, []);
@@ -23313,6 +23407,7 @@ var ImageTagsContainer = function (_a) {
23313
23407
  hardDeleteTags: hardDeleteTags,
23314
23408
  };
23315
23409
  // set loading state true
23410
+ setLoading(true);
23316
23411
  setImageTags(payload, ciPipelineId, artifactId)
23317
23412
  .then(function (res) {
23318
23413
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
@@ -23352,6 +23447,9 @@ var ImageTagsContainer = function (_a) {
23352
23447
  else {
23353
23448
  showError(err);
23354
23449
  }
23450
+ })
23451
+ .finally(function () {
23452
+ setLoading(false);
23355
23453
  });
23356
23454
  return [2 /*return*/];
23357
23455
  });
@@ -23402,10 +23500,10 @@ var ImageTagsContainer = function (_a) {
23402
23500
  }, tagId: tag.id, softDeleteTags: softDeleteTags, isSuperAdmin: isSuperAdmin, duplicateTag: tag === null || tag === void 0 ? void 0 : tag.duplicateTag, hideHardDelete: hideHardDelete }, tag.id)); }) })), showTagsWarning && (jsxRuntime.jsxs("div", __assign({ className: "cn-7 mb-8 flex left" }, { children: [jsxRuntime.jsx(SvgIcInfoFilled, { className: "form__icon--info icon-dim-16 mr-2" }), "Tags cannot be edited/removed later"] }))), jsxRuntime.jsx("div", __assign({ className: "cn-7 mt-12" }, { children: "Comment" })), jsxRuntime.jsx("div", __assign({ className: "flex left flex-wrap dc__gap-8 w-100 mt-6 mb-12", "data-testid": "add-image-comment-text-area" }, { children: jsxRuntime.jsx("textarea", { value: newDescription, onChange: handleDescriptionChange, className: "flex left flex-wrap dc__gap-8 dc__description-textarea fs-13", style: { height: '90px !important' } }) })), descriptionValidationMessage !== '' && (jsxRuntime.jsxs("div", __assign({ className: "flex left" }, { children: [jsxRuntime.jsx(SvgIcWarning, { className: "form__icon form__icon--error" }), jsxRuntime.jsx("div", __assign({ className: "form__error" }, { children: descriptionValidationMessage }))] }))), jsxRuntime.jsxs("div", __assign({ className: "w-100 flex right mt-12" }, { children: [jsxRuntime.jsx("button", __assign({ className: "cta flex cancel h-32 lh-32-imp", type: "button", onClick: function (e) {
23403
23501
  stopPropagation(e);
23404
23502
  handleCancel();
23405
- } }, { children: "Cancel" })), jsxRuntime.jsx("button", __assign({ className: "cta flex h-32 lh-32-imp ml-12", "data-testid": "save-tags-button", type: "button", onClick: function (e) {
23503
+ }, disabled: loading }, { children: "Cancel" })), jsxRuntime.jsx("button", __assign({ className: "cta flex h-32 lh-32-imp ml-12", "data-testid": "save-tags-button", type: "button", onClick: function (e) {
23406
23504
  stopPropagation(e);
23407
23505
  onClickSave();
23408
- } }, { children: "Save" }))] }))] }))) : (jsxRuntime.jsxs("div", __assign({ className: "top br-4 bcn-0 image-tags-container flexbox" }, { children: [jsxRuntime.jsx("div", __assign({ className: "flex left image-tag-left-border w-100 mt-8 mb-8 pr-10 pl-10", "data-testid": "image-tags-container-hover" }, { children: jsxRuntime.jsxs("div", __assign({ className: 'w-100' }, { children: [initialDescription && jsxRuntime.jsx("div", __assign({ className: "mb-6 fs-13 lh-20 dc__word-break-all" }, { children: initialDescription })), jsxRuntime.jsx("div", __assign({ className: "flex-wrap flex left" }, { children: initialTags === null || initialTags === void 0 ? void 0 : initialTags.map(function (tag, index) { return (jsxRuntime.jsx(ImageTagButton, { text: tag === null || tag === void 0 ? void 0 : tag.tagName, isSoftDeleted: tag === null || tag === void 0 ? void 0 : tag.deleted, isEditing: isEditing, onSoftDeleteClick: function (e) {
23506
+ }, disabled: loading }, { children: loading ? jsxRuntime.jsx(Progressing, {}) : 'Save' }))] }))] }))) : (jsxRuntime.jsxs("div", __assign({ className: "top br-4 bcn-0 image-tags-container flexbox" }, { children: [jsxRuntime.jsx("div", __assign({ className: "flex left image-tag-left-border w-100 mt-8 mb-8 pr-10 pl-10", "data-testid": "image-tags-container-hover" }, { children: jsxRuntime.jsxs("div", __assign({ className: 'w-100' }, { children: [initialDescription && jsxRuntime.jsx("div", __assign({ className: "mb-6 fs-13 lh-20 dc__word-break-all" }, { children: initialDescription })), jsxRuntime.jsx("div", __assign({ className: "flex-wrap flex left" }, { children: initialTags === null || initialTags === void 0 ? void 0 : initialTags.map(function (tag, index) { return (jsxRuntime.jsx(ImageTagButton, { text: tag === null || tag === void 0 ? void 0 : tag.tagName, isSoftDeleted: tag === null || tag === void 0 ? void 0 : tag.deleted, isEditing: isEditing, onSoftDeleteClick: function (e) {
23409
23507
  stopPropagation(e);
23410
23508
  handleTagSoftDelete(index);
23411
23509
  }, onHardDeleteClick: function (e) {
@@ -23690,9 +23788,9 @@ exports.closeOnEscKeyPressed = closeOnEscKeyPressed;
23690
23788
  exports.copyToClipboard = copyToClipboard;
23691
23789
  exports.createGitCommitUrl = createGitCommitUrl;
23692
23790
  exports.extractImage = extractImage;
23791
+ exports.genericCDMaterialsService = genericCDMaterialsService;
23693
23792
  exports.get = get;
23694
23793
  exports.getAlphabetIcon = getAlphabetIcon;
23695
- exports.getCDMaterials = getCDMaterials;
23696
23794
  exports.getCookie = getCookie;
23697
23795
  exports.getEmptyArrayOfLength = getEmptyArrayOfLength;
23698
23796
  exports.getLoginInfo = getLoginInfo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.33-beta-1",
3
+ "version": "0.0.33-beta-4",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -2,7 +2,20 @@ import moment from 'moment';
2
2
  import {get, post} from './Api';
3
3
  import { ROUTES } from './Constants'
4
4
  import { sortCallback } from './Helper';
5
- import { TeamList ,ResponseType, DeploymentNodeType, CDModalTab, FilterStates } from './Types';
5
+ import {
6
+ TeamList,
7
+ ResponseType,
8
+ DeploymentNodeType,
9
+ CDModalTab,
10
+ FilterStates,
11
+ CDMaterialServiceEnum,
12
+ CDMaterialServiceQueryParams,
13
+ CDMaterialResponseType,
14
+ CDMaterialsMetaInfo,
15
+ CDMaterialsApprovalInfo,
16
+ CDMaterialFilterQuery,
17
+ CDMaterialType,
18
+ } from './Types'
6
19
 
7
20
  export const getTeamListMin = (): Promise<TeamList> => {
8
21
  // ignore active field
@@ -51,83 +64,209 @@ export function setImageTags(request, pipelineId: number, artifactId: number){
51
64
  return post(`${ROUTES.IMAGE_TAGGING}/${pipelineId}/${artifactId}`,request )
52
65
  }
53
66
 
54
- // FIXME: This is only returning materials to cater the case of search in approval but it should be a common function service coming from dashboard.
55
- export const getCDMaterials = (
56
- cdMaterialId,
57
- stageType: DeploymentNodeType,
58
- abortSignal: AbortSignal,
59
- isApprovalNode?: boolean,
60
- imageTag?: string): Promise<any> => {
61
- const URL = (!imageTag) ? `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}` : `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}&search=${imageTag}`
62
-
63
- return get(URL, {
64
- signal: abortSignal,
65
- }).then((response) => {
66
- let artifacts = response.result.ci_artifacts ?? []
67
- if (!response.result) {
68
- return {
69
- materials: [],
67
+ const processURL = (url: string, params: object) => {
68
+ const validParams = Object.keys(params).filter((key) => {
69
+ return params[key] != null
70
+ })
71
+
72
+ if (!validParams.length) {
73
+ return url
74
+ }
75
+
76
+ const queryString = validParams
77
+ .map((key) => {
78
+ if (Array.isArray(params[key])) {
79
+ return `${key}=${params[key].join(',')}`
70
80
  }
81
+ return `${key}=${params[key]}`
82
+ })
83
+ .join('&')
84
+
85
+ return `${url}?${queryString}`
86
+ }
87
+
88
+ const cdMaterialListModal = (artifacts: any[], offset: number, artifactId?: number, artifactStatus?: string) => {
89
+ if (!artifacts || !artifacts.length) return []
90
+
91
+ const markFirstSelected = offset === 1
92
+ const startIndex = offset - 1
93
+ let isImageMarked = false
94
+
95
+ const materials: CDMaterialType[] = artifacts.map((material, index) => {
96
+ let artifactStatusValue = ''
97
+ const filterState = material.filterState ?? FilterStates.ALLOWED
98
+
99
+ if (artifactId && artifactStatus && material.id === artifactId) {
100
+ artifactStatusValue = artifactStatus
71
101
  }
72
- else {
73
- const materials = artifacts.map((material, index) => {
74
- let artifactStatusValue = ''
75
- const filterState = material.filterState ?? FilterStates.ALLOWED
76
-
77
- return {
78
- index,
79
- id: material.id,
80
- deployedTime: material.deployed_time
81
- ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
82
- : 'Not Deployed',
83
- deployedBy: material.deployedBy,
84
- wfrId: material.wfrId,
85
- image: extractImage(material.image),
86
- showChanges: false,
87
- vulnerabilities: [],
88
- buildTime: material.build_time || '',
89
- tab: CDModalTab.Changes,
90
- showSourceInfo: false,
91
- deployed: material.deployed || false,
92
- latest: material.latest || false,
93
- vulnerabilitiesLoading: true,
94
- scanned: material.scanned,
95
- scanEnabled: material.scanEnabled,
96
- isSelected: !material.vulnerable && filterState === FilterStates.ALLOWED && index === 0,
97
- vulnerable: material.vulnerable,
98
- runningOnParentCd: material.runningOnParentCd,
99
- artifactStatus: artifactStatusValue,
100
- userApprovalMetadata: material.userApprovalMetadata,
101
- triggeredBy: material.triggeredBy,
102
- isVirtualEnvironment: material.isVirtualEnvironment,
103
- imageComment: material.imageComment,
104
- imageReleaseTags: material.imageReleaseTags,
105
- materialInfo: material.material_info
106
- ? material.material_info.map((mat) => {
107
- return {
108
- modifiedTime: mat.modifiedTime ? moment(mat.modifiedTime).format("ddd, DD MMM YYYY, hh:mm A") : '',
109
- commitLink: createGitCommitUrl(mat.url, mat.revision),
110
- author: mat.author || '',
111
- message: mat.message || '',
112
- revision: mat.revision || '',
113
- tag: mat.tag || '',
114
- webhookData: mat.webhookData || '',
115
- url: mat.url || '',
116
- branch:
117
- (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
118
- ? material.ciConfigureSourceValue
119
- : mat.branch) || '',
120
- type: material.ciConfigureSourceType || '',
121
- }
122
- })
123
- : [],
124
- filterState,
125
- }
126
- })
127
- return {
128
- materials: materials
129
- }
102
+
103
+ const selectImage =
104
+ !isImageMarked && markFirstSelected && filterState === FilterStates.ALLOWED ? !material.vulnerable : false
105
+ if (selectImage) {
106
+ isImageMarked = true
107
+ }
108
+
109
+ return {
110
+ index: startIndex + index,
111
+ id: material.id,
112
+ deployedTime: material.deployed_time
113
+ ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
114
+ : 'Not Deployed',
115
+ deployedBy: material.deployedBy,
116
+ wfrId: material.wfrId,
117
+ tab: CDModalTab.Changes,
118
+ image: extractImage(material.image),
119
+ showChanges: false,
120
+ vulnerabilities: [],
121
+ buildTime: material.build_time || '',
122
+ isSelected: selectImage,
123
+ showSourceInfo: false,
124
+ deployed: material.deployed || false,
125
+ latest: material.latest || false,
126
+ vulnerabilitiesLoading: true,
127
+ scanned: material.scanned,
128
+ scanEnabled: material.scanEnabled,
129
+ vulnerable: material.vulnerable,
130
+ runningOnParentCd: material.runningOnParentCd,
131
+ artifactStatus: artifactStatusValue,
132
+ userApprovalMetadata: material.userApprovalMetadata,
133
+ triggeredBy: material.triggeredBy,
134
+ isVirtualEnvironment: material.isVirtualEnvironment,
135
+ imageComment: material.imageComment,
136
+ imageReleaseTags: material.imageReleaseTags,
137
+ // It is going to be null but required in type so can't remove
138
+ lastExecution: material.lastExecution,
139
+ materialInfo: material.material_info
140
+ ? material.material_info.map((mat) => {
141
+ return {
142
+ modifiedTime: mat.modifiedTime
143
+ ? moment(mat.modifiedTime).format('ddd, DD MMM YYYY, hh:mm A')
144
+ : '',
145
+ commitLink: createGitCommitUrl(mat.url, mat.revision),
146
+ author: mat.author || '',
147
+ message: mat.message || '',
148
+ revision: mat.revision || '',
149
+ tag: mat.tag || '',
150
+ webhookData: mat.webhookData || '',
151
+ url: mat.url || '',
152
+ branch:
153
+ (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
154
+ ? material.ciConfigureSourceValue
155
+ : mat.branch) || '',
156
+ type: material.ciConfigureSourceType || '',
157
+ }
158
+ })
159
+ : [],
160
+ filterState,
161
+ }
162
+ })
163
+ return materials
164
+ }
165
+
166
+ const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResult): CDMaterialsApprovalInfo => {
167
+ if (!enableApproval) {
168
+ return {
169
+ approvalUsers: [],
170
+ userApprovalConfig: null,
171
+ requestedUserId: 0,
172
+ }
173
+ }
174
+
175
+ return {
176
+ approvalUsers: cdMaterialsResult.approvalUsers,
177
+ userApprovalConfig: cdMaterialsResult.userApprovalConfig,
178
+ requestedUserId: cdMaterialsResult.requestedUserId,
179
+ }
180
+ }
181
+
182
+ const processCDMaterialsMetaInfo = (cdMaterialsResult): CDMaterialsMetaInfo => {
183
+ if (!cdMaterialsResult) {
184
+ return {
185
+ tagsEditable: false,
186
+ appReleaseTagNames: [],
187
+ hideImageTaggingHardDelete: false,
188
+ resourceFilters: [],
130
189
  }
190
+ }
191
+
192
+ return {
193
+ appReleaseTagNames: cdMaterialsResult.appReleaseTagNames,
194
+ tagsEditable: cdMaterialsResult.tagsEditable,
195
+ hideImageTaggingHardDelete: cdMaterialsResult.hideImageTaggingHardDelete,
196
+ resourceFilters: cdMaterialsResult.resourceFilters ?? [],
197
+ }
198
+ }
199
+
200
+ const processCDMaterialServiceResponse = (
201
+ cdMaterialsResult,
202
+ stage: DeploymentNodeType,
203
+ offset: number,
204
+ filter: CDMaterialFilterQuery,
205
+ ): CDMaterialResponseType => {
206
+ if (!cdMaterialsResult) {
207
+ return {
208
+ materials: [],
209
+ ...processCDMaterialsMetaInfo(cdMaterialsResult),
210
+ ...processCDMaterialsApprovalInfo(false, cdMaterialsResult),
211
+ }
212
+ }
213
+
214
+ const materials = cdMaterialListModal(
215
+ cdMaterialsResult.ci_artifacts,
216
+ offset ?? 1,
217
+ cdMaterialsResult.latest_wf_artifact_id,
218
+ cdMaterialsResult.latest_wf_artifact_status,
219
+ )
220
+ const approvalInfo = processCDMaterialsApprovalInfo(
221
+ stage === DeploymentNodeType.CD || stage === DeploymentNodeType.APPROVAL,
222
+ cdMaterialsResult,
223
+ )
224
+ const metaInfo = processCDMaterialsMetaInfo(cdMaterialsResult)
225
+
226
+ // TODO: On update of service would remove from here
227
+ const filteredMaterials =
228
+ filter && filter === CDMaterialFilterQuery.RESOURCE
229
+ ? materials.filter((material) => {
230
+ return material.filterState === FilterStates.ALLOWED
231
+ })
232
+ : materials
233
+
234
+ return {
235
+ materials: filteredMaterials,
236
+ ...approvalInfo,
237
+ ...metaInfo,
238
+ }
239
+ }
240
+
241
+ const getSanitizedQueryParams = (queryParams: CDMaterialServiceQueryParams): CDMaterialServiceQueryParams => {
242
+ const { filter, ...rest } = queryParams
243
+ return rest
244
+ }
245
+
246
+ export const genericCDMaterialsService = (
247
+ serviceType: CDMaterialServiceEnum,
248
+ cdMaterialID: number,
249
+ stage: DeploymentNodeType,
250
+ signal: AbortSignal,
251
+ queryParams: CDMaterialServiceQueryParams = {},
252
+ ): Promise<CDMaterialResponseType> => {
253
+ // TODO: On update of service would remove from here
254
+ const manipulatedParams = getSanitizedQueryParams(queryParams)
255
+
256
+ let URL
257
+ switch (serviceType) {
258
+ case CDMaterialServiceEnum.ROLLBACK:
259
+ URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material/rollback`, manipulatedParams)
260
+ break
261
+
262
+ // Meant for handling getCDMaterialList
263
+ default:
264
+ URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material`, { ...manipulatedParams, stage })
265
+ break
266
+ }
267
+
268
+ return get(URL, { signal }).then((response) => {
269
+ return processCDMaterialServiceResponse(response.result, stage, manipulatedParams.offset, manipulatedParams.filter)
131
270
  })
132
271
  }
133
272
 
@@ -24,6 +24,7 @@ export const ROUTES = {
24
24
  PROJECT_LIST_MIN: 'team/autocomplete',
25
25
  USER_CHECK_ROLE: 'user/check/roles',
26
26
  IMAGE_TAGGING:'app/image-tagging',
27
+ CD_MATERIAL_GET: 'app/cd-pipeline'
27
28
  }
28
29
 
29
30
  export enum KEY_VALUE {
@@ -326,7 +326,7 @@ export function CustomInput({
326
326
  tabIndex={tabIndex}
327
327
  />
328
328
  {handleError(error).map((err) => (
329
- <div className="form__error">
329
+ <div className="form__error" key={err}>
330
330
  <FormError className="form__icon form__icon--error" />
331
331
  {err}
332
332
  </div>
@@ -18,6 +18,7 @@ import { showError, stopPropagation } from './Helper'
18
18
  import { TippyCustomized } from './TippyCustomized'
19
19
  import { setImageTags, getUserRole } from './Common.service'
20
20
  import Tippy from '@tippyjs/react'
21
+ import { Progressing } from './Progressing'
21
22
 
22
23
  export const ImageTagsContainer = ({
23
24
  ciPipelineId,
@@ -47,6 +48,7 @@ export const ImageTagsContainer = ({
47
48
  const [isSuperAdmin, setSuperAdmin] = useState<boolean>(false)
48
49
  const [descriptionValidationMessage, setDescriptionValidationMessage] = useState<string>('')
49
50
  const [textInput, setTextInput] = useState<string>('')
51
+ const [loading, setLoading] = useState<boolean>(false)
50
52
 
51
53
  useEffect(() => {
52
54
  initialise()
@@ -226,6 +228,7 @@ export const ImageTagsContainer = ({
226
228
  }
227
229
 
228
230
  // set loading state true
231
+ setLoading(true)
229
232
  setImageTags(payload, ciPipelineId, artifactId)
230
233
  .then((res) => {
231
234
  const tags = res.result?.imageReleaseTags?.map((tag) => ({
@@ -262,6 +265,9 @@ export const ImageTagsContainer = ({
262
265
  showError(err)
263
266
  }
264
267
  })
268
+ .finally(()=>{
269
+ setLoading(false)
270
+ })
265
271
  }
266
272
 
267
273
  const renderInfoCard = (): JSX.Element => {
@@ -438,6 +444,7 @@ export const ImageTagsContainer = ({
438
444
  stopPropagation(e)
439
445
  handleCancel()
440
446
  }}
447
+ disabled={loading}
441
448
  >
442
449
  Cancel
443
450
  </button>
@@ -449,8 +456,9 @@ export const ImageTagsContainer = ({
449
456
  stopPropagation(e)
450
457
  onClickSave()
451
458
  }}
459
+ disabled={loading}
452
460
  >
453
- Save
461
+ {loading ? <Progressing /> : 'Save'}
454
462
  </button>
455
463
  </div>
456
464
  </div>
@@ -247,6 +247,30 @@ export interface CDMaterialType {
247
247
  imageReleaseTags?: ReleaseTag[]
248
248
  artifactStatus?: string
249
249
  filterState: FilterStates
250
+ // Not even coming from API but required in CDMaterials for Security which makes its own api call but stores data in CDMaterials
251
+ scanToolId?: number
252
+ }
253
+
254
+ export enum CDMaterialServiceEnum {
255
+ ROLLBACK = 'rollback',
256
+ CD_MATERIALS = 'cd-materials',
257
+ }
258
+
259
+ export enum CDMaterialResourceQuery {
260
+ PENDING_APPROVAL = 'PENDING_APPROVAL'
261
+ }
262
+
263
+ export enum CDMaterialFilterQuery {
264
+ RESOURCE = 'ELIGIBLE_RESOURCES',
265
+ ALL = 'ALL_RESOURCES'
266
+ }
267
+
268
+ export interface CDMaterialServiceQueryParams {
269
+ search?: string
270
+ offset?: number
271
+ size?: number
272
+ resource?: CDMaterialResourceQuery
273
+ filter?: CDMaterialFilterQuery
250
274
  }
251
275
 
252
276
  export interface CommonNodeAttr {
@@ -362,17 +386,23 @@ export interface FilterConditionsListType {
362
386
  conditions: FilterConditionsInfo[]
363
387
  }
364
388
 
365
- export interface CDMaterialResponseType {
389
+ export interface CDMaterialsApprovalInfo {
366
390
  approvalUsers: string[]
367
- materials: any[]
368
391
  userApprovalConfig: UserApprovalConfigType
369
392
  requestedUserId: number
393
+ }
394
+
395
+ export interface CDMaterialsMetaInfo {
370
396
  tagsEditable: boolean
371
397
  appReleaseTagNames: string[]
372
398
  hideImageTaggingHardDelete: boolean
373
399
  resourceFilters?: FilterConditionsListType[]
374
400
  }
375
401
 
402
+ export interface CDMaterialResponseType extends CDMaterialsMetaInfo, CDMaterialsApprovalInfo {
403
+ materials: CDMaterialType[]
404
+ }
405
+
376
406
  export interface InputDetailType {
377
407
  label: string
378
408
  defaultValue: string