diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui index 9bbf7bc..167a50e 100755 --- a/src/codex-launcher-gui +++ b/src/codex-launcher-gui @@ -2802,7 +2802,7 @@ class LauncherWin(Gtk.Window): dlg = Gtk.Dialog(title="OAuth 2.0 Client Secrets", parent=self, modal=True) dlg.add_button("Cancel", Gtk.ResponseType.CANCEL) dlg.add_button("Save", Gtk.ResponseType.OK) - dlg.set_default_size(520, 340) + dlg.set_default_size(540, 420) area = dlg.get_content_area() area.set_margin_start(16) area.set_margin_end(16) @@ -2814,7 +2814,13 @@ class LauncherWin(Gtk.Window): fields = {} for section_key, section_label in [("antigravity", "Antigravity (CloudCode)"), ("gemini_cli", "Gemini CLI")]: - area.pack_start(Gtk.Label(label=f"\n{section_label}", use_markup=True, xalign=0), False, False, 2) + section_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) + hdr_row = Gtk.Box(spacing=6) + hdr_row.pack_start(Gtk.Label(label=f"\n{section_label}", use_markup=True, xalign=0), True, True, 0) + import_btn = Gtk.Button(label="Import JSON") + import_btn.set_size_request(100, -1) + hdr_row.pack_end(import_btn, False, False, 0) + section_box.pack_start(hdr_row, False, False, 2) sec = data.get(section_key, {}) for fk, fl in [("client_id", "Client ID"), ("client_secret", "Client Secret")]: row = Gtk.Box(spacing=6) @@ -2828,10 +2834,12 @@ class LauncherWin(Gtk.Window): entry.set_invisible_char("*") row.pack_start(lbl, False, False, 0) row.pack_start(entry, True, True, 0) - area.pack_start(row, False, False, 2) + section_box.pack_start(row, False, False, 2) fields[(section_key, fk)] = entry + import_btn.connect("clicked", lambda b, sk=section_key: self._import_oauth_json(fields, sk)) + area.pack_start(section_box, False, False, 0) - area.pack_start(Gtk.Label(label="\nGet credentials from console.cloud.google.com → APIs & Services → Credentials", use_markup=True, xalign=0), False, False, 4) + area.pack_start(Gtk.Label(label="\nImport a client_secret_*.json from Google Cloud Console\nor edit fields manually. console.cloud.google.com → Credentials", use_markup=True, xalign=0), False, False, 4) area.show_all() if dlg.run() == Gtk.ResponseType.OK: @@ -2848,6 +2856,32 @@ class LauncherWin(Gtk.Window): self._show_error_dialog("Save failed", str(e)) dlg.destroy() + def _import_oauth_json(self, fields, section_key): + chooser = Gtk.FileChooserDialog( + title="Import Google OAuth Client Secret JSON", + parent=self, action=Gtk.FileChooserAction.OPEN) + chooser.add_button("Cancel", Gtk.ResponseType.CANCEL) + chooser.add_button("Open", Gtk.ResponseType.OK) + filt = Gtk.FileFilter() + filt.set_name("JSON files") + filt.add_pattern("*.json") + chooser.add_filter(filt) + if chooser.run() == Gtk.ResponseType.OK: + path = chooser.get_filename() + try: + with open(path) as f: + raw = json.load(f) + creds = raw.get("installed") or raw.get("web") or raw + cid = creds.get("client_id", "") + csec = creds.get("client_secret", "") + if not cid or not csec: + raise ValueError("JSON does not contain client_id and client_secret") + fields[(section_key, "client_id")].set_text(cid) + fields[(section_key, "client_secret")].set_text(csec) + except Exception as e: + self._show_error_dialog("Import failed", str(e)) + chooser.destroy() + # ═══════════════════════════════════════════════════════════════════ # Endpoint manager dialog # ═══════════════════════════════════════════════════════════════════