Skip to content

Commit 1fbc02b

Browse files
1spyralamitytPriteshKiriJonsy13
authored
Render step name in fault settings and make it editable (#5215)
* Add updateFaultStepName method Creates functionality to update the display name of a Chaos Fault Signed-off-by: Luke Zhan <[email protected]> * Render step name in Fault settings and make it editable - If the Chaos Fault's step name differs from its template name, both are now displayed - An edit icon appears next to the title, allowing users to edit it Signed-off-by: Luke Zhan <[email protected]> * Add test suite for EditableStepName Signed-off-by: Luke Zhan <[email protected]> --------- Signed-off-by: Luke Zhan <[email protected]> Co-authored-by: Amit Kumar Das <[email protected]> Co-authored-by: Pritesh Kiri <[email protected]> Co-authored-by: Vedant Shrotria <[email protected]>
1 parent 43c4c1d commit 1fbc02b

File tree

10 files changed

+764
-11
lines changed

10 files changed

+764
-11
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.displayMode {
2+
display: flex;
3+
align-items: center;
4+
gap: var(--spacing-small);
5+
width: 100%;
6+
min-height: 45px;
7+
8+
.stepNameTextContainer {
9+
display: flex;
10+
flex-direction: column;
11+
gap: var(--spacing-tiny);
12+
flex: 1;
13+
}
14+
}
15+
16+
.editMode {
17+
display: flex;
18+
align-items: center;
19+
gap: var(--spacing-small);
20+
width: 100%;
21+
min-height: 45px;
22+
animation: fadeIn 0.2s ease-out;
23+
24+
.stepNameTextInput {
25+
flex: 1;
26+
min-width: 200px;
27+
margin-bottom: 0;
28+
}
29+
}
30+
31+
@keyframes fadeIn {
32+
from {
33+
opacity: 0;
34+
transform: translateY(-2px);
35+
}
36+
37+
to {
38+
opacity: 1;
39+
transform: translateY(0);
40+
}
41+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
declare namespace EditableStepNameModuleScssNamespace {
2+
export interface IEditableStepNameModuleScss {
3+
displayMode: string;
4+
editMode: string;
5+
fadeIn: string;
6+
stepNameTextContainer: string;
7+
stepNameTextInput: string;
8+
}
9+
}
10+
11+
declare const EditableStepNameModuleScssModule: EditableStepNameModuleScssNamespace.IEditableStepNameModuleScss;
12+
13+
export = EditableStepNameModuleScssModule;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import React from 'react';
2+
import { Color, FontVariation } from '@harnessio/design-system';
3+
import { Button, ButtonSize, ButtonVariation, Text, TextInput, useToaster } from '@harnessio/uicore';
4+
import css from './EditableStepName.module.scss';
5+
6+
export interface EditableStepNameProps {
7+
stepName?: string;
8+
faultName: string;
9+
onSave: (newStepName: string) => Promise<void>;
10+
fontSize?: FontVariation;
11+
showSubtitle?: boolean;
12+
disabled?: boolean;
13+
}
14+
15+
export function EditableStepName({
16+
stepName,
17+
faultName,
18+
onSave,
19+
fontSize = FontVariation.H5,
20+
showSubtitle = true,
21+
disabled = false
22+
}: EditableStepNameProps): React.ReactElement {
23+
const { showError } = useToaster();
24+
const [isEditing, setIsEditing] = React.useState<boolean>(false);
25+
const [editedValue, setEditedValue] = React.useState<string>('');
26+
const [isSaving, setIsSaving] = React.useState<boolean>(false);
27+
28+
const displayName = stepName || faultName;
29+
const shouldShowSubtitle = showSubtitle && stepName && stepName !== faultName;
30+
31+
const handleEditStart = (): void => {
32+
setEditedValue(displayName);
33+
setIsEditing(true);
34+
};
35+
36+
const handleSave = async (): Promise<void> => {
37+
if (editedValue.trim() && editedValue !== stepName) {
38+
setIsSaving(true);
39+
try {
40+
await onSave(editedValue.trim());
41+
setIsEditing(false);
42+
setEditedValue('');
43+
} catch (error) {
44+
showError('Failed to update step name');
45+
} finally {
46+
setIsSaving(false);
47+
}
48+
} else {
49+
setIsEditing(false);
50+
setEditedValue('');
51+
}
52+
};
53+
54+
const handleCancel = (): void => {
55+
setIsEditing(false);
56+
setEditedValue('');
57+
};
58+
59+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
60+
if (e.key === 'Enter') {
61+
e.stopPropagation();
62+
e.preventDefault();
63+
handleSave();
64+
} else if (e.key === 'Escape') {
65+
e.stopPropagation();
66+
e.preventDefault();
67+
handleCancel();
68+
}
69+
};
70+
71+
if (isEditing) {
72+
return (
73+
<div className={css.editMode}>
74+
<TextInput
75+
wrapperClassName={css.stepNameTextInput}
76+
value={editedValue}
77+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEditedValue(e.target.value)}
78+
onKeyDown={handleKeyDown}
79+
autoFocus
80+
disabled={isSaving}
81+
/>
82+
<Button
83+
variation={ButtonVariation.ICON}
84+
icon="tick"
85+
size={ButtonSize.SMALL}
86+
onClick={handleSave}
87+
disabled={isSaving}
88+
loading={isSaving}
89+
/>
90+
<Button
91+
variation={ButtonVariation.ICON}
92+
icon="cross"
93+
size={ButtonSize.SMALL}
94+
onClick={handleCancel}
95+
disabled={isSaving}
96+
/>
97+
</div>
98+
);
99+
}
100+
101+
return (
102+
<div className={css.displayMode}>
103+
<div className={css.stepNameTextContainer}>
104+
<Text font={{ variation: fontSize }}>{displayName}</Text>
105+
{shouldShowSubtitle && (
106+
<Text color={Color.GREY_600} font={{ variation: FontVariation.SMALL, italic: true }}>
107+
{faultName}
108+
</Text>
109+
)}
110+
</div>
111+
{!disabled && (
112+
<Button
113+
variation={ButtonVariation.ICON}
114+
icon="Edit"
115+
size={ButtonSize.SMALL}
116+
onClick={handleEditStart}
117+
minimal
118+
/>
119+
)}
120+
</div>
121+
);
122+
}
123+
124+
export default EditableStepName;

0 commit comments

Comments
 (0)