mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-16 19:29:26 +02:00
fix(lark): hide only the Lark (international) connect entry; keep Feishu (#3835)
Mainland Feishu binding works; only the newly-added Lark (international, open.larksuite.com) install path is unreliable — some Lark installs complete on Lark's side but never persist a lark_installation row (no WS, no inbound, no task). Hide just the "Bind to Lark" CTA behind a single LARK_INTL_CONNECT_ENABLED flag and leave the "Bind to Feishu" entry, the settings panel, and all existing-installation management untouched. Flip LARK_INTL_CONNECT_ENABLED back to true to restore the Lark CTA; nothing else changes. Temporary measure while the Lark install-landing bug is investigated. - LarkAgentBindButton: the Lark button is gated by the flag; the Feishu button and the Connected badge / Manage / Disconnect are unchanged. - Tests: the CTA tests assert Feishu shown + Lark hidden; the Feishu click-to-begin (region=feishu) test stays; the Lark click test was removed (no button) and noted for restore; the dialog polling-error tests open via the Feishu CTA. MUL-3083 Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -187,28 +187,24 @@ function resetFixtures() {
|
||||
describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
beforeEach(resetFixtures);
|
||||
|
||||
it("renders both Feishu and Lark bind CTAs when the viewer is a workspace owner and install is supported", () => {
|
||||
// The CTA was split into two explicit entry points — one per cloud
|
||||
// — so the begin POST hits the right accounts host up front (no
|
||||
// tenant-brand mid-poll auto-switch from a Feishu-first start) and
|
||||
// the QR / dialog copy reflects the cloud the user picked. Both
|
||||
// buttons must mount side by side for owners/admins; either one
|
||||
// alone would re-introduce the "Lark user has to scan a Feishu QR"
|
||||
// confusion this split is meant to remove (MUL-3083 follow-up).
|
||||
it("shows the Feishu bind CTA but hides the Lark CTA for an owner (MUL-3083)", () => {
|
||||
// Mainland Feishu binding stays available; the Lark (international)
|
||||
// entry is temporarily hidden via LARK_INTL_CONNECT_ENABLED while its
|
||||
// install→inbound pipeline is stabilized (MUL-3083).
|
||||
render(<LarkAgentBindButton agentId="agent-1" agentName="Bot" />, {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
expect(screen.getByRole("button", { name: /Bind to Feishu/i })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: /Bind to Lark/i })).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /Bind to Lark/i })).toBeNull();
|
||||
});
|
||||
|
||||
it("renders both bind CTAs when the viewer is a workspace admin", () => {
|
||||
it("shows the Feishu bind CTA but hides the Lark CTA for an admin (MUL-3083)", () => {
|
||||
membersRef.current = [{ user_id: "user-1", role: "admin" }];
|
||||
render(<LarkAgentBindButton agentId="agent-1" agentName="Bot" />, {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
expect(screen.getByRole("button", { name: /Bind to Feishu/i })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: /Bind to Lark/i })).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /Bind to Lark/i })).toBeNull();
|
||||
});
|
||||
|
||||
it("hides both bind CTAs for a non-admin agent owner (matches backend admin gate)", () => {
|
||||
@@ -258,28 +254,12 @@ describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("clicking Bind to Lark begins an install with region='lark'", async () => {
|
||||
const user = userEvent.setup();
|
||||
mockBeginInstall.mockResolvedValue({
|
||||
session_id: "sess-lark",
|
||||
qr_code_url: "https://accounts.larksuite.com/oauth/v1/device?u=lark",
|
||||
expires_in_seconds: 300,
|
||||
poll_interval_seconds: 2,
|
||||
});
|
||||
mockGetStatus.mockResolvedValue({ status: "pending" });
|
||||
render(<LarkAgentBindButton agentId="agent-1" agentName="Bot" />, {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
await user.click(screen.getByRole("button", { name: /Bind to Lark/i }));
|
||||
await waitFor(() => {
|
||||
expect(mockBeginInstall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
expect(mockBeginInstall).toHaveBeenCalledWith(
|
||||
"workspace-1",
|
||||
"agent-1",
|
||||
"lark",
|
||||
);
|
||||
});
|
||||
// NOTE (MUL-3083): the "clicking Bind to Lark begins an install with
|
||||
// region='lark'" test was removed alongside the temporarily-hidden Lark
|
||||
// (international) CTA — there is no Lark button to click while
|
||||
// LARK_INTL_CONNECT_ENABLED is false. The Feishu region routing is still
|
||||
// pinned by the "clicking Bind to Feishu …" test above; restore the Lark
|
||||
// case when the entry is re-enabled.
|
||||
|
||||
it("swaps the bind CTAs for a 'Connected + Manage in Lark' badge when this agent already has an active installation", () => {
|
||||
// Anti-zombie guard: re-scanning the same agent upserts the row
|
||||
@@ -352,7 +332,7 @@ describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
expect(link.href).toBe("https://open.larksuite.com/app/cli_lark_app");
|
||||
});
|
||||
|
||||
it("still shows both bind CTAs when an installation exists for a DIFFERENT agent (per-agent scoping)", () => {
|
||||
it("shows the Feishu CTA (Lark hidden) for an agent without its own installation, per-agent scoping (MUL-3083)", () => {
|
||||
installationsRef.current.installations = [
|
||||
{
|
||||
id: "inst-other",
|
||||
@@ -371,7 +351,7 @@ describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
expect(screen.getByRole("button", { name: /Bind to Feishu/i })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: /Bind to Lark/i })).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /Bind to Lark/i })).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps the Connected + Manage badge for an already-installed agent even when new installs are unavailable (install_supported=false)", () => {
|
||||
@@ -413,7 +393,7 @@ describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("still shows both bind CTAs when this agent's only installation is revoked (treat as not-installed for re-bind)", () => {
|
||||
it("shows the Feishu CTA (Lark hidden) when this agent's only installation is revoked (MUL-3083)", () => {
|
||||
installationsRef.current.installations = [
|
||||
{
|
||||
id: "inst-revoked",
|
||||
@@ -432,7 +412,7 @@ describe("LarkAgentBindButton (CTA gate)", () => {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
expect(screen.getByRole("button", { name: /Bind to Feishu/i })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: /Bind to Lark/i })).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /Bind to Lark/i })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -599,7 +579,9 @@ describe("LarkInstallDialog (polling terminal errors)", () => {
|
||||
render(<LarkAgentBindButton agentId="agent-1" agentName="Bot" />, {
|
||||
wrapper: I18nWrapper,
|
||||
});
|
||||
await user.click(screen.getByRole("button", { name: /Bind to Lark/i }));
|
||||
// The Lark CTA is hidden (MUL-3083); open the dialog via the Feishu CTA
|
||||
// — the polling-error behavior under test is region-agnostic.
|
||||
await user.click(screen.getByRole("button", { name: /Bind to Feishu/i }));
|
||||
// Let the begin-session promise resolve and the QR render.
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("qr-code")).toBeTruthy();
|
||||
@@ -673,7 +655,9 @@ describe("LarkInstallDialog (polling terminal errors)", () => {
|
||||
render(<LarkAgentBindButton agentId="agent-1" agentName="Bot" />, {
|
||||
wrapper: StrictModeWrapper,
|
||||
});
|
||||
await user.click(screen.getByRole("button", { name: /Bind to Lark/i }));
|
||||
// The Lark CTA is hidden (MUL-3083); the StrictMode regression is about
|
||||
// the dialog mount cycle, so open it via the Feishu CTA.
|
||||
await user.click(screen.getByRole("button", { name: /Bind to Feishu/i }));
|
||||
|
||||
// The QR must appear even though the dialog mounted, unmounted, and
|
||||
// mounted again under StrictMode. The previous bug left the body
|
||||
|
||||
@@ -43,6 +43,15 @@ import type { LarkInstallation, LarkInstallStatusResponse } from "@multica/core/
|
||||
import { ActorAvatar } from "../../common/actor-avatar";
|
||||
import { useT } from "../../i18n";
|
||||
|
||||
// MUL-3083: the Lark (international, open.larksuite.com) "connect a Bot"
|
||||
// entry is temporarily hidden while its install → inbound pipeline is
|
||||
// stabilized — some Lark installs complete on Lark's side but never land a
|
||||
// `lark_installation` row, so the Bot silently can't receive messages.
|
||||
// Mainland Feishu is unaffected and keeps its bind entry. Existing
|
||||
// installations (either cloud) stay fully manageable. Flip this back to
|
||||
// `true` to restore the "Bind to Lark" CTA; nothing else needs to change.
|
||||
const LARK_INTL_CONNECT_ENABLED: boolean = false;
|
||||
|
||||
// LarkTab is the workspace settings panel for Lark Bot installations.
|
||||
// Listing is member-visible; the disconnect action is admin-only (the
|
||||
// backend enforces it; the UI hides the button for non-admins to match).
|
||||
@@ -389,21 +398,26 @@ export function LarkAgentBindButton({
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
{t(($) => $.lark.bind_button_feishu)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setDialogRegion("lark")}
|
||||
disabled={!agentId}
|
||||
title={
|
||||
agentName
|
||||
? t(($) => $.lark.bind_button_lark_title, { agent: agentName })
|
||||
: undefined
|
||||
}
|
||||
data-testid="lark-agent-bind-lark"
|
||||
>
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
{t(($) => $.lark.bind_button_lark)}
|
||||
</Button>
|
||||
{/* MUL-3083: Lark (international) bind entry is temporarily hidden —
|
||||
see LARK_INTL_CONNECT_ENABLED. Mainland Feishu (above) is
|
||||
unaffected. */}
|
||||
{LARK_INTL_CONNECT_ENABLED && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setDialogRegion("lark")}
|
||||
disabled={!agentId}
|
||||
title={
|
||||
agentName
|
||||
? t(($) => $.lark.bind_button_lark_title, { agent: agentName })
|
||||
: undefined
|
||||
}
|
||||
data-testid="lark-agent-bind-lark"
|
||||
>
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
{t(($) => $.lark.bind_button_lark)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{dialogRegion && (
|
||||
<LarkInstallDialog
|
||||
|
||||
Reference in New Issue
Block a user