@devtron-labs/devtron-fe-common-lib 0.0.10-beta-6 → 0.0.10-beta-8

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
1
  /// <reference types="react" />
2
2
  import { ImageButtonType, ImageTaggingContainerType } from './Types';
3
- export declare const ImageTagsContainer: ({ ciPipelineId, artifactId, imageComment, imageReleaseTags, appReleaseTagNames, tagsEditable, toggleCardMode, }: ImageTaggingContainerType) => JSX.Element;
3
+ export declare const ImageTagsContainer: ({ ciPipelineId, artifactId, imageComment, imageReleaseTags, appReleaseTagNames, setAppReleaseTagNames, tagsEditable, setTagsEditable, toggleCardMode, }: ImageTaggingContainerType) => JSX.Element;
4
4
  export declare const ImageTagButton: ({ text, isSoftDeleted, isEditing, onSoftDeleteClick, onHardDeleteClick, tagId, softDeleteTags, isSuperAdmin, }: ImageButtonType) => JSX.Element;
@@ -324,6 +324,8 @@ export interface ImageTaggingContainerType {
324
324
  imageReleaseTags?: ReleaseTag[];
325
325
  appReleaseTagNames?: string[];
326
326
  tagsEditable?: boolean;
327
+ setAppReleaseTagNames?: (appReleaseTags: string[]) => void;
328
+ setTagsEditable?: (tagsEditable: boolean) => void;
327
329
  toggleCardMode?: (id: number) => void;
328
330
  }
