Commit Graph

2 Commits

Author SHA1 Message Date
matevip
b4aef56c89 fix(channels): close QR loading dead-window for feishu and dingtalk register flows
Reported issue: click 'scan to create' -> button momentarily flickers
loading -> button re-enables but no QR shows up -> blank for 1-2 seconds
-> QR suddenly appears. Looks broken even though it works.

Root cause: loading.value flipped back to false the moment the begin HTTP
call returned (sessionId in hand), but the actual QR image only arrives on
the first status poll, which the existing code waited a full 2 seconds
for. Between begin completing and the first poll firing the UI was a
disabled button + nothing.

Three coordinated changes:
- useFeishuAppRegister and useDingTalkAppRegister: keep loading.value true
  through begin AND across the polls, only flip false when the QR image
  is actually populated (or a terminal failure status arrives). Also run
  an immediate first poll right after begin instead of waiting for the
  setInterval tick — usually the first poll already has the rendered QR
  for dingtalk, and pushes the feishu user roughly 2 seconds closer.
- ChannelEditModal: same-sized loading placeholder (min-height 240px,
  matching the QR card) that renders when loading is true and no QR is
  in hand. CSS spinner ring tinted with the channel brand color (feishu
  indigo, dingtalk blue) and a new
  channels.{feishu,dingtalk}Register.qrcodeLoading hint. The placeholder
  swaps to the real image with no layout shift.
- i18n: new qrcodeLoading key in zh-CN and en-US for both flows.

Net effect: click to spinner-visible is ~50ms; the user is never staring
at a frozen button-without-content again.
2026-04-28 11:14:14 +08:00
matevip
acf6eccb3a feat(dingtalk): one-click bot creation via OAuth device flow
Mirrors the feishu one-click flow: scan a QR with the DingTalk app,
approve, and the bot's client_id / client_secret get auto-filled instead
of forcing the user through the open-dev console. Saves about seven
manual steps per channel setup.

Backend
- Bump dingtalk-stream from 1.3.5 to 1.3.12. Diff against the classes we
  depend on (OpenDingTalkStreamClient, ChatbotMessage, MessageContent,
  GenericEventListener) is empty — pure point-release bumps, no API churn.
- New DingTalkAppRegistrationService: synchronously runs init + begin
  against /app/registration/{init,begin} on oapi.dingtalk.com to obtain
  the device_code and verification URL, then spawns a daemon worker that
  polls /app/registration/poll every 5s until SUCCESS / FAIL / EXPIRED is
  returned. Sessions evict after 7 minutes, worker has a 6-minute hard
  runtime cap, transient HTTP errors do not terminate the loop. Same
  shape as the feishu service, but written from scratch because the
  dingtalk-stream SDK doesn't wrap this OAuth device flow.
- Two new endpoints under /api/v1/channels/webhook:
  POST /dingtalk/register/begin returns session_id;
  GET  /dingtalk/register/status returns status + qrcode_img (data URI
  PNG, ZXing-encoded from the verification URL, matching the feishu and
  weixin flows). Status surface: waiting / confirmed / expired / denied.

Frontend
- channelApi.dingtalkRegisterBegin / dingtalkRegisterStatus.
- New useDingTalkAppRegister composable, structurally identical to
  useFeishuAppRegister minus the domain argument. Stops polling on
  terminal status, fires onConfirmed with {clientId, clientSecret}.
- ChannelEditModal: dingtalk-register-card rendered when channelType is
  dingtalk, scoped DingTalk blue (#1f79ff) to differentiate from feishu's
  indigo. onConfirmed writes channelConfig.client_id / client_secret so
  the existing form fields update reactively.
- i18n: channels.dingtalkRegister.* keys for title / hint / button states
  / scan / confirmed / expired / denied / startFailed.
2026-04-28 11:12:22 +08:00