Skip to content

Commit ca8f668

Browse files
cabella-dotmarcomurabwieger-atlassian-com
authored
[AXON-411] Add FG for rich text editor (#405)
* [AXON-411] Add fg for rich text editor * [AXON-411] update * Clean-ups after changing the E2E framework * AXON-301: Drop labs from extension title (#401) * Drop labs from extension title * Changelog * Homepage change * Revert "Clean-ups after changing the E2E framework" This reverts commit d364d88. * AXON-405: Remove FF for badges and banners (#407) * Remove FF * Improved switch for creating action on notifications :wq * Clean-ups after changing the E2E framework (#408) * Upgraded ESLint and other npm packages + cleanups + improvements (#409) * [AXON-411] fix FG implementation * remove unneeded fg --------- Co-authored-by: Marco Mura <[email protected]> Co-authored-by: bwieger-atlassian-com <[email protected]> Co-authored-by: Marco <[email protected]>
1 parent cfae1d9 commit ca8f668

File tree

12 files changed

+78
-9
lines changed

12 files changed

+78
-9
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,4 +1390,4 @@
13901390
"webpack-node-externals": "^3.0.0"
13911391
},
13921392
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
1393-
}
1393+
}

src/util/featureFlags/features.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const enum Features {
22
NoOpFeature = 'atlascode-noop',
33
EnableErrorTelemetry = 'atlascode-send-error-telemetry',
4+
JiraRichText = 'atlascode-jira-rte',
45
}
56

67
export const enum Experiments {

src/webviews/abstractWebview.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import { Container } from '../container';
1818
import { submitLegacyJSDPMF } from '../feedback/pmfJSDSubmitter';
1919
import { isAction, isAlertable, isPMFSubmitAction } from '../ipc/messaging';
2020
import { CommonActionType } from '../lib/ipc/fromUI/common';
21+
import { CommonMessageType } from '../lib/ipc/toUI/common';
2122
import { iconSet, Resources } from '../resources';
23+
import { Experiments, FeatureFlagClient, Features } from '../util/featureFlags';
24+
import { ExperimentGateValues, FeatureGateValues } from '../util/featureFlags/features';
2225
import { UIWebsocket } from '../ws';
2326

2427
// ReactWebview is an interface that can be used to deal with webview objects when you don't know their generic typings.
@@ -133,6 +136,25 @@ export abstract class AbstractReactWebview implements ReactWebview {
133136
);
134137
this._panel.reveal(column ? column : ViewColumn.Active); // , false);
135138
}
139+
140+
this.fireFeatureGates([Features.JiraRichText]);
141+
this.fireExperimentGates([]);
142+
}
143+
144+
private fireFeatureGates(features: Features[]) {
145+
if (features.length) {
146+
const featureFlags = {} as FeatureGateValues;
147+
features.forEach((x) => (featureFlags[x] = FeatureFlagClient.checkGate(x)));
148+
this.postMessage({ type: CommonMessageType.UpdateFeatureFlags, featureFlags });
149+
}
150+
}
151+
152+
private fireExperimentGates(experiments: Experiments[]) {
153+
if (experiments.length) {
154+
const experimentValues = {} as ExperimentGateValues;
155+
experiments.forEach((x) => (experimentValues[x] = FeatureFlagClient.checkExperimentValue(x)));
156+
this.postMessage({ type: CommonMessageType.UpdateExperimentValues, experimentValues });
157+
}
136158
}
137159

138160
private onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent) {

src/webviews/components/issue/AbstractIssueEditorPage.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export interface CommonEditorViewState extends Message {
7373
showPMF: boolean;
7474
errorDetails: any;
7575
commentInputValue: string;
76+
isRteEnabled: boolean;
7677
}
7778

7879
export const emptyCommonEditorState: CommonEditorViewState = {
@@ -88,6 +89,7 @@ export const emptyCommonEditorState: CommonEditorViewState = {
8889
isErrorBannerOpen: false,
8990
errorDetails: undefined,
9091
commentInputValue: '',
92+
isRteEnabled: false,
9193
};
9294

9395
const shouldShowCreateOption = (inputValue: any, selectValue: any, selectOptions: any[]) => {
@@ -185,6 +187,10 @@ export abstract class AbstractIssueEditorPage<
185187
this.setState({ showPMF: e.showPMF });
186188
break;
187189
}
190+
case 'updateFeatureFlags': {
191+
this.setState({ isRteEnabled: e.featureFlags.rteEnabled });
192+
break;
193+
}
188194
}
189195

190196
return handled;
@@ -493,6 +499,7 @@ export abstract class AbstractIssueEditorPage<
493499
: `[~${user.name}]`,
494500
}))
495501
}
502+
featureGateEnabled={this.state.isRteEnabled}
496503
/>
497504
);
498505
}

