Skip to content

Commit 698a3fd

Browse files
committed
Add browser profile name input and use it for identifying connected browsers in the editor
- [Fragment] should use 'bangers' font - because user can run multiple sandboxed browser profiles, to distinguish between them, they should be able to give them an optional name. Whenever browser name changes, reconnect so that it's updated on the editor's extension side. - refer to 'profile name' as profile name, not just name - never show user agent to the user (limit its usage to determining browser name) - [Pasted text] - connected browsers should be listed alphabetically (if having profile name set, those without profile names, list at the end) ├── apps │ ├── browser │ │ ├── src │ │ │ ├── background │ │ │ │ ├── clear-chat-init-data.ts │ │ │ │ ├── config.ts │ │ │ │ ├── keep-alive.ts │ │ │ │ ├── main.ts │ │ │ │ ├── message-handler.ts │ │ │ │ └── websocket.ts │ │ │ ├── fonts │ │ │ │ └── Bangers-Regular.ttf │ │ │ ├── icons │ │ │ │ ├── icon-128.png │ │ │ │ ├── icon-16.png │ │ │ │ ├── icon-32.png │ │ │ │ └── icon-48.png │ │ │ ├── manifest.json │ │ │ ├── types │ │ │ │ └── messages.ts │ │ │ ├── utils │ │ │ │ └── is-message.ts │ │ │ └── views │ │ │ └── popup │ │ │ ├── App.tsx │ │ │ ├── Popup.module.scss │ │ │ ├── Popup.tsx │ │ │ ├── index.css │ │ │ ├── index.html │ │ │ ├── use-browser-profile-name.ts │ │ │ └── use-firefox-containers.ts │ │ └── webpack.config.ts │ └── editor │ └── src │ ├── constants │ │ └── state-keys.ts │ └── services │ ├── websocket-manager.ts │ └── websocket-server-process.ts └── packages ├── shared │ └── src │ └── types │ └── websocket-message.ts └── ui └── src └── styles ├── foundation │ └── _variables.scss └── global.scss
1 parent ddf6b3a commit 698a3fd

10 files changed

Lines changed: 137 additions & 21 deletions

File tree

‎apps/browser/src/background/websocket.ts‎

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ let websocket: WebSocket | null = null
66
let is_reconnecting = false
77
let last_ping_timestamp = Date.now()
88

