[Bug]: Browser preferences reject changes while a project is selected
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 50/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- frontend
Hướng nghiên cứu
Start with SETTINGS_DEVICE_ONLY_PATHS in apps/web/src/components/settings/SettingsScopeSentence.tsx and the deviceOnly prop passed from apps/web/src/routes/_chat.settings.tsx for /settings/browser. Then read BrowserSearchEngineSetting in IntegrationsSettings.tsx and the serverScoped handling in settingsLayout.tsx. Run the focused scope test in apps/web/src/components/settings/ before and after the change. Done when the Browser page's project scope either saves device preferences or shows the rows read-only, with no warning toast.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
On Settings → Browser, selecting a project leaves device preference controls interactive, but changing one produces a “Setting not saved” warning and leaves the preference unchanged. Device preferences are documented to ignore the project selection, and settings that cannot be overridden should be shown read-only. An isolated check reproduced the writer's rejection for Search engine and confirmed the active row and scope wiring in source; the full UI interaction was not run.
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/web
Steps to reproduce
- Run the script below against a clean checkout of the specified commit with installed dependencies; it creates and removes one uniquely named focused test file in that checkout.
- The focused test compares a valid browser search-engine patch in project and all-projects scopes. The script then checks that the Browser route remains scope-aware and that the Search engine row still offers the scoped writer through an active select.
One run reproduced the failure path. The direct pointer interaction in a running web or desktop client was not exercised; the row state and hook connection were confirmed from the pinned source. The script prints tool versions and returns 1 with RESULT: defect reproduced when both the rejection and active UI wiring are present, 0 with RESULT: expected behavior when that wiring changes, and 2 with RESULT: inconclusive if the focused test or setup fails. Save it as repro.sh, then run sh repro.sh "$PWD" from the checkout; Node, Vite+, and installed workspace dependencies are required.
Reproduction script: repro.sh
#!/bin/sh
set -eu
checkout=${1:?pass the T3 Code checkout path}
case "$checkout" in /*) ;; *) checkout=$(cd "$checkout" && pwd) ;; esac
scratch=$(mktemp -d)
test_file="$checkout/apps/web/src/components/settings/browser-scope.y02-01.test.ts"
if [ -e "$test_file" ]; then
echo 'RESULT: inconclusive'
exit 2
fi
cleanup() { rm -f "$test_file"; rm -rf "$scratch"; }
trap cleanup EXIT HUP INT TERM
export HOME="$scratch/home" TMPDIR="$scratch/tmp" T3CODE_HOME="$scratch/t3"
mkdir -p "$HOME" "$TMPDIR" "$T3CODE_HOME"
printf 'Node: %s\n' "$(node --version)"
vp --version | sed -n '1,3p'
cat > "$test_file" <<'TS'
import { DEFAULT_SERVER_SETTINGS, EnvironmentId } from "@t3tools/contracts";
import { expect, it } from "vite-plus/test";
import { planScopedSettingsPatch } from "./scopedSettings";
import type { ResolvedSettingsScope } from "./settingsScope";
it("compares Browser client-setting writes in project and all scopes", () => {
const id = EnvironmentId.make("example");
const environments = [{
environmentId: id,
label: "Example",
connection: { phase: "connected" as const },
serverConfig: { settings: DEFAULT_SERVER_SETTINGS },
}];
const project = {
kind: "project", environmentIds: [id], members: [],
} as unknown as ResolvedSettingsScope;
const all = {
kind: "all", environmentIds: [id], members: [],
} as unknown as ResolvedSettingsScope;
const patch = { browserSearchEngine: "google" as const };
const rejected = planScopedSettingsPatch(project, environments, patch);
const accepted = planScopedSettingsPatch(all, environments, patch);
expect(rejected).toMatchObject({
clientPatch: {}, hasClientWrite: false, serverWrites: [],
unavailableReason: "This setting is environment-wide and cannot be overridden by a project.",
});
expect(accepted).toMatchObject({
clientPatch: patch, hasClientWrite: true, unavailableReason: null,
});
});
TS
if ! (cd "$checkout" && vp test run apps/web/src/components/settings/browser-scope.y02-01.test.ts); then
echo 'RESULT: inconclusive'
exit 2
fi
node - "$checkout" <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const root = process.argv[2];
const read = (name) => fs.readFileSync(path.join(root, name), 'utf8');
const paths = read('apps/web/src/components/settings/SettingsScopeSentence.tsx');
const pathList = paths.match(/SETTINGS_DEVICE_ONLY_PATHS:[\s\S]*?new Set\(\[([\s\S]*?)\]\)/)?.[1];
const panel = read('apps/web/src/components/settings/IntegrationsSettings.tsx');
const search = panel.match(/function BrowserSearchEngineSetting\(\) \{([\s\S]*?)\nexport function PullRequestLinksOpenInAppSetting/)?.[1];
const route = read('apps/web/src/routes/_chat.settings.tsx');
const scopeAware = pathList !== undefined && !pathList.includes('"/settings/browser"') && route.includes('deviceOnly={SETTINGS_DEVICE_ONLY_PATHS.has(pathname)}');
const activeWrite = search !== undefined && search.includes('useUpdateScopedSettings()') && search.includes('updateSettings({ browserSearchEngine: next })') && !search.includes('serverScoped') && !search.includes('settingKeys=') && !search.includes('disabled=');
console.log(`Browser page keeps project scope: ${scopeAware}`);
console.log(`Search-engine control remains active and uses scoped writer: ${activeWrite}`);
if (!scopeAware || !activeWrite) {
console.log('RESULT: expected behavior');
process.exit(0);
}
console.log('RESULT: defect reproduced');
process.exit(1);
NODE
Expected behavior
Device preferences should ignore the selected project, as the user guide says, or the UI should present a read-only control for a value it cannot change at project scope: docs/user/project-settings.md#L3-L17. The Browser page's profile create, rename, and remove actions use the device writer in every scope, which demonstrates the existing device-preference pattern on this page: apps/web/src/components/settings/IntegrationsSettings.tsx#L1110-L1116.
Actual behavior
The Browser page exposes the project scope picker because /settings/browser is absent from SETTINGS_DEVICE_ONLY_PATHS, and the route passes deviceOnly={false} for that path: apps/web/src/components/settings/SettingsScopeSentence.tsx#L50-L60, apps/web/src/routes/_chat.settings.tsx#L146-L155. The Search engine row uses useUpdateScopedSettings, offers an enabled select, and submits browserSearchEngine when changed: apps/web/src/components/settings/IntegrationsSettings.tsx#L706-L751. The same panel renders this row outside the desktop-only group: apps/web/src/components/settings/IntegrationsSettings.tsx#L1581-L1608.
The isolated run found that a project-scoped browserSearchEngine patch has no client write or server write and returns “This setting is environment-wide and cannot be overridden by a project”; the same patch in all-projects scope has a client write. This follows the planner's client-only key rule: apps/web/src/components/settings/scopedSettings.ts#L220-L245, apps/web/src/components/settings/scopedSettings.ts#L331-L343. The update hook passes the page's deviceOnly value to that planner and shows a warning toast instead of persisting an unavailable patch: apps/web/src/components/settings/useScopedSettings.ts#L50-L62, apps/web/src/components/settings/useScopedSettings.ts#L100-L105.
Impact and scope
Impact: P2 - a project or checkout selection blocks changes to otherwise interactive browser preferences, but selecting All projects or an environment lets the same preference save.
The verified search-engine path is available in both web and desktop clients. Source inspection finds the same scoped writer on desktop browser viewport, zoom, appearance, recording, link-target, and floating-preview rows, and on the “Set as default” profile action: apps/web/src/components/settings/IntegrationsSettings.tsx#L323-L325, apps/web/src/components/settings/IntegrationsSettings.tsx#L473-L475, apps/web/src/components/settings/IntegrationsSettings.tsx#L562-L565, apps/web/src/components/settings/IntegrationsSettings.tsx#L654-L656, apps/web/src/components/settings/IntegrationsSettings.tsx#L1076-L1078, apps/web/src/components/settings/IntegrationsSettings.tsx#L1423-L1432. Those controls were not exercised at runtime. The failure does not corrupt the saved value; it prevents the requested change.
Earliest failure stage
Core processing
Analysis or suspected cause
SettingsRow only makes an environment-wide row inert at project scope when serverScoped is true; the Search engine row supplies neither that flag nor another disabled condition: apps/web/src/components/settings/settingsLayout.tsx#L305-L328, apps/web/src/components/settings/settingsLayout.tsx#L368-L379, apps/web/src/components/settings/settingsLayout.tsx#L427-L449.
Additional context
The six governing files checked have identical blobs on current main and the tested commit, so the checked path remains present.
Impact
Minor bug or occasional failure
Version or commit
main @ c00a373
Environment
Node.js v26.12.1, Vite+ v1.5.1 with local vite-plus v1.4.0 and Vitest v5.0.5, macOS arm64. The focused test ran on this platform.
Logs or stack traces
The script's output below is from the run against the stated commit. Vite+'s checkout path, run timestamp, duration, and advisory line were omitted from this excerpt; the result and diagnostic lines are unchanged.
Node: v26.12.1
vp v1.5.1
Local vite-plus:
vite-plus v1.4.0
Test Files 1 passed (1)
Tests 1 passed (1)
Browser page keeps project scope: true
Search-engine control remains active and uses scoped writer: true
RESULT: defect reproduced
Screenshots, recordings, or supporting files
No response
Workaround
Select All projects or an environment to save the same preference.
References
- https://github.com/pingdotgg/t3code/issues/35093 — closed report of the earlier project-scope overwrite; this report concerns the current rejection with an enabled control.
- https://github.com/pingdotgg/t3code/pull/35143 — merged fix for that overwrite; its description explicitly leaves the interactive project-scoped Browser rows unchanged.
- https://github.com/pingdotgg/t3code/issues/35094 — closed request for true per-project browser defaults; this report concerns editing existing device preferences.
- Ngôn ngữ chính
- TypeScript
- Star
- 24.8k
- Fork
- 6.4k
- Merge trung bình
- 59 phút
- Pull request đã merge (30 ngày)
- 418
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của pingdotgg/t3code
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
Maintainer thường phản hồi trong vòng 1 ngày
-
via-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: MCP App inline frames never go below 80px, so compact apps get blank space under themĐang mở
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Question card options show LaTeX as raw source, though the question text renders itCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: Settings inheritance popover shows raw slugs for branch naming, default permissions and response streamingCó thể đã có người làm @juliusmarminge đã nhận 1 ngày trước. Đang mởvouch:denounced
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của pingdotgg/t3code
Issue tương tự
-
bug platform:mobile root-cause:found
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
openchamber/openchamber#6926 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
push-based/user-flow#356 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Cygnux-Labs/Tracekit#827 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
www build: a refused import shows only "ENOENT scandir <outDir>", never the build-audience errorĐang mởkind:defect
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 91/100
Maintainer thường phản hồi trong vòng 1 ngày
-
type:bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
nightgauge/nightgauge#3266 ·
Maintainer thường phản hồi trong vòng 1 ngày