src/webviews/components/issue/common/JiraIssueTextArea.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe('JiraIssueTextAreaEditor', () => {
2020
onCancel: mockOnCancel,
2121
fetchUsers: mockFetchUsers,
2222
saving: false,
23+
featureGateEnabled: true,
2324
};
2425

2526
beforeAll(() => {

src/webviews/components/issue/common/JiraIssueTextArea.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Props = {
2020
onInternalCommentSave?: () => void;
2121
isDescription?: boolean;
2222
saving?: boolean;
23+
featureGateEnabled?: boolean;
2324
};
2425

2526
interface User {
@@ -39,6 +40,7 @@ const JiraIssueTextAreaEditor: React.FC<Props> = ({
3940
onInternalCommentSave,
4041
isDescription,
4142
saving,
43+
featureGateEnabled = false,
4244
}) => {
4345
const inputTextAreaRef = React.useRef<HTMLTextAreaElement>(null);
4446
const [cursorPosition, setCursorPosition] = React.useState(value?.length || 0);
@@ -47,7 +49,7 @@ const JiraIssueTextAreaEditor: React.FC<Props> = ({
4749
appearance: 'subtle' as ButtonAppearance,
4850
};
4951

50-
const [rteEnabled, setRteEnabled] = React.useState(true);
52+
const [rteEnabled, setRteEnabled] = React.useState(featureGateEnabled);
5153

5254
const { viewHost, handleSave } = useEditor<User>({
5355
value,
@@ -149,9 +151,11 @@ const JiraIssueTextAreaEditor: React.FC<Props> = ({
149151
/>
150152
)}
151153
</div>
152-
<Tooltip content="Toggle rich text editor" position="top">
153-
<Toggle label="rte toggle" defaultChecked onChange={(e) => setRteEnabled(e.target.checked)} />
154-
</Tooltip>
154+
{featureGateEnabled && (
155+
<Tooltip content="Toggle rich text editor" position="top">
156+
<Toggle label="rte toggle" defaultChecked onChange={(e) => setRteEnabled(e.target.checked)} />
157+
</Tooltip>
158+
)}
155159
</div>
156160
</div>
157161
);

src/webviews/components/issue/create-issue-screen/CreateIssuePage.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ export default class CreateIssuePage extends AbstractIssueEditorPage<Emit, Accep
8585
const issueData = e as CreateIssueData;
8686
this.updateInternals(issueData);
8787
this.setState(issueData, () => {
88-
this.setState({ isSomethingLoading: false, loadingField: '' });
88+
this.setState({
89+
isSomethingLoading: false,
90+
loadingField: '',
91+
});
8992
});
9093

9194
break;

src/webviews/components/issue/view-issue-screen/JiraIssuePage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export default class JiraIssuePage extends AbstractIssueEditorPage<Emit, Accept,
9292
});
9393
break;
9494
}
95+
9596
case 'epicChildrenUpdate': {
9697
this.setState({ isSomethingLoading: false, loadingField: '', epicChildren: e.epicChildren });
9798
break;
@@ -520,6 +521,7 @@ export default class JiraIssuePage extends AbstractIssueEditorPage<Emit, Accept,
520521
}))
521522
}
522523
fetchImage={(img) => this.fetchImage(img)}
524+
isRteEnabled={this.state.isRteEnabled}
523525
/>
524526
{this.advancedMain()}
525527
{this.state.fields['comment'] && (
@@ -546,6 +548,7 @@ export default class JiraIssuePage extends AbstractIssueEditorPage<Emit, Accept,
546548
this.state.fieldValues['project'] &&
547549
this.state.fieldValues['project'].projectTypeKey === 'service_desk'
548550
}
551+
isRteEnabled={this.state.isRteEnabled}
549552
/>
550553
</div>
551554
)}