9+
browser.storage.onChanged.addListener((changes, areaName) => {
10+
if (areaName == 'local' && changes['browser-profile-name']) {
11+
if (websocket) {
12+
is_reconnecting = false
13+
const old_ws = websocket
14+
websocket = null
15+
old_ws.close()
16+
}
17+
connect_websocket()
18+
}
19+
})
20+
921
export const check_server_health = async (): Promise<boolean> => {
1022
try {
1123
const response = await fetch(`http://localhost:${DEFAULT_PORT}/health`)
@@ -16,7 +28,7 @@ export const check_server_health = async (): Promise<boolean> => {
1628
}
1729

1830
export const check_and_recover_connection = () => {
19-
if (websocket?.readyState === WebSocket.OPEN) {
31+
if (websocket?.readyState == WebSocket.OPEN) {
2032
if (Date.now() - last_ping_timestamp > 20000) {
2133
console.warn(
2234
'WebSocket connection is stale (no recent pings). Force reconnecting...'
@@ -28,8 +40,8 @@ export const check_and_recover_connection = () => {
2840

2941
if (
3042
!is_reconnecting &&
31-
websocket?.readyState !== WebSocket.OPEN &&
32-
websocket?.readyState !== WebSocket.CONNECTING
43+
websocket?.readyState != WebSocket.OPEN &&
44+
websocket?.readyState != WebSocket.CONNECTING
3345
) {
3446
connect_websocket()
3547
}
@@ -38,8 +50,8 @@ export const check_and_recover_connection = () => {
3850
export const connect_websocket = async (): Promise<void> => {
3951
if (
4052
is_reconnecting ||
41-
websocket?.readyState === WebSocket.OPEN ||
42-
websocket?.readyState === WebSocket.CONNECTING
53+
websocket?.readyState == WebSocket.OPEN ||
54+
websocket?.readyState == WebSocket.CONNECTING
4355
) {
4456
return
4557
}
@@ -59,9 +71,17 @@ export const connect_websocket = async (): Promise<void> => {
5971
const version = manifest.version
6072
const user_agent = navigator.userAgent
6173

62-
const ws = new WebSocket(
63-
`ws://localhost:${DEFAULT_PORT}?token=${SECURITY_TOKENS.BROWSERS}&version=${version}&user_agent=${encodeURIComponent(user_agent)}`
64-
)
74+
const storage = await browser.storage.local.get('browser-profile-name')
75+
const profile_name = (
76+
storage['browser-profile-name'] as string | undefined
77+
)?.trim()
78+
79+
let ws_url = `ws://localhost:${DEFAULT_PORT}?token=${SECURITY_TOKENS.BROWSERS}&version=${version}&user_agent=${encodeURIComponent(user_agent)}`
80+
if (profile_name) {
81+
ws_url += `&profile_name=${encodeURIComponent(profile_name)}`
82+
}
83+
84+
const ws = new WebSocket(ws_url)
6585
websocket = ws
6686

6787
ws.onopen = () => {
90.3 KB
Binary file not shown.

‎apps/browser/src/views/popup/Popup.module.scss‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
gap: 12px;
88

99
&__title {
10-
font-size: 16px;
10+
font-family: 'Bangers';
11+
font-size: 24px;
1112
margin: 0;
1213
}
1314

@@ -21,6 +22,27 @@
2122
gap: 8px;
2223
}
2324

25+
&__profile-name {
26+
width: 100%;
27+
display: flex;
28+
flex-direction: column;
29+
align-items: center;
30+
gap: 8px;
31+
}
32+
33+
&__input-label {
34+
font-size: 14px;
35+
align-self: flex-start;
36+
}
37+
38+
&__profile-name-input {
39+
width: 100%;
40+
padding: 6px;
41+
box-sizing: border-box;
42+
border: 1px solid #ccc;
43+
border-radius: 4px;
44+
}
45+
2446
&__enable-button {
2547
background: #0060df;
2648
color: white;
@@ -36,6 +58,9 @@
3658

3759
&__container-select {
3860
width: 100%;
39-
padding: 4px;
61+
padding: 6px;
62+
box-sizing: border-box;
63+
border: 1px solid #ccc;
64+
border-radius: 4px;
4065
}
4166
}

‎apps/browser/src/views/popup/Popup.tsx‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react'
22
import styles from './Popup.module.scss'
33
import { use_firefox_containers } from './use-firefox-containers'
4+
import { use_browser_profile_name } from './use-browser-profile-name'
45

56
export const Popup: React.FC = () => {
67
const {
@@ -12,11 +13,25 @@ export const Popup: React.FC = () => {
1213
handle_container_change
1314
} = use_firefox_containers()
1415

16+
const { profile_name, handle_profile_name_change } =
17+
use_browser_profile_name()
18+
1519
return (
1620
<div className={styles.popup}>
17-
<p className={styles['popup__title']}>
18-
Autofill for Code Web Chat is alive
19-
</p>
21+
<p className={styles['popup__title']}>Code Web Chat</p>
22+
23+
<div className={styles['popup__profile-name']}>
24+
<label className={styles['popup__input-label']}>
25+
Browser Profile Name:
26+
</label>
27+
<input
28+
type="text"
29+
value={profile_name}
30+
onChange={handle_profile_name_change}
31+
className={styles['popup__profile-name-input']}
32+
placeholder="e.g. Work, Personal"
33+
/>
34+
</div>
2035

2136
{is_firefox && (
2237
<div className={styles['popup__firefox']}>

‎apps/browser/src/views/popup/index.css‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
@font-face {
2+
font-family: 'Bangers';
3+
src: url('fonts/Bangers-Regular.ttf') format('truetype');
4+
font-weight: normal;
5+
font-style: normal;
6+
}
7+
18
body {
29
margin: 0;
310
font-family:
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { useEffect, useState } from 'react'
2+
import browser from 'webextension-polyfill'
3+
4+
export const use_browser_profile_name = () => {
5+
const [profile_name, set_profile_name] = useState<string>('')
6+
7+
useEffect(() => {
8+
const init = async () => {
9+
const storage = await browser.storage.local.get('browser-profile-name')
10+
set_profile_name((storage['browser-profile-name'] as string) || '')
11+
}
12+
init()
13+
}, [])
14+
15+
const handle_profile_name_change = async (
16+
e: React.ChangeEvent<HTMLInputElement>
17+
) => {
18+
const value = e.target.value
19+
set_profile_name(value)
20+
if (value) {
21+
await browser.storage.local.set({ 'browser-profile-name': value })
22+
} else {
23+
await browser.storage.local.remove('browser-profile-name')
24+
}
25+
}
26+
27+
return {
28+
profile_name,
29+
handle_profile_name_change
30+
}
31+
}

‎apps/browser/webpack.config.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const config = (_: any, argv: Record<string, any>): webpack.Configuration => {
1717
patterns: [
1818
{ from: 'src/manifest.json', to: 'manifest.json' },
1919
{ from: 'src/icons', to: 'icons' },
20+
{ from: 'src/fonts', to: 'fonts' },
2021
{ from: 'src/views/popup/index.html', to: 'popup.html' },
2122
{ from: 'src/views/popup/index.css', to: 'index.css' }
2223
]

‎apps/editor/src/services/websocket-manager.ts‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,25 @@ export class WebSocketManager {
294294
LAST_SELECTED_BROWSER_ID_STATE_KEY
295295
)
296296

297-
const items = this.connected_browsers.map((b) => ({
298-
label: this._get_browser_name(b.user_agent),
299-
detail: b.user_agent,
300-
id: b.id
301-
}))
297+
const items = this.connected_browsers
298+
.map((b) => ({
299+
label: b.profile_name || this._get_browser_name(b.user_agent),
300+
description: b.profile_name
301+
? this._get_browser_name(b.user_agent)
302+
: undefined,
303+
id: b.id,
304+
_has_profile: !!b.profile_name
305+
}))
306+
.sort((a, b) => {
307+
if (a._has_profile && !b._has_profile) return -1
308+
if (!a._has_profile && b._has_profile) return 1
309+
return a.label.localeCompare(b.label)
310+
})
311+
.map((item) => ({
312+
label: item.label,
313+
description: item.description,
314+
id: item.id
315+
}))
302316

303317
return new Promise<number | undefined>((resolve) => {
304318
const quick_pick = vscode.window.createQuickPick<

‎apps/editor/src/services/websocket-server-process.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface BrowserClient {
2323
version: string
2424
id: number
2525
user_agent: string
26+
profile_name?: string
2627
is_alive: boolean
2728
}
2829

@@ -110,6 +111,7 @@ class WebSocketServer {
110111
private _handle_browser_connection(ws: WebSocket, url: URL) {
111112
const version = url.searchParams.get('version') || 'unknown'
112113
const user_agent = url.searchParams.get('user_agent') || 'unknown'
114+
const profile_name = url.searchParams.get('profile_name') || undefined
113115

114116
this.browser_client_counter++
115117
const id = this.browser_client_counter
@@ -119,6 +121,7 @@ class WebSocketServer {
119121
version,
120122
id,
121123
user_agent,
124+
profile_name,
122125
is_alive: true
123126
}
124127
this.browser_clients.set(id, client)
@@ -252,7 +255,8 @@ class WebSocketServer {
252255
return Array.from(this.browser_clients.values()).map((c) => ({
253256
id: c.id,
254257
version: c.version,
255-
user_agent: c.user_agent
258+
user_agent: c.user_agent,
259+
profile_name: c.profile_name
256260
}))
257261
}
258262

‎packages/shared/src/types/websocket-message.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { WebPromptType } from './prompt-types'
2-
31
export type Chat = {
42
url: string
53
model?: string
@@ -12,6 +10,7 @@ export type ConnectedBrowser = {
1210
id: number
1311
version: string
1412
user_agent: string
13+
profile_name?: string
1514
}
1615

1716
export type InitializeChatMessage = {

0 commit comments

Comments
 (0)