reorder skills for app integrations

This commit is contained in:
Timothy Carambat 2026-04-14 14:25:36 -07:00
parent 1c0d0301b0
commit f17337fb97
4 changed files with 95 additions and 18 deletions

View File

@ -133,7 +133,7 @@ export default function GMailSkillPanel({
a: ( a: (
<Link <Link
className="text-sky-400 hover:text-sky-500 text-xs font-medium underline" className="text-sky-400 hover:text-sky-500 text-xs font-medium underline"
to={paths.docs("/features/gmail-agent")} to={paths.docs("/agent/usage/gmail-agent")}
target="_blank" target="_blank"
/> />
), ),

View File

@ -225,7 +225,7 @@ export default function OutlookSkillPanel({
a: ( a: (
<Link <Link
className="text-sky-400 hover:text-sky-500 text-xs font-medium underline" className="text-sky-400 hover:text-sky-500 text-xs font-medium underline"
to={paths.docs("/features/outlook-agent")} to={paths.docs("/agent/usage/outlook-agent")}
target="_blank" target="_blank"
/> />
), ),

View File

@ -13,11 +13,16 @@ import {
Robot, Robot,
Hammer, Hammer,
FlowArrow, FlowArrow,
Package,
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
import ContextualSaveBar from "@/components/ContextualSaveBar"; import ContextualSaveBar from "@/components/ContextualSaveBar";
import { castToType } from "@/utils/types"; import { castToType } from "@/utils/types";
import { FullScreenLoader } from "@/components/Preloader"; import { FullScreenLoader } from "@/components/Preloader";
import { getDefaultSkills, getConfigurableSkills } from "./skills"; import {
getDefaultSkills,
getConfigurableSkills,
getAppIntegrationSkills,
} from "./skills.jsx";
import { DefaultBadge } from "./Badges/default"; import { DefaultBadge } from "./Badges/default";
import ImportedSkillList from "./Imported/SkillList"; import ImportedSkillList from "./Imported/SkillList";
import ImportedSkillConfig from "./Imported/ImportedSkillConfig"; import ImportedSkillConfig from "./Imported/ImportedSkillConfig";
@ -68,20 +73,25 @@ export default function AdminAgents() {
fileSystemAgentAvailable, fileSystemAgentAvailable,
createFilesAgentAvailable, createFilesAgentAvailable,
}); });
const allAppIntegrationSkills = getAppIntegrationSkills(t);
// Filter skills based on mode restrictions // Filter skills based on mode restrictions
// singleUserOnly -> hidden in multi-user mode // singleUserOnly -> hidden in multi-user mode
// multiUserOnly -> hidden when NOT in multi-user mode // multiUserOnly -> hidden when NOT in multi-user mode
const isMultiUserMode = settings?.MultiUserMode ?? false; const isMultiUserMode = settings?.MultiUserMode ?? false;
const filterSkillsByMode = ([_, skillConfig]) => {
if (!skillConfig.mode) return true;
if (skillConfig.mode.includes("singleUserOnly") && isMultiUserMode)
return false;
if (skillConfig.mode.includes("multiUserOnly") && !isMultiUserMode)
return false;
return true;
};
const configurableSkills = Object.fromEntries( const configurableSkills = Object.fromEntries(
Object.entries(allConfigurableSkills).filter(([_, skillConfig]) => { Object.entries(allConfigurableSkills).filter(filterSkillsByMode)
if (!skillConfig.mode) return true; );
if (skillConfig.mode.includes("singleUserOnly") && isMultiUserMode) const appIntegrationSkills = Object.fromEntries(
return false; Object.entries(allAppIntegrationSkills).filter(filterSkillsByMode)
if (skillConfig.mode.includes("multiUserOnly") && !isMultiUserMode)
return false;
return true;
})
); );
// Alert user if they try to leave the page with unsaved changes // Alert user if they try to leave the page with unsaved changes
@ -232,6 +242,8 @@ export default function AdminAgents() {
SelectedSkillComponent = ImportedSkillConfig; SelectedSkillComponent = ImportedSkillConfig;
} else if (configurableSkills[selectedSkill]) { } else if (configurableSkills[selectedSkill]) {
SelectedSkillComponent = configurableSkills[selectedSkill]?.component; SelectedSkillComponent = configurableSkills[selectedSkill]?.component;
} else if (appIntegrationSkills[selectedSkill]) {
SelectedSkillComponent = appIntegrationSkills[selectedSkill]?.component;
} else { } else {
SelectedSkillComponent = defaultSkills[selectedSkill]?.component; SelectedSkillComponent = defaultSkills[selectedSkill]?.component;
} }
@ -382,6 +394,17 @@ export default function AdminAgents() {
activeSkills={agentSkills} activeSkills={agentSkills}
/> />
<div className="text-theme-text-primary flex items-center gap-x-2 mt-6">
<Package size={24} />
<p className="text-lg font-medium">App Integrations</p>
</div>
<SkillList
skills={appIntegrationSkills}
selectedSkill={selectedSkill}
handleClick={handleSkillClick}
activeSkills={agentSkills}
/>
<div className="text-theme-text-primary flex items-center gap-x-2"> <div className="text-theme-text-primary flex items-center gap-x-2">
<Plug size={24} /> <Plug size={24} />
<p className="text-lg font-medium">Custom Skills</p> <p className="text-lg font-medium">Custom Skills</p>
@ -484,7 +507,7 @@ export default function AdminAgents() {
setHasChanges={setHasChanges} setHasChanges={setHasChanges}
{...defaultSkills[selectedSkill]} {...defaultSkills[selectedSkill]}
/> />
) : ( ) : configurableSkills?.[selectedSkill] ? (
// The selected skill is a configurable skill - show the configurable skill panel // The selected skill is a configurable skill - show the configurable skill panel
<SelectedSkillComponent <SelectedSkillComponent
skill={configurableSkills[selectedSkill]?.skill} skill={configurableSkills[selectedSkill]?.skill}
@ -497,6 +520,21 @@ export default function AdminAgents() {
hasChanges={hasChanges} hasChanges={hasChanges}
{...configurableSkills[selectedSkill]} {...configurableSkills[selectedSkill]}
/> />
) : (
// The selected skill is an app integration skill
<SelectedSkillComponent
skill={
appIntegrationSkills[selectedSkill]?.skill
}
settings={settings}
toggleSkill={toggleAgentSkill}
enabled={agentSkills.includes(
appIntegrationSkills[selectedSkill]?.skill
)}
setHasChanges={setHasChanges}
hasChanges={hasChanges}
{...appIntegrationSkills[selectedSkill]}
/>
)} )}
</> </>
)} )}
@ -580,6 +618,17 @@ export default function AdminAgents() {
activeSkills={agentSkills} activeSkills={agentSkills}
/> />
<div className="text-theme-text-primary flex items-center gap-x-2 mt-6">
<Package size={24} />
<p className="text-lg font-medium">App Integrations</p>
</div>
<SkillList
skills={appIntegrationSkills}
selectedSkill={selectedSkill}
handleClick={handleSkillClick}
activeSkills={agentSkills}
/>
<div className="text-theme-text-primary flex items-center gap-x-2 mt-4"> <div className="text-theme-text-primary flex items-center gap-x-2 mt-4">
<Plug size={24} /> <Plug size={24} />
<p className="text-lg font-medium">Custom Skills</p> <p className="text-lg font-medium">Custom Skills</p>
@ -680,7 +729,7 @@ export default function AdminAgents() {
setHasChanges={setHasChanges} setHasChanges={setHasChanges}
{...defaultSkills[selectedSkill]} {...defaultSkills[selectedSkill]}
/> />
) : ( ) : configurableSkills?.[selectedSkill] ? (
// The selected skill is a configurable skill - show the configurable skill panel // The selected skill is a configurable skill - show the configurable skill panel
<SelectedSkillComponent <SelectedSkillComponent
skill={configurableSkills[selectedSkill]?.skill} skill={configurableSkills[selectedSkill]?.skill}
@ -693,6 +742,19 @@ export default function AdminAgents() {
hasChanges={hasChanges} hasChanges={hasChanges}
{...configurableSkills[selectedSkill]} {...configurableSkills[selectedSkill]}
/> />
) : (
// The selected skill is an app integration skill
<SelectedSkillComponent
skill={appIntegrationSkills[selectedSkill]?.skill}
settings={settings}
toggleSkill={toggleAgentSkill}
enabled={agentSkills.includes(
appIntegrationSkills[selectedSkill]?.skill
)}
setHasChanges={setHasChanges}
hasChanges={hasChanges}
{...appIntegrationSkills[selectedSkill]}
/>
)} )}
</> </>
)} )}
@ -740,6 +802,7 @@ function SkillList({
selectedSkill = null, selectedSkill = null,
handleClick = null, handleClick = null,
activeSkills = [], activeSkills = [],
Icon = null,
}) { }) {
if (skills.length === 0) return null; if (skills.length === 0) return null;
@ -766,7 +829,14 @@ function SkillList({
}`} }`}
onClick={() => handleClick?.(skill)} onClick={() => handleClick?.(skill)}
> >
<div className="text-sm font-light">{settings.title}</div> <div className="flex items-center gap-x-2">
{settings.Icon ? (
<settings.Icon size={16} />
) : (
Icon && <Icon size={16} />
)}
<div className="text-sm font-light">{settings.title}</div>
</div>
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
{isDefault ? ( {isDefault ? (
<DefaultBadge title={skill} /> <DefaultBadge title={skill} />

View File

@ -13,8 +13,6 @@ import {
ChartBar, ChartBar,
FolderOpen, FolderOpen,
FilePlus, FilePlus,
EnvelopeSimple,
MicrosoftOutlookLogo,
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
import RAGImage from "@/media/agents/rag-memory.png"; import RAGImage from "@/media/agents/rag-memory.png";
import SummarizeImage from "@/media/agents/view-summarize.png"; import SummarizeImage from "@/media/agents/view-summarize.png";
@ -22,6 +20,8 @@ import ScrapeWebsitesImage from "@/media/agents/scrape-websites.png";
import GenerateChartsImage from "@/media/agents/generate-charts.png"; import GenerateChartsImage from "@/media/agents/generate-charts.png";
import GenerateSaveImages from "@/media/agents/generate-save-files.png"; import GenerateSaveImages from "@/media/agents/generate-save-files.png";
import FileSystemImage from "@/media/agents/file-system.png"; import FileSystemImage from "@/media/agents/file-system.png";
import GMailIcon from "./GMailSkillPanel/gmail.png";
import OutlookIcon from "./OutlookSkillPanel/outlook.png";
export const getDefaultSkills = (t) => ({ export const getDefaultSkills = (t) => ({
"rag-memory": { "rag-memory": {
@ -94,12 +94,17 @@ export const getConfigurableSkills = (
component: AgentSQLConnectorSelection, component: AgentSQLConnectorSelection,
skill: "sql-agent", skill: "sql-agent",
}, },
});
export const getAppIntegrationSkills = (t) => ({
"gmail-agent": { "gmail-agent": {
title: t("agent.skill.gmail.title"), title: t("agent.skill.gmail.title"),
description: t("agent.skill.gmail.description"), description: t("agent.skill.gmail.description"),
component: GMailSkillPanel, component: GMailSkillPanel,
skill: "gmail-agent", skill: "gmail-agent",
icon: EnvelopeSimple, Icon: ({ size }) => (
<img src={GMailIcon} alt="GMail" width={size} height={size} />
),
mode: ["singleUserOnly"], mode: ["singleUserOnly"],
}, },
"outlook-agent": { "outlook-agent": {
@ -107,7 +112,9 @@ export const getConfigurableSkills = (
description: t("agent.skill.outlook.description"), description: t("agent.skill.outlook.description"),
component: OutlookSkillPanel, component: OutlookSkillPanel,
skill: "outlook-agent", skill: "outlook-agent",
icon: MicrosoftOutlookLogo, Icon: ({ size }) => (
<img src={OutlookIcon} alt="Outlook" width={size} height={size} />
),
mode: ["singleUserOnly"], mode: ["singleUserOnly"],
}, },
}); });