Repository navigation
feat(import): import link v2 opens the New upstream dialog - #320
Merged
Merged
Conversation
Import links could only carry a name, address, protocol, key and model
list, and opened a confirmation dialog where only the name could be
changed. Upstreams have grown since, so v2 (the contract shared with the
website and the enterprise edition) lets a link set everything the New
upstream dialog lets a user set for the chosen service and
authentication method, and opens that dialog itself, prefilled.
Parser (src-tauri/src/import_link.rs):
- A parameter is accepted only when the dialog shows its field for the
chosen service and auth method; the per-service rules live in one table
(SERVICES). It is exported to src/generated/import-services.json and
checked by tests/ts_bindings.rs, and src/import/services.test.ts checks
that JSON against PRESETS, fieldRules, authOptions and serviceOf, so the
Rust and TypeScript rules cannot drift apart.
- Without `service` the address picks the service the edit dialog would
recognize; when a parameter does not fit it, the link is read as Custom,
so every v1 link stays valid.
- Unknown parameter names are no longer silent: the UI shows "Cannot
import this link" with the update state (the name only when it matches
^[a-z0-9_]{1,32}$). Never-accepted names and invalid values still reject
the link silently. No value may contain `$`, `{` or `}`.
- Plain http:// is accepted for loopback and private-network addresses
(v2.2); the dialog then says the address is not encrypted.
Dialog:
- The link opens UpstreamDialog in create mode on step 2, like the Bedrock
draft path; a one-line note on every step names the host(s) requests
and keys go to. Nothing reaches any host before Next or a sign-in.
- Specs are written after the upstream exists, only for models on the
final list; the Models step says which are skipped.
- `price_multiplier` / `prices` preselect a new price sheet, editable as a
draft and created together with the upstream (removed again if the
upstream cannot be created). A taken sheet name has to be changed.
- Account links open on the sign-in panel and never replace an existing
Z.ai upstream's key.
- A link that arrives while a dialog is open is dropped and the gate
released; closing the import dialog in any way releases it.
- Custom upstreams get a visible Balance source field in Advanced
settings, so a link's `balance` can be seen and changed.
The note's height is added to the dialog's height, so every step that fit
at 1100x720 before still fits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fylorn
added a commit
that referenced
this pull request
Oct 11, 2026
* fix(upstreams): undo layout squeezed only to avoid a scrollbar #319 and #320 made every step of the upstream dialog fit 1100x720 without a scrollbar, including the steps with many settings. That rule was meant for steps with few options and a lot of empty space. Steps with many settings may scroll: the dialog keeps its fixed height and its body scrolls. Options crammed into columns, descriptions dropped and results moved into hovers only to save a few rows go back to their natural form. The approved redesign stays (service tiles and search, auth rows, Advanced settings collapsed unless set, Check on Next when creating, sign-in cards, account summary rows, the import host note). - Edit dialog: Check connection is back in the Connection section body, with the full result and the balance below it, not in the footer with the details in a hover. - Advanced settings, expanded: headers full width, then Forward client identity with its description, then the short fields two per row (proxy unavailable, concurrency limit with its description, and the balance source for Custom as a normal labelled field). - Connection: the base URL is full width again, protocol and region share the next row; AWS access keys and OAuth go back to two columns with the session token and access token on their own rows; the English "Auto-detect (not detected, forwarded as is)" that was shortened for the narrow protocol column is back. Spacing back to the form's gap-4. - Descriptions restored, as worded before: base URL, headers (${NAME}), session token, OAuth access token, and the egress note on the ChatGPT account page; also the Z.ai key-storage notice and the full device code warning, which had been cut to fit one line. - ChatGPT account page: name and egress in two columns with the concurrency limit below, usage limits above reset credits, gap-5. - Import link: the dialog no longer grows by the note's height; the note takes its space from the body, and long host names wrap instead of being cut off. - Billing: the price sheet rows keep their normal padding, and the import link's new-sheet row wraps its detail and its error instead of truncating them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Base URL and protocol share a row again The user approved that row in the design; a step with few fields does not need the extra line, and the base URL hint still sits under the address. The undetected label stays short for the narrower column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Implements import link v2 (the contract shared with the website and the enterprise edition, including clarifications v2.1 and v2.2).
What a link can do now
A link can set everything the New upstream dialog lets a user set for the chosen service and authentication method:
service,auth,site,name,url,protocol,key, the OAuth credentials, Bedrock region and access keys,headers,client_identity,concurrency,balance(Custom only),models,models_only,specs,billing,price_multiplierandprices.It opens the New upstream dialog itself, prefilled, instead of a separate confirmation dialog. The v1
ImportDialogand its strings and test are deleted.Parser (
src-tauri/src/import_link.rs)SERVICES.tests/ts_bindings.rsexports the table tosrc/generated/import-services.json(regenerate withUPDATE_TS=1, the same as the bindings).src/import/services.test.tschecks that JSON againstPRESETS,fieldRules,authOptions,serviceOfandZAI_ENDPOINTS. If either side changes without the other, that test fails.service. The parser takes the service the edit dialog would recognize from the address. If any parameter does not fit that service, the link is read as Custom, so every v1 link stays valid (https://api.openai.com/v1, Ollama withkey, DeepSeek withprotocol=openai-chat).ImportLink::Unsupported. The UI shows Cannot import this link with the updater's state: Check for updates, or Install update plus the "update, then open this link again" line when an update is known, and Close. The parameter name is shown only when it matches^[a-z0-9_]{1,32}$. The never-accepted names and invalid values are still rejected silently.$,{,}or control or invisible characters; forheadersthe check runs per line.http://is accepted for loopback, private IPv4/IPv6 ranges and intranet-style names (v2.2). The dialog then adds "This address is not encrypted; the key and request content travel in plain text."take_import_linknow returnsImportLink, a proposal or unsupported, through the same one-at-a-timeGate.Tests cover:
$,{,}and control or invisible characters in every parameter;172.15/172.16,100.63/100.64,fbff::/fc00::,.corpvs.com, …);Dialog
auth=account), with step 1 counted as visited. This is the same path as the Bedrock draft (nav.open("upstreams", { create: "upstream", imported })).PreviewProviderandQueryPricecalls run before that. I checked this by reading every effect that runs when the dialog opens, and in the harness, where the calls before Next contain noTestProvideror sign-in and no request leaves for a non-local host.SetModelSpecafter the upstream exists, only for models on the final list. The Models step says which models are skipped. The table shows the link's context window in the meantime.price_multiplier/pricespreselect a new sheet named after the upstream. It can be edited as a draft inPriceSheetDialog(newdraftmode, which writes nothing) and is created on Create before the upstream. If the upstream cannot be created, the new sheet is deleted again. A taken sheet name blocks Create until it is changed.Verification
pnpm typecheckandpnpm test(1192 tests) pass.cargo fmt --check,cargo clippy --all-targets -- -D warningsandcargo testpass.models_only, specs and prices, Bedrock with access keys, Custom OAuth with a token endpoint on another host, a ChatGPT account, a Z.ai account withsite, a v1 link, an unknown parameter, an intranethttp://gateway, and Custom with a balance source.scrollHeightstays withinclientHeighton every step visited.TestProvidercall and no sign-in happens before Next.🤖 Generated with Claude Code