Skip to content

Commit 7d8e522

Browse files
fix(launcher): fix proxy save button and duplicate detection logic (#95)
* refactor: rename BotBrowserConsole to BotBrowserLauncher * feat: add kernel management, proxy management, and setup scripts * fix: enable macOS native Edit menu for Cmd+C/V/X/A keyboard shortcuts * chore: upgrade Neutralino runtime to 6.4.0 * chore: remove Neutralino binaries from repo, download via neu update * fix: improve macOS clipboard support with JS fallback for Cmd+V paste * fix: expand macOS clipboard fallback to Cmd+C/X, auto-download Neutralino via postinstall * chore: upgrade Neutralino to 6.5.0 and simplify setup scripts * fix: fix PowerShell setup script ZIP download corruption * feat: enhance proxy workflow with IP check, quick change, and reusable input component * fix: correct checkbox color override and setup script stdin handling * feat: improve profile deletion with auto-stop, group WebRTC settings, prioritize custom exec path * feat: add port protection toggle, fix kernel auto-update cleanup and UI refresh * fix: detect kernel assets by file extension to support renamed Windows/Linux packages * fix: handle non-browser process exits, add crash detection, validate kernel executable paths * docs: add --bot-time-seed documentation, changelog 2026-03-03, value range and per-context cross-links * feat: add proxy save/check, improve table layout and kernel date display - Add "Save to proxy list" button in proxy input for reusing manually entered proxies - Add batch proxy connectivity check with IP/status display in proxy management - Sort proxy list by creation time (newest first) - Fix kernel date display: parse from asset filename, fix timezone offset bug - Simplify profile status column to icon-only (play/stop) with tooltips - Remove year from "Last Launch" date to prevent truncation - Widen window to 1080px, use fixed table layout to prevent horizontal scrollbar - Add column width constraints for profile and proxy tables * feat: redesign profile editor with left nav, advanced config modes, and new fields - Add left-side anchor navigation with scrollspy (IntersectionObserver) - Split Fingerprint into separate Noise and Rendering sections - Replace expansion panel with flat Advanced section layout - Add mode toggles for Executable (kernel/custom), Cookies and Bookmarks (file/input) - Add FPS dropdown (profile/real/custom number) instead of free-text input - Add Save IP button in proxy section for explicit IP saving - Add new fields: Time Seed, Proxy Bypass Regex, Cookies, Bookmarks, Custom Headers - Put username/password on same row in proxy input - Widen status column to prevent icon clipping * fix: replace Save IP with Save to proxy list, unify dropdown option labels * fix: include username and password in proxy duplicate detection Normalize both sides with `|| ''` to handle undefined values, and add password to the comparison so proxies with the same host:port but different credentials are treated as distinct entries.
1 parent ba59247 commit 7d8e522

4 files changed

Lines changed: 17 additions & 37 deletions

File tree

launcher/src/app/edit-browser-profile.component.html

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
7474
<mat-form-field>
7575
<mat-label>Select existing proxy</mat-label>
7676
<mat-select [(value)]="selectedProxyId" (selectionChange)="onProxySelected($event.value)">
77-
<mat-option value="">-- None --</mat-option>
77+
<mat-option value="">None</mat-option>
7878
@for (proxy of proxies; track proxy.id) {
7979
<mat-option [value]="proxy.id"
8080
>{{ proxy.name }} ({{ proxy.type }}://{{ proxy.host }}:{{ proxy.port }})</mat-option
@@ -88,12 +88,10 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
8888
[value]="proxyValue"
8989
[showQuickParse]="true"
9090
[showCheckButton]="true"
91-
[showSaveButton]="!selectedProxyId"
92-
[showSaveIpButton]="true"
91+
[showSaveButton]="true"
9392
(valueChange)="onProxyValueChange($event)"
9493
(ipCheckResult)="onIpCheckResult($event)"
9594
(saveToList)="onSaveProxyToList($event)"
96-
(saveIp)="onSaveIp($event)"
9795
/>
9896

9997
<div class="section-title">Advanced Proxy Config</div>
@@ -189,7 +187,7 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
189187
<mat-form-field class="flex-1">
190188
<mat-label>Platform</mat-label>
191189
<mat-select formControlName="botConfigPlatform">
192-
<mat-option value="">-- Default --</mat-option>
190+
<mat-option value="">Default</mat-option>
193191
@for (platform of platforms; track platform) {
194192
<mat-option [value]="platform">{{ platform }}</mat-option>
195193
}
@@ -211,7 +209,7 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
211209
<mat-form-field class="flex-1">
212210
<mat-label>Architecture</mat-label>
213211
<mat-select formControlName="botConfigArchitecture">
214-
<mat-option value="">-- Default --</mat-option>
212+
<mat-option value="">Default</mat-option>
215213
@for (arch of architectures; track arch) {
216214
<mat-option [value]="arch">{{ arch }}</mat-option>
217215
}
@@ -221,7 +219,7 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
221219
<mat-form-field class="flex-1">
222220
<mat-label>Bitness</mat-label>
223221
<mat-select formControlName="botConfigBitness">
224-
<mat-option value="">-- Default --</mat-option>
222+
<mat-option value="">Default</mat-option>
225223
@for (bit of bitnesses; track bit) {
226224
<mat-option [value]="bit">{{ bit }}-bit</mat-option>
227225
}
@@ -351,7 +349,7 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
351349
<mat-form-field class="flex-1">
352350
<mat-label>FPS</mat-label>
353351
<mat-select [(value)]="fpsMode" (selectionChange)="onFpsModeChange()">
354-
<mat-option value="">-- Default --</mat-option>
352+
<mat-option value="">Default</mat-option>
355353
<mat-option value="profile">profile</mat-option>
356354
<mat-option value="real">real</mat-option>
357355
<mat-option value="number">Custom</mat-option>

launcher/src/app/edit-browser-profile.component.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,14 @@ export class EditBrowserProfileComponent implements OnInit, AfterViewInit, OnDes
367367
this.selectedProxyId = '';
368368
}
369369

370+
onIpCheckResult(result: ProxyCheckResult): void {
371+
this.proxyConfigGroup.patchValue({ proxyIp: result.ip });
372+
}
373+
370374
async onSaveProxyToList(proxy: ParsedProxy): Promise<void> {
371-
const duplicate = this.proxies.find((p) => p.host === proxy.host && p.port === proxy.port);
375+
const duplicate = this.proxies.find(
376+
(p) => p.host === proxy.host && p.port === proxy.port && (p.username || '') === (proxy.username || '') && (p.password || '') === (proxy.password || '')
377+
);
372378
if (duplicate) {
373379
this.#dialog.open(AlertDialogComponent, {
374380
data: { message: `Proxy ${proxy.host}:${proxy.port} already exists in the proxy list.` },
@@ -391,14 +397,6 @@ export class EditBrowserProfileComponent implements OnInit, AfterViewInit, OnDes
391397
});
392398
}
393399

394-
onIpCheckResult(_result: ProxyCheckResult): void {
395-
// IP saving is handled by the Save IP button via onSaveIp
396-
}
397-
398-
onSaveIp(ip: string): void {
399-
this.proxyConfigGroup.patchValue({ proxyIp: ip });
400-
}
401-
402400
async chooseFile(): Promise<void> {
403401
let entries: string[];
404402
try {

launcher/src/app/quick-proxy-change.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ export class QuickProxyChangeComponent implements OnInit {
9595
}
9696

9797
async onSaveProxyToList(proxy: ParsedProxy): Promise<void> {
98-
const duplicate = this.proxies.find((p) => p.host === proxy.host && p.port === proxy.port);
98+
const duplicate = this.proxies.find(
99+
(p) => p.host === proxy.host && p.port === proxy.port && (p.username || '') === (proxy.username || '') && (p.password || '') === (proxy.password || '')
100+
);
99101
if (duplicate) {
100102
this.#dialog.open(AlertDialogComponent, {
101103
data: { message: `Proxy ${proxy.host}:${proxy.port} already exists in the proxy list.` },

launcher/src/app/shared/proxy-input.component.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ import { ProxyParserService, type ParsedProxy } from './proxy-parser.service';
8888
</div>
8989
</form>
9090
91-
@if (showCheckButton || showSaveButton || showSaveIpButton) {
91+
@if (showCheckButton || showSaveButton) {
9292
<div class="check-ip-section">
9393
<div class="button-row">
9494
@if (showCheckButton) {
@@ -101,11 +101,6 @@ import { ProxyParserService, type ParsedProxy } from './proxy-parser.service';
101101
}
102102
</button>
103103
}
104-
@if (showSaveIpButton) {
105-
<button mat-stroked-button (click)="onSaveIp()" [disabled]="!checkResult || ipSaved">
106-
{{ ipSaved ? 'IP Saved' : 'Save IP' }}
107-
</button>
108-
}
109104
@if (showSaveButton && getValue()) {
110105
<button mat-stroked-button (click)="onSaveToList()">
111106
Save to proxy list
@@ -301,8 +296,6 @@ export class ProxyInputComponent {
301296
@Input() showQuickParse = true;
302297
@Input() showCheckButton = false;
303298
@Input() showSaveButton = false;
304-
@Input() showSaveIpButton = false;
305-
306299
@Input() set value(v: ParsedProxy | null) {
307300
if (v) {
308301
this.formGroup.patchValue(
@@ -326,8 +319,6 @@ export class ProxyInputComponent {
326319
@Output() valueChange = new EventEmitter<ParsedProxy | null>();
327320
@Output() ipCheckResult = new EventEmitter<ProxyCheckResult>();
328321
@Output() saveToList = new EventEmitter<ParsedProxy>();
329-
@Output() saveIp = new EventEmitter<string>();
330-
331322
quickParseInput = '';
332323
parseError = '';
333324
parseSuccess = false;
@@ -336,7 +327,6 @@ export class ProxyInputComponent {
336327
checkResult: ProxyCheckResult | null = null;
337328
checkError = '';
338329
copyTooltip = 'Copy IP';
339-
ipSaved = false;
340330

341331
readonly formGroup = this.#formBuilder.group({
342332
type: 'http' as ProxyType,
@@ -381,7 +371,6 @@ export class ProxyInputComponent {
381371
this.checking = true;
382372
this.checkResult = null;
383373
this.checkError = '';
384-
this.ipSaved = false;
385374

386375
try {
387376
const result = await this.#proxyCheck.checkProxy(proxy);
@@ -414,13 +403,6 @@ export class ProxyInputComponent {
414403
}
415404
}
416405

417-
onSaveIp(): void {
418-
if (this.checkResult) {
419-
this.saveIp.emit(this.checkResult.ip);
420-
this.ipSaved = true;
421-
}
422-
}
423-
424406
onSaveToList(): void {
425407
const value = this.getValue();
426408
if (value) this.saveToList.emit(value);

0 commit comments

Comments
 (0)