mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 17:36:45 +08:00
* MUL-8280: refactor(issues): trim issue sidebar header actions - Drop settings-only '…' menus from Properties, Quick Actions, Wakeups and Plugins; keep the Pull requests menu, which carries a per-issue action (keep status on merge). - Remove the Quick Actions '+' (workspace-level creation belongs in Settings) and hide the section again when there are no actions. - Restore the inline '+ Add property' row with its popover instead of the header icon. Co-authored-by: multica-agent <[email protected]> * MUL-8280: fix(issues): bound the add property list to the viewport The Popover that replaced the header DropdownMenu has no height bound, so a long property catalog pushed its tail options off-screen. Cap it to --available-height and scroll inside, and add an e2e that wheels to the last option and picks it. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: multica-agent <[email protected]>
65 lines
2.6 KiB
TypeScript
65 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo, useState } from "react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { pluginInstallationsOptions } from "@multica/core/plugins";
|
|
import { useCurrentWorkspace } from "@multica/core/paths";
|
|
import { useFeatureEnabled } from "@multica/core/config";
|
|
import { PLUGINS_V1_FLAG } from "@multica/core/feature-flags";
|
|
import { useT } from "../i18n";
|
|
import { isDesktopShell } from "../platform/local-directory";
|
|
import { IssueSidebarSectionHeader } from "../issues/components/issue-sidebar-section";
|
|
import { PluginSurfaceFrame } from "./plugin-surface-frame";
|
|
|
|
/**
|
|
* Renders every enabled `issue_panel` surface on an issue.
|
|
*
|
|
* Disabled installations are filtered here AND refused by the Action API — the
|
|
* client filter is presentation, the server check is the control. A surface
|
|
* left open in a stale tab stops working even though this component never
|
|
* re-rendered.
|
|
*/
|
|
export function PluginPanelSection({ issueId }: { issueId: string }) {
|
|
const { t } = useT("issues");
|
|
const [open, setOpen] = useState(true);
|
|
const platform = isDesktopShell() ? "desktop" : "web";
|
|
const workspace = useCurrentWorkspace();
|
|
const wsId = workspace?.id ?? "";
|
|
const pluginsEnabled = useFeatureEnabled(PLUGINS_V1_FLAG, false);
|
|
|
|
const { data } = useQuery({ ...pluginInstallationsOptions(wsId), enabled: pluginsEnabled && wsId.length > 0 });
|
|
|
|
const panels = useMemo(() => {
|
|
const installations = data?.plugins ?? [];
|
|
return installations
|
|
.filter((installation) => installation.enabled === true)
|
|
.flatMap((installation) =>
|
|
installation.surfaces
|
|
.filter((surface) => surface.type === "issue_panel")
|
|
// An empty list means "anywhere"; a declared list is a filter, not a
|
|
// hint, or a desktop-only panel renders on web anyway.
|
|
.filter((surface) => (surface.platforms ?? []).length === 0 || (surface.platforms ?? []).includes(platform))
|
|
.map((surface) => ({ installation, surface })),
|
|
);
|
|
}, [data, platform]);
|
|
|
|
if (!pluginsEnabled || panels.length === 0) return null;
|
|
|
|
return (
|
|
<section>
|
|
<IssueSidebarSectionHeader title={t(($) => $.plugins.panels)} open={open} onOpenChange={setOpen} count={panels.length} />
|
|
<div hidden={!open} className="space-y-2 px-2">
|
|
{panels.map(({ installation, surface }) => (
|
|
<PluginSurfaceFrame
|
|
key={`${installation.id}:${surface.key}`}
|
|
wsId={wsId}
|
|
installation={installation}
|
|
surface={surface}
|
|
issueId={issueId}
|
|
/>
|
|
))}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|