src/webviews/components/issue/view-issue-screen/mainpanel/IssueCommentComponent.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ describe('IssueCommentComponent', () => {
151151
fetchUsers={mockFetchUsers}
152152
fetchImage={mockFetchImage}
153153
onDelete={mockOnDelete}
154+
isRteEnabled={true}
154155
/>,
155156
);
156157

@@ -195,6 +196,7 @@ describe('IssueCommentComponent', () => {
195196
fetchUsers={mockFetchUsers}
196197
fetchImage={mockFetchImage}
197198
onDelete={mockOnDelete}
199+
isRteEnabled={true}
198200
/>,
199201
);
200202

src/webviews/components/issue/view-issue-screen/mainpanel/IssueCommentComponent.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type IssueCommentComponentProps = {
2525
fetchUsers: (input: string) => Promise<any[]>;
2626
fetchImage: (url: string) => Promise<string>;
2727
onDelete: (commentId: string) => void;
28+
isRteEnabled?: boolean;
2829
};
2930
const CommentComponent: React.FC<{
3031
siteDetails: DetailedSiteInfo;
@@ -34,7 +35,17 @@ const CommentComponent: React.FC<{
3435
onDelete: (commentId: string) => void;
3536
fetchUsers: (input: string) => Promise<any[]>;
3637
isServiceDeskProject?: boolean;
37-
}> = ({ siteDetails, comment, onSave, fetchImage, onDelete, fetchUsers, isServiceDeskProject }) => {
38+
isRteEnabled?: boolean;
39+
}> = ({
40+
siteDetails,
41+
comment,
42+
onSave,
43+
fetchImage,
44+
onDelete,
45+
fetchUsers,
46+
isServiceDeskProject,
47+
isRteEnabled = false,
48+
}) => {
3849
const [isEditing, setIsEditing] = React.useState(false);
3950
const [isSaving, setIsSaving] = React.useState(false);
4051
const bodyText = comment.renderedBody ? comment.renderedBody : comment.body;
@@ -105,6 +116,7 @@ const CommentComponent: React.FC<{
105116
setIsEditing(false);
106117
onSave(commentText, comment.id, JsdInternalCommentVisibility);
107118
}}
119+
featureGateEnabled={isRteEnabled}
108120
/>
109121
) : (
110122
<RenderedContent html={bodyText} fetchImage={fetchImage} />
@@ -124,7 +136,8 @@ const AddCommentComponent: React.FC<{
124136
user: User;
125137
onCreate: (t: string, restriction?: CommentVisibility) => void;
126138
isServiceDeskProject?: boolean;
127-
}> = ({ fetchUsers, user, onCreate, isServiceDeskProject }) => {
139+
isRteEnabled?: boolean;
140+
}> = ({ fetchUsers, user, onCreate, isServiceDeskProject, isRteEnabled = false }) => {
128141
const [commentText, setCommentText] = React.useState('');
129142
const [isEditing, setIsEditing] = React.useState(false);
130143

@@ -177,6 +190,7 @@ const AddCommentComponent: React.FC<{
177190
setCommentText('');
178191
setIsEditing(false);
179192
}}
193+
featureGateEnabled={isRteEnabled}
180194
/>
181195
)}
182196
</Box>
@@ -193,10 +207,16 @@ export const IssueCommentComponent: React.FC<IssueCommentComponentProps> = ({
193207
fetchUsers,
194208
fetchImage,
195209
onDelete,
210+
isRteEnabled = false,
196211
}) => {
197212
return (
198213
<Box style={{ display: 'flex', flexDirection: 'column', paddingTop: '8px' }}>
199-
<AddCommentComponent fetchUsers={fetchUsers} user={currentUser} onCreate={onCreate} />
214+
<AddCommentComponent
215+
fetchUsers={fetchUsers}
216+
user={currentUser}
217+
onCreate={onCreate}
218+
isRteEnabled={isRteEnabled}
219+
/>
200220
{comments
201221
.sort((a, b) => (a.created > b.created ? -1 : 1))
202222
.map((comment: JiraComment) => (
@@ -209,6 +229,7 @@ export const IssueCommentComponent: React.FC<IssueCommentComponentProps> = ({
209229
onDelete={onDelete}
210230
fetchUsers={fetchUsers}
211231
isServiceDeskProject={isServiceDeskProject}
232+
isRteEnabled={isRteEnabled}
212233
/>
213234
))}
214235
</Box>

0 commit comments

Comments
 (0)