Improve local setup, token handling, and Chinese localization - #1
Open
makerjackie wants to merge 4 commits into
Open
Improve local setup, token handling, and Chinese localization#1makerjackie wants to merge 4 commits into
makerjackie wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves local developer ergonomics for CF Studio by (1) making the Tauri backend more reliable at discovering Node/Wrangler in GUI-launched environments, (2) resolving a Cloudflare auth/token precedence edge case, (3) introducing a simple i18n system with English and Simplified Chinese, and (4) adding public “fallback” implementations so the repo builds without private Pro modules/submodules.
Changes:
- Add a shell bootstrap helper for PATH discovery (nvm/Homebrew/npm-global) and reuse it for dependency probing and Wrangler refresh.
- Prefer
CLOUDFLARE_API_TOKEN(when set) over the local Wrangler OAuth config; add basic i18n with language selection persisted in the app store. - Remove the private
src/pro_modulessubmodule and add public placeholder/fallbacksrc/pro_modulesmodules + a Chinese README.
Reviewed changes
Copilot reviewed 41 out of 42 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/store/useAppStore.ts | Adds persisted language setting and setter. |
| src/lib/i18n.ts | Introduces translation tables and useI18n() helper. |
| src/components/SetupWizard.tsx | Replaces setup wizard strings with i18n keys. |
| src/components/SettingsView.tsx | Localizes settings UI and adds language selector. |
| src/components/SchemaVisualizer.tsx | Localizes schema empty-state strings. |
| src/components/R2ProGate.tsx | Localizes Pro gating labels/toasts and PRO badge text. |
| src/components/QueryEditor.tsx | Localizes editor strings, templates, tooltips, and pagination labels. |
| src/components/Layout.tsx | Localizes sidebar/titlebar; adds KV placeholder route/view. |
| src/components/IntelligencePanel.tsx | Localizes query intelligence messaging and actions. |
| src/components/FreeExportDialog.tsx | Localizes export upsell dialog strings. |
| src/components/ExportWrapper.tsx | Localizes lazy-load fallback text. |
| src/components/EditColumnDialog.tsx | Localizes column editor UI, diffs, and toasts. |
| src/components/DatabasesView.tsx | Localizes D1 empty states, headings, and history labels. |
| src/components/DatabaseExplorer.tsx | Localizes explorer UI (tabs, tooltips, pagination, dialogs). |
| src-tauri/src/shell_env.rs | Adds reusable shell/PATH bootstrap for GUI launch environments. |
| src-tauri/src/setup.rs | Reuses shell bootstrap for dependency checks and shell execution. |
| src-tauri/src/lib.rs | Wires public src/pro_modules/rust/* via #[path] modules. |
| src-tauri/src/cloudflare_auth.rs | Prefers CLOUDFLARE_API_TOKEN; uses login-shell PATH bootstrap for refresh. |
| src/pro_modules/ui/audits/SecurityPosture.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/audits/PerformancePosture.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/audits/Overview.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/audits/DomainScanner.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/audits/DnsEmailPosture.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/audits/AuditPreferences.tsx | Public placeholder UI for Pro audit screen. |
| src/pro_modules/ui/ActivityDashboard.tsx | Public placeholder UI for Pro history/dashboard screen. |
| src/pro_modules/rust/r2_worker_proxy.rs | Stub Rust file to keep public build self-contained. |
| src/pro_modules/rust/r2_pro.rs | Public stub implementations for Pro R2 commands. |
| src/pro_modules/rust/history.rs | Public stub implementations for Pro history commands. |
| src/pro_modules/rust/domain_audit.rs | Public stub implementations for Pro audit commands. |
| src/pro_modules/hooks/useD1TrackerLogic.ts | Public stub for tracked-query hook logic. |
| src/pro_modules/frontend/useRemoteConfig.ts | Public fallback remote config with Pro features disabled. |
| src/pro_modules/frontend/R2BucketsView.tsx | Public fallback R2 bucket/object listing UI. |
| src/pro_modules/frontend/PurchaseScreen.tsx | Public placeholder purchase/unavailable dialog. |
| src/pro_modules/frontend/ProFeatureGate.tsx | Public placeholder feature-gate dialog. |
| src/pro_modules/frontend/IndexManagerDialog.tsx | Public placeholder dialog (auto-closes). |
| src/pro_modules/frontend/AuditZoneContext.tsx | Public placeholder provider wrapper. |
| README.zh-CN.md | Adds Simplified Chinese README for local fork usage. |
| README.md | Links to the Chinese README. |
| docs/makerjackie-fork-requirements.md | Adds fork requirements/spec documentation. |
| .gitmodules | Removes private src/pro_modules submodule entry. |
| .gitignore | Adds LOCAL_DEV.md ignore entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+596
to
+613
| export type TranslationKey = keyof typeof translations["en-US"]; | ||
|
|
||
| export function useI18n() { | ||
| const language = useAppStore((state) => state.language); | ||
| const setLanguage = useAppStore((state) => state.setLanguage); | ||
|
|
||
| const interpolate = (value: string, vars?: Record<string, string | number>) => { | ||
| if (!vars) return value; | ||
| return value.replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? `{${key}}`)); | ||
| }; | ||
|
|
||
| return { | ||
| language, | ||
| setLanguage, | ||
| t: (key: TranslationKey, vars?: Record<string, string | number>) => | ||
| interpolate(translations[language][key] ?? translations["en-US"][key] ?? key, vars), | ||
| }; | ||
| } |
Comment on lines
+9
to
+16
| pub fn user_path_prefix() -> &'static str { | ||
| r#"export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"; | ||
| if [ -s "$NVM_DIR/nvm.sh" ]; then . "$NVM_DIR/nvm.sh" >/dev/null 2>&1; fi; | ||
| for d in "$HOME"/.nvm/versions/node/*/bin "$HOME"/.npm-global/bin /opt/homebrew/bin /usr/local/bin; do | ||
| if [ -d "$d" ]; then PATH="$d:$PATH"; fi; | ||
| done; | ||
| export PATH"# | ||
| } |
Comment on lines
+1
to
+16
| import type { D1TableSchema } from "@/hooks/useCloudflare"; | ||
|
|
||
| export function IndexManagerDialog({ | ||
| open, | ||
| onOpenChange, | ||
| }: { | ||
| databaseId: string; | ||
| open: boolean; | ||
| onOpenChange: (open: boolean) => void; | ||
| allTables: D1TableSchema[]; | ||
| }) { | ||
| if (open) { | ||
| queueMicrotask(() => onOpenChange(false)); | ||
| } | ||
| return null; | ||
| } |
Comment on lines
+7
to
+25
| #[tauri::command] | ||
| pub async fn fetch_cloudflare_zones() -> Result<Vec<Value>, String> { | ||
| Ok(Vec::new()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn create_r2_bucket(_bucket_name: String) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn delete_r2_bucket(_bucket_name: String) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn empty_r2_bucket(_bucket_name: String) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } |
Comment on lines
+27
to
+53
| #[tauri::command] | ||
| pub async fn upload_r2_object( | ||
| _bucket_name: String, | ||
| _key: String, | ||
| _local_path: String, | ||
| _upload_id: String, | ||
| ) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn cancel_upload_r2_object( | ||
| _upload_id: String, | ||
| _bucket_name: String, | ||
| _key: String, | ||
| ) -> Result<(), String> { | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn download_r2_object( | ||
| _bucket_name: String, | ||
| _key: String, | ||
| _destination_path: String, | ||
| ) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } |
Comment on lines
+55
to
+84
| #[tauri::command] | ||
| pub async fn update_r2_bucket_managed_domain( | ||
| _bucket_name: String, | ||
| _enabled: bool, | ||
| ) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn add_r2_bucket_custom_domain( | ||
| _bucket_name: String, | ||
| _domain: String, | ||
| _zone_id: String, | ||
| _zone_name: String, | ||
| ) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn remove_r2_bucket_custom_domain( | ||
| _bucket_name: String, | ||
| _domain: String, | ||
| ) -> Result<(), String> { | ||
| Err(unavailable()) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn get_r2_bucket_domains_list(_bucket_name: String) -> Result<Value, String> { | ||
| Ok(json!({ "managed": null, "custom": [] })) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hi Mubashar, thanks for building CF Studio. I have been trying it locally as a Cloudflare D1/R2 desktop workflow and found it useful, so I put together a few changes that may be helpful upstream.
This PR includes:
node,npm, andwranglerinstalled throughnvm, Homebrew, or npm global paths.CLOUDFLARE_API_TOKEN, but CF Studio still reads an older Wrangler OAuth config file and can hitinvalid access token.en-USandzh-CN, plus a language selector in Settings.src/pro_modulessubmodule so the public repository can be cloned and built without access to the private Pro repository.Why
The main bug I hit was on macOS: when a Tauri app is opened from Finder, it does not inherit the interactive shell
PATH. In that case,nodeandwranglerinstalled under~/.nvm/versions/node/.../binare available in Terminal but not visible to the app.I also hit an auth mismatch:
wrangler whoamiworked because Wrangler was usingCLOUDFLARE_API_TOKEN, while CF Studio read an olderoauth_tokenfrom~/Library/Preferences/.wrangler/config/default.toml, which produced an invalid-token API error. The change now prefersCLOUDFLARE_API_TOKENwhen it is present, and otherwise falls back to Wrangler OAuth config.The i18n changes are intentionally simple. They do not replace the existing English UI. English remains the default language, and
zh-CNis added as an optional language through the Settings screen.The public fallback for
src/pro_modulesis included because a fresh clone of the public repo cannot initialize the private submodule. I kept those fallback modules minimal and clearly scoped so they do not attempt to recreate the private Pro functionality.Verification
I verified locally with:
thx for opensource !