Skip to content

Commit ba90785

Browse files
authored
Remove the global websocket feature flag (#226)
1 parent 3d6fb13 commit ba90785

File tree

4 files changed

+33
-60
lines changed

4 files changed

+33
-60
lines changed

frontend/src/constants/featureFlags.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { retrieveValue, storeValue } from '@/utils/storage'
22

3-
export type FeatureFlag = 'useWebsockets' | 'sendViaWebsocket' | 'refreshStaleData'
3+
export type FeatureFlag = 'sendViaWebsocket' | 'refreshStaleData'
44

55
export interface FeatureFlagDefinition {
66
name: FeatureFlag
@@ -9,14 +9,9 @@ export interface FeatureFlagDefinition {
99
}
1010

1111
export const featureFlagDefinitions: FeatureFlagDefinition[] = [
12-
{
13-
name: 'useWebsockets',
14-
description: 'Use websockets',
15-
defaultValue: false,
16-
},
1712
{
1813
name: 'sendViaWebsocket',
19-
description: 'Send requests via WebSocket (requires websockets)',
14+
description: 'Send requests via WebSocket',
2015
defaultValue: false,
2116
},
2217
{

frontend/src/utils/websocket.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ export class WebSocketManager {
1616
private socket: WebSocket | null = null
1717
private retryCount = 0
1818
private manualClose = false
19-
private enabled: boolean = store.getState().featureFlags.useWebsockets
2019
private listeners: Map<WSEvent, Set<WebSocketEventListener>> = new Map()
2120
private pendingRequests: Map<
2221
string,
@@ -30,25 +29,7 @@ export class WebSocketManager {
3029
private reconnectTimer?: ReturnType<typeof setTimeout>
3130

3231
private constructor() {
33-
if (this.enabled) {
34-
this.connect()
35-
}
36-
37-
store.subscribe(() => {
38-
const newState = store.getState()
39-
const newEnabledState = newState.featureFlags.useWebsockets
40-
41-
// If websockets were disabled, disconnect
42-
if (this.enabled && !newEnabledState) {
43-
this.enabled = newEnabledState
44-
this.disconnect()
45-
}
46-
// If websockets were enabled, try to connect
47-
else if (!this.enabled && newEnabledState) {
48-
this.enabled = newEnabledState
49-
this.connect()
50-
}
51-
})
32+
this.connect()
5233
}
5334

5435
static getInstance(): WebSocketManager {
@@ -305,7 +286,7 @@ export class WebSocketManager {
305286
}
306287

307288
private scheduleReconnect() {
308-
if (this.manualClose || !this.enabled) {
289+
if (this.manualClose) {
309290
return
310291
}
311292

frontend/src/views/Navigation/SyncStatus.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import { RootState } from '@/store/store'
66
import { SyncState } from '@/models/sync'
77

88
interface SyncStatusProps {
9-
websocketsEnabled: boolean
10-
119
style?: React.CSSProperties
1210
userStatus: SyncState
1311
userError: string | null
@@ -77,9 +75,7 @@ class SyncStatusImpl extends React.Component<SyncStatusProps, SyncStatusState> {
7775
{ name: 'Tokens', status: tokensStatus, error: tokensError },
7876
]
7977

80-
if (this.props.websocketsEnabled) {
81-
statuses.push({ name: 'WebSocket', status: wsStatus, error: wsError })
82-
}
78+
statuses.push({ name: 'WebSocket', status: wsStatus, error: wsError })
8379

8480
return statuses
8581
}
@@ -154,7 +150,6 @@ class SyncStatusImpl extends React.Component<SyncStatusProps, SyncStatusState> {
154150
}
155151

156152
const mapStateToProps = (state: RootState) => ({
157-
websocketsEnabled: state.featureFlags.useWebsockets,
158153
userStatus: state.user.status,
159154
userError: state.user.error,
160155
tasksStatus: state.tasks.status,

frontend/test/constants/featureFlags.test.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ describe('featureFlags', () => {
1313

1414
describe('setFeatureFlag', () => {
1515
it('should store feature flag with correct prefix', () => {
16-
setFeatureFlag('useWebsockets', true)
17-
const storedValue = localStorage.getItem(FEATURE_FLAG_PREFIX + 'useWebsockets')
16+
setFeatureFlag('sendViaWebsocket', true)
17+
const storedValue = localStorage.getItem(
18+
FEATURE_FLAG_PREFIX + 'sendViaWebsocket',
19+
)
1820
expect(storedValue).toBe('true')
1921
})
2022

@@ -25,36 +27,36 @@ describe('featureFlags', () => {
2527
})
2628

2729
it('should update existing feature flag', () => {
28-
setFeatureFlag('useWebsockets', true)
29-
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'useWebsockets')).toBe('true')
30+
setFeatureFlag('sendViaWebsocket', true)
31+
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'sendViaWebsocket')).toBe('true')
3032

31-
setFeatureFlag('useWebsockets', false)
32-
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'useWebsockets')).toBe('false')
33+
setFeatureFlag('sendViaWebsocket', false)
34+
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'sendViaWebsocket')).toBe('false')
3335
})
3436

3537
it('should handle multiple feature flags independently', () => {
36-
setFeatureFlag('useWebsockets', true)
38+
setFeatureFlag('sendViaWebsocket', true)
3739
setFeatureFlag('refreshStaleData', false)
3840

39-
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'useWebsockets')).toBe('true')
41+
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'sendViaWebsocket')).toBe('true')
4042
expect(localStorage.getItem(FEATURE_FLAG_PREFIX + 'refreshStaleData')).toBe('false')
4143
})
4244
})
4345

4446
describe('getFeatureFlag', () => {
4547
it('should return stored value when flag exists', () => {
46-
localStorage.setItem(FEATURE_FLAG_PREFIX + 'useWebsockets', 'true')
47-
const result = getFeatureFlag('useWebsockets', false)
48+
localStorage.setItem(FEATURE_FLAG_PREFIX + 'sendViaWebsocket', 'true')
49+
const result = getFeatureFlag('sendViaWebsocket', false)
4850
expect(result).toBe(true)
4951
})
5052

5153
it('should return default value when flag does not exist', () => {
52-
const result = getFeatureFlag('useWebsockets', false)
54+
const result = getFeatureFlag('sendViaWebsocket', false)
5355
expect(result).toBe(false)
5456
})
5557

5658
it('should return different default values correctly', () => {
57-
const result1 = getFeatureFlag('useWebsockets', true)
59+
const result1 = getFeatureFlag('sendViaWebsocket', true)
5860
expect(result1).toBe(true)
5961

6062
const result2 = getFeatureFlag('refreshStaleData', false)
@@ -68,13 +70,13 @@ describe('featureFlags', () => {
6870
})
6971

7072
it('should retrieve true value correctly', () => {
71-
localStorage.setItem(FEATURE_FLAG_PREFIX + 'useWebsockets', 'true')
72-
const result = getFeatureFlag('useWebsockets', false)
73+
localStorage.setItem(FEATURE_FLAG_PREFIX + 'sendViaWebsocket', 'true')
74+
const result = getFeatureFlag('sendViaWebsocket', false)
7375
expect(result).toBe(true)
7476
})
7577

7678
it('should handle all feature flag types', () => {
77-
const flags: FeatureFlag[] = ['useWebsockets', 'sendViaWebsocket', 'refreshStaleData']
79+
const flags: FeatureFlag[] = ['sendViaWebsocket', 'refreshStaleData']
7880

7981
flags.forEach(flag => {
8082
setFeatureFlag(flag, true)
@@ -85,8 +87,8 @@ describe('featureFlags', () => {
8587

8688
describe('getFeatureFlag and setFeatureFlag integration', () => {
8789
it('should store and retrieve feature flag correctly', () => {
88-
setFeatureFlag('useWebsockets', true)
89-
expect(getFeatureFlag('useWebsockets', false)).toBe(true)
90+
setFeatureFlag('sendViaWebsocket', true)
91+
expect(getFeatureFlag('sendViaWebsocket', false)).toBe(true)
9092
})
9193

9294
it('should update and retrieve updated value', () => {
@@ -98,25 +100,25 @@ describe('featureFlags', () => {
98100
})
99101

100102
it('should maintain feature flag values independently', () => {
101-
setFeatureFlag('useWebsockets', true)
103+
setFeatureFlag('sendViaWebsocket', true)
102104
setFeatureFlag('refreshStaleData', false)
103105

104-
expect(getFeatureFlag('useWebsockets', false)).toBe(true)
106+
expect(getFeatureFlag('sendViaWebsocket', false)).toBe(true)
105107
expect(getFeatureFlag('refreshStaleData', true)).toBe(false)
106108
})
107109

108110
it('should handle toggling feature flags', () => {
109111
// Initial state
110-
setFeatureFlag('useWebsockets', false)
111-
expect(getFeatureFlag('useWebsockets', false)).toBe(false)
112+
setFeatureFlag('sendViaWebsocket', false)
113+
expect(getFeatureFlag('sendViaWebsocket', false)).toBe(false)
112114

113115
// Toggle on
114-
setFeatureFlag('useWebsockets', true)
115-
expect(getFeatureFlag('useWebsockets', false)).toBe(true)
116+
setFeatureFlag('sendViaWebsocket', true)
117+
expect(getFeatureFlag('sendViaWebsocket', false)).toBe(true)
116118

117119
// Toggle off
118-
setFeatureFlag('useWebsockets', false)
119-
expect(getFeatureFlag('useWebsockets', false)).toBe(false)
120+
setFeatureFlag('sendViaWebsocket', false)
121+
expect(getFeatureFlag('sendViaWebsocket', false)).toBe(false)
120122
})
121123
})
122124

@@ -126,7 +128,7 @@ describe('featureFlags', () => {
126128
})
127129

128130
it('should be used as prefix for all feature flags', () => {
129-
setFeatureFlag('useWebsockets', true)
131+
setFeatureFlag('sendViaWebsocket', true)
130132
const keys = Object.keys(localStorage)
131133
const flagKeys = keys.filter(key => key.startsWith(FEATURE_FLAG_PREFIX))
132134
expect(flagKeys.length).toBeGreaterThan(0)

0 commit comments

Comments
 (0)