Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Use these conventions for all UI work under `lib/public/js` and `lib/public/css`
- Use the `htm` + `preact` pattern:
- `const html = htm.bind(h);`
- return `html\`...\``
- In `htm` templates, be explicit with inline spacing around styled inline tags (`<span>`, `<code>`, `<a>`): use ` ${" "}` where needed, and verify rendered copy so words never collapse (`eventsand`) or gain double spaces.
- Prefer early return for hidden states (e.g. `if (!visible) return null;`).
- Use `<PageHeader />` for tab/page headers that need a title and right-side actions.
- Use card shells consistently: `bg-surface border border-border rounded-xl`.
Expand Down
17 changes: 17 additions & 0 deletions lib/public/assets/icons/slack.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions lib/public/js/components/add-channel-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { h } from "https://esm.sh/preact";
import htm from "https://esm.sh/htm";
import { ActionButton } from "./action-button.js";
import { AddLineIcon } from "./icons.js";
import { OverflowMenu, OverflowMenuItem } from "./overflow-menu.js";

const html = htm.bind(h);

export const AddChannelMenu = ({
open = false,
onClose = () => {},
onToggle = () => {},
triggerDisabled = false,
channelIds = [],
getChannelMeta = () => ({ label: "Channel", iconSrc: "" }),
isChannelDisabled = () => false,
onSelectChannel = () => {},
}) => html`
<${OverflowMenu}
open=${open}
ariaLabel="Add channel"
title="Add channel"
onClose=${onClose}
onToggle=${onToggle}
renderTrigger=${({ onToggle: handleToggle, ariaLabel, title }) => html`
<${ActionButton}
onClick=${handleToggle}
disabled=${triggerDisabled}
loading=${false}
loadingMode="inline"
tone="subtle"
size="sm"
idleLabel="Add channel"
loadingLabel="Opening..."
idleIcon=${AddLineIcon}
idleIconClassName="h-3.5 w-3.5"
iconOnly=${true}
title=${title}
ariaLabel=${ariaLabel}
/>
`}
>
${channelIds.map((channelId) => {
const channelMeta = getChannelMeta(channelId);
const disabled = !!isChannelDisabled(channelId);
return html`
<${OverflowMenuItem}
key=${channelId}
iconSrc=${channelMeta.iconSrc}
disabled=${disabled}
onClick=${() => onSelectChannel(channelId)}
>
${channelMeta.label}
</${OverflowMenuItem}>
`;
})}
</${OverflowMenu}>
`;

52 changes: 14 additions & 38 deletions lib/public/js/components/agents-tab/agent-bindings-section/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { h } from "https://esm.sh/preact";
import htm from "https://esm.sh/htm";
import { isChannelProviderDisabledForAdd } from "../../../lib/channel-provider-availability.js";
import { AddChannelMenu } from "../../add-channel-menu.js";
import { ActionButton } from "../../action-button.js";
import { ALL_CHANNELS, ChannelsCard, getChannelMeta } from "../../channels.js";
import { ConfirmDialog } from "../../confirm-dialog.js";
import { AddLineIcon } from "../../icons.js";
import { OverflowMenu, OverflowMenuItem } from "../../overflow-menu.js";
import { CreateChannelModal } from "../create-channel-modal.js";
import { ChannelCardItem } from "./channel-item-trailing.js";
import { useAgentBindings } from "./use-agent-bindings.js";
Expand Down Expand Up @@ -50,7 +51,7 @@ export const AgentBindingsSection = ({
setShowCreateModal,
showCreateModal,
} = useAgentBindings({ agent, agents });
const { hasDiscordAccount, mergedChannelItems } = useChannelItems({
const { mergedChannelItems } = useChannelItems({
agentId,
agentNameMap,
channelStatus,
Expand Down Expand Up @@ -108,48 +109,23 @@ export const AgentBindingsSection = ({
/>`;
}}
actions=${html`
<${OverflowMenu}
<${AddChannelMenu}
open=${menuOpenId === "__create_channel"}
ariaLabel="Add channel"
title="Add channel"
onClose=${() => setMenuOpenId("")}
onToggle=${() =>
setMenuOpenId((current) =>
current === "__create_channel" ? "" : "__create_channel",
)}
renderTrigger=${({ onToggle, ariaLabel, title }) => html`
<${ActionButton}
onClick=${onToggle}
disabled=${saving}
loading=${false}
loadingMode="inline"
tone="subtle"
size="sm"
loadingLabel="Opening..."
idleIcon=${AddLineIcon}
idleIconClassName="h-3.5 w-3.5"
iconOnly=${true}
title=${title}
ariaLabel=${ariaLabel}
idleLabel="Add channel"
/>
`}
>
${ALL_CHANNELS.map((channelId) => {
const channelMeta = getChannelMeta(channelId);
const isDisabled = channelId === "discord" && hasDiscordAccount;
return html`
<${OverflowMenuItem}
key=${channelId}
iconSrc=${channelMeta.iconSrc}
disabled=${isDisabled}
onClick=${() => openCreateChannelModal(channelId)}
>
${channelMeta.label}
</${OverflowMenuItem}>
`;
})}
</${OverflowMenu}>
triggerDisabled=${saving}
channelIds=${ALL_CHANNELS}
getChannelMeta=${getChannelMeta}
isChannelDisabled=${(channelId) =>
isChannelProviderDisabledForAdd({
configuredChannelMap,
provider: channelId,
})}
onSelectChannel=${openCreateChannelModal}
/>
`}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ export const useChannelItems = ({
defaultAgentId = "",
isDefaultAgent = false,
}) => {
const hasDiscordAccount = useMemo(() => {
const discordChannel = configuredChannelMap.get("discord");
return Array.isArray(discordChannel?.accounts) && discordChannel.accounts.length > 0;
}, [configuredChannelMap]);

const [showAssignedElsewhere, setShowAssignedElsewhere] = useState(false);

const channelItemData = useMemo(() => {
Expand Down Expand Up @@ -205,7 +200,6 @@ export const useChannelItems = ({
}, [assignedElsewhereItems, showAssignedElsewhere, visibleChannelItems]);

return {
hasDiscordAccount,
mergedChannelItems,
};
};
Loading