329
331
  export interface ImageButtonType {
package/dist/index.js CHANGED
@@ -22763,7 +22763,7 @@ var SvgIcMinus = function SvgIcMinus(props) {
22763
22763
  };
22764
22764
 
22765
22765
  var ImageTagsContainer = function (_a) {
22766
- var ciPipelineId = _a.ciPipelineId, artifactId = _a.artifactId, imageComment = _a.imageComment, imageReleaseTags = _a.imageReleaseTags, appReleaseTagNames = _a.appReleaseTagNames, tagsEditable = _a.tagsEditable, toggleCardMode = _a.toggleCardMode;
22766
+ var ciPipelineId = _a.ciPipelineId, artifactId = _a.artifactId, imageComment = _a.imageComment, imageReleaseTags = _a.imageReleaseTags, appReleaseTagNames = _a.appReleaseTagNames, setAppReleaseTagNames = _a.setAppReleaseTagNames, tagsEditable = _a.tagsEditable, setTagsEditable = _a.setTagsEditable, toggleCardMode = _a.toggleCardMode;
22767
22767
  var _b = __read(React.useState(imageReleaseTags ? imageReleaseTags : []), 2), initialTags = _b[0], setInitialTags = _b[1];
22768
22768
  var _c = __read(React.useState(imageComment ? imageComment.comment : ''), 2), initialDescription = _c[0], setInitialDescription = _c[1];
22769
22769
  var _d = __read(React.useState(appReleaseTagNames ? appReleaseTagNames : []), 2), existingTags = _d[0], setExistingTags = _d[1];
@@ -22776,12 +22776,16 @@ var ImageTagsContainer = function (_a) {
22776
22776
  var _l = __read(React.useState([]), 2), softDeleteTags = _l[0], setSoftDeleteTags = _l[1];
22777
22777
  var _m = __read(React.useState([]), 2), hardDeleteTags = _m[0], setHardDeleteTags = _m[1];
22778
22778
  var _o = __read(React.useState(false), 2), isSuperAdmin = _o[0], setSuperAdmin = _o[1];
22779
+ var _p = __read(React.useState(''), 2), descriptionValidationMessage = _p[0], setDescriptionValidationMessage = _p[1];
22779
22780
  React.useEffect(function () {
22780
22781
  initialise();
22781
22782
  }, []);
22782
22783
  React.useEffect(function () {
22783
22784
  reInitState();
22784
- }, [imageReleaseTags, imageComment, appReleaseTagNames, tagsEditable]);
22785
+ }, [imageReleaseTags, imageComment, tagsEditable]);
22786
+ React.useEffect(function () {
22787
+ setExistingTags(appReleaseTagNames ? appReleaseTagNames : []);
22788
+ }, [appReleaseTagNames]);
22785
22789
  function initialise() {
22786
22790
  var _a, _b;
22787
22791
  return __awaiter(this, void 0, void 0, function () {
@@ -22806,11 +22810,12 @@ var ImageTagsContainer = function (_a) {
22806
22810
  });
22807
22811
  }
22808
22812
  var reInitState = function () {
22809
- setInitialTags(imageReleaseTags ? imageReleaseTags : []);
22810
- setInitialDescription(imageComment ? imageComment.comment : '');
22811
- setExistingTags(appReleaseTagNames ? appReleaseTagNames : []);
22812
- setNewDescription(imageComment ? imageComment.comment : '');
22813
- setDisplayedTags(imageReleaseTags ? imageReleaseTags : []);
22813
+ if (isEditing === false) {
22814
+ setInitialTags(imageReleaseTags ? imageReleaseTags : []);
22815
+ setInitialDescription(imageComment ? imageComment.comment : '');
22816
+ setNewDescription(imageComment ? imageComment.comment : '');
22817
+ setDisplayedTags(imageReleaseTags ? imageReleaseTags : []);
22818
+ }
22814
22819
  };
22815
22820
  var CreatableComponents = React.useMemo(function () { return ({
22816
22821
  DropdownIndicator: function () { return null; },
@@ -22824,7 +22829,9 @@ var ImageTagsContainer = function (_a) {
22824
22829
  }
22825
22830
  };
22826
22831
  var handleDescriptionChange = function (e) {
22827
- setNewDescription(e.target.value);
22832
+ var description = e.target.value;
22833
+ (description === null || description === void 0 ? void 0 : description.length) > 500 ? setDescriptionValidationMessage('comment length cannot exceed 500 characters') : setDescriptionValidationMessage('');
22834
+ setNewDescription(description);
22828
22835
  };
22829
22836
  var handleCancel = function () {
22830
22837
  setDisplayedTags(initialTags);
@@ -22837,7 +22844,11 @@ var ImageTagsContainer = function (_a) {
22837
22844
  setTagErrorMessage('');
22838
22845
  };
22839
22846
  var handleTagCreate = function (newValue) {
22840
- var lowercaseValue = newValue.toLowerCase();
22847
+ var lowercaseValue = newValue.toLowerCase().trim();
22848
+ if (lowercaseValue.length == 0 || lowercaseValue.length >= 128 || lowercaseValue[0] == '.' || lowercaseValue[0] == '-') {
22849
+ setTagErrorMessage("tag name cannot be empty or exceed 128 characters or cannot start with . or -");
22850
+ return;
22851
+ }
22841
22852
  setTagErrorMessage('');
22842
22853
  var isTagExistsInExistingTags = existingTags.includes(lowercaseValue);
22843
22854
  var isTagExistsInDisplayedTags = false;
@@ -22845,8 +22856,8 @@ var ImageTagsContainer = function (_a) {
22845
22856
  if (displayedTags[i].tagName.toLowerCase() === lowercaseValue)
22846
22857
  isTagExistsInDisplayedTags = true;
22847
22858
  }
22848
- if (isTagExistsInExistingTags || isTagExistsInDisplayedTags) {
22849
- setTagErrorMessage('This tag is already applied on another image in this application');
22859
+ if (isTagExistsInExistingTags || isTagExistsInDisplayedTags || lowercaseValue === 'latest') {
22860
+ setTagErrorMessage("This tag ".concat(lowercaseValue, " is already applied on same/another image in this application"));
22850
22861
  return;
22851
22862
  }
22852
22863
  var newTag = {
@@ -22892,51 +22903,50 @@ var ImageTagsContainer = function (_a) {
22892
22903
  }
22893
22904
  };
22894
22905
  var handleSave = function () { return __awaiter(void 0, void 0, void 0, function () {
22895
- var payload, response, tags, err_2;
22896
- var _a, _b, _c, _d, _e, _f;
22897
- return __generator(this, function (_g) {
22898
- switch (_g.label) {
22899
- case 0:
22900
- payload = {
22901
- createTags: createTags,
22902
- softDeleteTags: softDeleteTags,
22903
- imageComment: {
22904
- id: 0,
22905
- comment: newDescription.trim(),
22906
- artifactId: 0,
22907
- },
22908
- hardDeleteTags: hardDeleteTags,
22909
- };
22910
- _g.label = 1;
22911
- case 1:
22912
- _g.trys.push([1, 3, , 4]);
22913
- return [4 /*yield*/, setImageTags(payload, ciPipelineId, artifactId)];
22914
- case 2:
22915
- response = _g.sent();
22916
- tags = (_b = (_a = response.result) === null || _a === void 0 ? void 0 : _a.imageReleaseTags) === null || _b === void 0 ? void 0 : _b.map(function (tag) { return ({
22917
- id: tag.id,
22918
- tagName: tag.tagName,
22919
- deleted: tag.deleted,
22920
- appId: 0,
22921
- artifactId: 0,
22922
- }); });
22923
- setInitialTags(tags);
22924
- setInitialDescription((_d = (_c = response.result) === null || _c === void 0 ? void 0 : _c.imageComment) === null || _d === void 0 ? void 0 : _d.comment);
22925
- setDisplayedTags(tags);
22926
- setNewDescription((_f = (_e = response.result) === null || _e === void 0 ? void 0 : _e.imageComment) === null || _f === void 0 ? void 0 : _f.comment);
22927
- setCreateTags([]);
22928
- setSoftDeleteTags([]);
22929
- setHardDeleteTags([]);
22930
- handleEditClick();
22931
- setShowTagsWarning(false);
22932
- setTagErrorMessage('');
22933
- return [3 /*break*/, 4];
22934
- case 3:
22935
- err_2 = _g.sent();
22936
- showError(err_2);
22937
- return [3 /*break*/, 4];
22938
- case 4: return [2 /*return*/];
22939
- }
22906
+ var payload;
22907
+ return __generator(this, function (_a) {
22908
+ payload = {
22909
+ createTags: createTags,
22910
+ softDeleteTags: softDeleteTags,
22911
+ imageComment: {
22912
+ id: 0,
22913
+ comment: newDescription.trim(),
22914
+ artifactId: 0,
22915
+ },
22916
+ hardDeleteTags: hardDeleteTags,
22917
+ };
22918
+ // set loading state true
22919
+ setImageTags(payload, ciPipelineId, artifactId)
22920
+ .then(function (res) {
22921
+ var _a, _b, _c, _d, _e, _f, _g, _h;
22922
+ var tags = (_b = (_a = res.result) === null || _a === void 0 ? void 0 : _a.imageReleaseTags) === null || _b === void 0 ? void 0 : _b.map(function (tag) { return ({
22923
+ id: tag.id,
22924
+ tagName: tag.tagName,
22925
+ deleted: tag.deleted,
22926
+ appId: 0,
22927
+ artifactId: 0,
22928
+ }); });
22929
+ if (setAppReleaseTagNames) {
22930
+ setAppReleaseTagNames((_c = res.result) === null || _c === void 0 ? void 0 : _c.appReleaseTags);
22931
+ }
22932
+ if (setTagsEditable) {
22933
+ setTagsEditable((_d = res.result) === null || _d === void 0 ? void 0 : _d.tagsEditable);
22934
+ }
22935
+ setInitialTags(tags);
22936
+ setInitialDescription((_f = (_e = res.result) === null || _e === void 0 ? void 0 : _e.imageComment) === null || _f === void 0 ? void 0 : _f.comment);
22937
+ setDisplayedTags(tags);
22938
+ setNewDescription((_h = (_g = res.result) === null || _g === void 0 ? void 0 : _g.imageComment) === null || _h === void 0 ? void 0 : _h.comment);
22939
+ setCreateTags([]);
22940
+ setSoftDeleteTags([]);
22941
+ setHardDeleteTags([]);
22942
+ handleEditClick();
22943
+ setShowTagsWarning(false);
22944
+ setTagErrorMessage('');
22945
+ })
22946
+ .catch(function (err) {
22947
+ showError(err);
22948
+ });
22949
+ return [2 /*return*/];
22940
22950
  });
22941
22951
  }); };
22942
22952
  var renderInfoCard = function () {
@@ -22955,7 +22965,7 @@ var ImageTagsContainer = function (_a) {
22955
22965
  }, onHardDeleteClick: function (e) {
22956
22966
  stopPropagation(e);
22957
22967
  handleTagHardDelete(index);
22958
- }, tagId: tag.id, softDeleteTags: softDeleteTags, isSuperAdmin: isSuperAdmin }, 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", style: { height: '90px !important' } }) })), jsxRuntime.jsxs("div", __assign({ className: "w-100 flex right" }, { children: [jsxRuntime.jsx("button", __assign({ className: "cta flex cancel h-32 lh-32-imp", type: "button", onClick: function (e) {
22968
+ }, tagId: tag.id, softDeleteTags: softDeleteTags, isSuperAdmin: isSuperAdmin }, 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", "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", 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) {
22959
22969
  stopPropagation(e);
22960
22970
  handleCancel();
22961
22971
  } }, { 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) {
@@ -22992,7 +23002,8 @@ var ImageTagButton = function (_a) {
22992
23002
  };
22993
23003
  var AddImageButton = function (_a) {
22994
23004
  var handleEditClick = _a.handleEditClick;
22995
- var handleClick = function () {
23005
+ var handleClick = function (e) {
23006
+ stopPropagation(e);
22996
23007
  handleEditClick();
22997
23008
  };
22998
23009
  return (jsxRuntime.jsx("div", __assign({ className: "add-tag-button flex pt-12 pr-12", "data-testid": "add-tags-button", onClick: handleClick }, { children: jsxRuntime.jsxs("div", __assign({ className: "lh-16 flex" }, { children: [jsxRuntime.jsx(SvgIcAdd, { className: "icon-dim-16 cn-6" }), jsxRuntime.jsx("span", __assign({ className: "cn-7" }, { children: "Add tags/comment" }))] })) })));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.10-beta-6",
3
+ "version": "0.0.10-beta-8",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -22,7 +22,9 @@ export const ImageTagsContainer = ({
22
22
  imageComment,
23
23
  imageReleaseTags,
24
24
  appReleaseTagNames,
25
+ setAppReleaseTagNames,
25
26
  tagsEditable,
27
+ setTagsEditable,
26
28
  toggleCardMode,
27
29
  }: ImageTaggingContainerType) => {
28
30
  const [initialTags, setInitialTags] = useState<ReleaseTag[]>(imageReleaseTags ? imageReleaseTags : [])
@@ -37,6 +39,7 @@ export const ImageTagsContainer = ({
37
39
  const [softDeleteTags, setSoftDeleteTags] = useState<ReleaseTag[]>([])
38
40
  const [hardDeleteTags, setHardDeleteTags] = useState<ReleaseTag[]>([])
39
41
  const [isSuperAdmin, setSuperAdmin] = useState<boolean>(false)
42
+ const [descriptionValidationMessage, setDescriptionValidationMessage] = useState<string>('')
40
43
 
41
44
  useEffect(() => {
42
45
  initialise()
@@ -44,7 +47,11 @@ export const ImageTagsContainer = ({
44
47
 
45
48
  useEffect(() => {
46
49
  reInitState()
47
- }, [imageReleaseTags, imageComment, appReleaseTagNames, tagsEditable])
50
+ }, [imageReleaseTags,imageComment,tagsEditable])
51
+
52
+ useEffect(() => {
53
+ setExistingTags(appReleaseTagNames ? appReleaseTagNames : [])
54
+ },[appReleaseTagNames])
48
55
 
49
56
  async function initialise() {
50
57
  try {
@@ -58,11 +65,12 @@ export const ImageTagsContainer = ({
58
65
  }
59
66
 
60
67
  const reInitState = () => {
61
- setInitialTags(imageReleaseTags ? imageReleaseTags : [])
62
- setInitialDescription(imageComment ? imageComment.comment : '')
63
- setExistingTags(appReleaseTagNames ? appReleaseTagNames : [])
64
- setNewDescription(imageComment ? imageComment.comment : '')
65
- setDisplayedTags(imageReleaseTags ? imageReleaseTags : [])
68
+ if (isEditing === false) {
69
+ setInitialTags(imageReleaseTags ? imageReleaseTags : [])
70
+ setInitialDescription(imageComment ? imageComment.comment : '')
71
+ setNewDescription(imageComment ? imageComment.comment : '')
72
+ setDisplayedTags(imageReleaseTags ? imageReleaseTags : [])
73
+ }
66
74
  }
67
75
 
68
76
  const CreatableComponents = useMemo(
@@ -82,7 +90,9 @@ export const ImageTagsContainer = ({
82
90
  }
83
91
 
84
92
  const handleDescriptionChange = (e) => {
85
- setNewDescription(e.target.value)
93
+ const description = e.target.value
94
+ description?.length > 500 ? setDescriptionValidationMessage('comment length cannot exceed 500 characters') : setDescriptionValidationMessage('')
95
+ setNewDescription(description)
86
96
  }
87
97
 
88
98
  const handleCancel = () => {
@@ -97,15 +107,19 @@ export const ImageTagsContainer = ({
97
107
  }
98
108
 
99
109
  const handleTagCreate = (newValue) => {
100
- const lowercaseValue = newValue.toLowerCase()
110
+ const lowercaseValue = newValue.toLowerCase().trim()
111
+ if(lowercaseValue.length == 0 || lowercaseValue.length >= 128 || lowercaseValue[0] == '.' || lowercaseValue[0] == '-') {
112
+ setTagErrorMessage("tag name cannot be empty or exceed 128 characters or cannot start with . or -")
113
+ return
114
+ }
101
115
  setTagErrorMessage('')
102
116
  const isTagExistsInExistingTags = existingTags.includes(lowercaseValue)
103
117
  let isTagExistsInDisplayedTags = false
104
118
  for (let i = 0; i < displayedTags?.length; i++) {
105
119
  if (displayedTags[i].tagName.toLowerCase() === lowercaseValue) isTagExistsInDisplayedTags = true
106
120
  }
107
- if (isTagExistsInExistingTags || isTagExistsInDisplayedTags) {
108
- setTagErrorMessage('This tag is already applied on another image in this application')
121
+ if (isTagExistsInExistingTags || isTagExistsInDisplayedTags || lowercaseValue === 'latest') {
122
+ setTagErrorMessage(`This tag ${lowercaseValue} is already applied on same/another image in this application`)
109
123
  return
110
124
  }
111
125
  const newTag: ReleaseTag = {
@@ -167,31 +181,39 @@ export const ImageTagsContainer = ({
167
181
  hardDeleteTags: hardDeleteTags,
168
182
  }
169
183
 
170
- try {
171
- // set loading state true
172
- let response = await setImageTags(payload, ciPipelineId, artifactId)
173
- const tags = response.result?.imageReleaseTags?.map((tag) => ({
174
- id: tag.id,
175
- tagName: tag.tagName,
176
- deleted: tag.deleted,
177
- appId: 0,
178
- artifactId: 0,
179
- }))
180
- setInitialTags(tags)
181
- setInitialDescription(response.result?.imageComment?.comment)
182
- setDisplayedTags(tags)
183
- setNewDescription(response.result?.imageComment?.comment)
184
- setCreateTags([])
185
- setSoftDeleteTags([])
186
- setHardDeleteTags([])
187
- handleEditClick()
188
- setShowTagsWarning(false)
189
- setTagErrorMessage('')
190
- } catch (err) {
191
- showError(err)
192
- }
184
+ // set loading state true
185
+ setImageTags(payload, ciPipelineId, artifactId)
186
+ .then((res) => {
187
+ const tags = res.result?.imageReleaseTags?.map((tag) => ({
188
+ id: tag.id,
189
+ tagName: tag.tagName,
190
+ deleted: tag.deleted,
191
+ appId: 0,
192
+ artifactId: 0,
193
+ }))
194
+ if (setAppReleaseTagNames) {
195
+ setAppReleaseTagNames(res.result?.appReleaseTags)
196
+ }
197
+ if (setTagsEditable) {
198
+ setTagsEditable(res.result?.tagsEditable)
199
+ }
200
+ setInitialTags(tags)
201
+ setInitialDescription(res.result?.imageComment?.comment)
202
+ setDisplayedTags(tags)
203
+ setNewDescription(res.result?.imageComment?.comment)
204
+ setCreateTags([])
205
+ setSoftDeleteTags([])
206
+ setHardDeleteTags([])
207
+ handleEditClick()
208
+ setShowTagsWarning(false)
209
+ setTagErrorMessage('')
210
+ })
211
+ .catch((err) => {
212
+ showError(err)
213
+ })
193
214
  }
194
215
 
216
+
195
217
  const renderInfoCard = (): JSX.Element => {
196
218
  return (
197
219
  <TippyCustomized
@@ -297,7 +319,7 @@ export const ImageTagsContainer = ({
297
319
  )}
298
320
  <div className="cn-7 mt-12">Comment</div>
299
321
  <div
300
- className="flex left flex-wrap dc__gap-8 w-100 mt-6 mb-12"
322
+ className="flex left flex-wrap dc__gap-8 w-100 mt-6"
301
323
  data-testid="add-image-comment-text-area"
302
324
  >
303
325
  <textarea
@@ -307,7 +329,12 @@ export const ImageTagsContainer = ({
307
329
  style={{ height: '90px !important' }}
308
330
  />
309
331
  </div>
310
- <div className="w-100 flex right">
332
+ { (descriptionValidationMessage !== '') && (<div className="flex left">
333
+ <Error className="form__icon form__icon--error" />
334
+ <div className="form__error">{descriptionValidationMessage}</div>
335
+ </div>
336
+ )}
337
+ <div className="w-100 flex right mt-12">
311
338
  <button
312
339
  className="cta flex cancel h-32 lh-32-imp"
313
340
  type="button"
@@ -437,7 +464,8 @@ export const ImageTagButton = ({
437
464
  }
438
465
 
439
466
  const AddImageButton = ({ handleEditClick }) => {
440
- const handleClick = () => {
467
+ const handleClick = (e) => {
468
+ stopPropagation(e)
441
469
  handleEditClick()
442
470
  }
443
471
 
@@ -357,6 +357,8 @@ export interface ImageTaggingContainerType {
357
357
  imageReleaseTags?: ReleaseTag[]
358
358
  appReleaseTagNames?: string[]
359
359
  tagsEditable?: boolean
360
+ setAppReleaseTagNames?: (appReleaseTags: string[]) => void
361
+ setTagsEditable?: (tagsEditable: boolean) => void
360
362
  toggleCardMode?: (id: number) => void
361
363
  }
362
364