mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): claude_code_plugins/MakeSkillPublicForm to shadcn
- antd Modal/Button/Checkbox + @tremor Text/Title/Badge \u2192 shadcn Dialog/Button/Checkbox/Badge. - antd Steps/Step preserved for the 2-step wizard progress indicator. - Published/domain badges use categorical emerald/blue palette; confirmation info callouts use blue/amber tints (file added to .eslintrc.json overrides). Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
3eaaf5ff1a
commit
5ac527d49d
2 changed files with 125 additions and 80 deletions
|
|
@ -64,6 +64,7 @@
|
|||
"src/components/mcp_tools/mcp_server_columns.tsx",
|
||||
"src/components/playground/chat_ui/A2AMetrics.tsx",
|
||||
"src/components/common_components/PassThroughGuardrailsSection.tsx",
|
||||
"src/components/claude_code_plugins/MakeSkillPublicForm.tsx",
|
||||
"src/components/permissions/VectorStorePermissions.tsx",
|
||||
"src/components/permissions/AgentPermissions.tsx",
|
||||
"src/components/permissions/MCPServerPermissions.tsx",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,18 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Modal, Form, Steps, Button, Checkbox } from "antd";
|
||||
import { Text, Title, Badge } from "@tremor/react";
|
||||
import { enableClaudeCodePlugin, disableClaudeCodePlugin } from "../networking";
|
||||
import { Form, Steps } from "antd";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
enableClaudeCodePlugin,
|
||||
disableClaudeCodePlugin,
|
||||
} from "../networking";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { Plugin } from "./types";
|
||||
|
||||
|
|
@ -60,10 +71,11 @@ const MakeSkillPublicForm: React.FC<MakeSkillPublicFormProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
// Pre-check already-published skills when modal opens
|
||||
useEffect(() => {
|
||||
if (visible && skillsList.length > 0) {
|
||||
setSelectedSkills(new Set(skillsList.filter((s) => s.enabled).map((s) => s.name)));
|
||||
setSelectedSkills(
|
||||
new Set(skillsList.filter((s) => s.enabled).map((s) => s.name)),
|
||||
);
|
||||
}
|
||||
}, [visible, skillsList]);
|
||||
|
||||
|
|
@ -86,15 +98,19 @@ const MakeSkillPublicForm: React.FC<MakeSkillPublicFormProps> = ({
|
|||
return disableClaudeCodePlugin(accessToken, skill.name);
|
||||
}
|
||||
return Promise.resolve();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
NotificationsManager.success(`Skill Hub updated — ${selectedSkills.size} skill(s) published`);
|
||||
NotificationsManager.success(
|
||||
`Skill Hub updated — ${selectedSkills.size} skill(s) published`,
|
||||
);
|
||||
handleClose();
|
||||
onSuccess();
|
||||
} catch (error) {
|
||||
console.error("Error publishing skills:", error);
|
||||
NotificationsManager.fromBackend("Failed to update skills. Please try again.");
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to update skills. Please try again.",
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -107,65 +123,76 @@ const MakeSkillPublicForm: React.FC<MakeSkillPublicFormProps> = ({
|
|||
const renderStep1 = () => (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Title>Select Skills to Publish</Title>
|
||||
<Checkbox
|
||||
checked={allSelected}
|
||||
indeterminate={isIndeterminate}
|
||||
onChange={(e) => handleSelectAll(e.target.checked)}
|
||||
disabled={skillsList.length === 0}
|
||||
>
|
||||
Select All ({skillsList.length})
|
||||
</Checkbox>
|
||||
<h3 className="text-lg font-semibold">Select Skills to Publish</h3>
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<Checkbox
|
||||
checked={
|
||||
isIndeterminate ? "indeterminate" : allSelected ? true : false
|
||||
}
|
||||
onCheckedChange={(c) => handleSelectAll(c === true)}
|
||||
disabled={skillsList.length === 0}
|
||||
/>
|
||||
<span className="text-sm">Select All ({skillsList.length})</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<Text className="text-sm text-gray-600">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Selected skills will be visible to all users in the Skill Hub.
|
||||
Deselected skills will be unpublished.
|
||||
</Text>
|
||||
</p>
|
||||
|
||||
<div className="max-h-96 overflow-y-auto border rounded-lg p-4">
|
||||
<div className="max-h-96 overflow-y-auto border border-border rounded-lg p-4">
|
||||
<div className="space-y-3">
|
||||
{skillsList.length === 0 ? (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
<Text>No skills registered yet.</Text>
|
||||
<div className="text-center py-8 text-muted-foreground">
|
||||
<p>No skills registered yet.</p>
|
||||
</div>
|
||||
) : (
|
||||
skillsList.map((skill) => (
|
||||
<div
|
||||
<label
|
||||
key={skill.name}
|
||||
className="flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50"
|
||||
className="flex items-center space-x-3 p-3 border border-border rounded-lg hover:bg-muted cursor-pointer"
|
||||
>
|
||||
<Checkbox
|
||||
checked={selectedSkills.has(skill.name)}
|
||||
onChange={(e) => handleSkillSelection(skill.name, e.target.checked)}
|
||||
onCheckedChange={(c) =>
|
||||
handleSkillSelection(skill.name, c === true)
|
||||
}
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<Text className="font-medium font-mono text-sm">{skill.name}</Text>
|
||||
<span className="font-medium font-mono text-sm">
|
||||
{skill.name}
|
||||
</span>
|
||||
{skill.enabled && (
|
||||
<Badge color="green" size="xs">Public</Badge>
|
||||
<Badge className="text-xs bg-emerald-100 text-emerald-700 dark:bg-emerald-950 dark:text-emerald-300">
|
||||
Public
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{skill.description && (
|
||||
<Text className="text-xs text-gray-500 truncate max-w-sm">
|
||||
<span className="text-xs text-muted-foreground truncate max-w-sm block">
|
||||
{skill.description}
|
||||
</Text>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{skill.domain && (
|
||||
<Badge color="blue" size="xs">{skill.domain}</Badge>
|
||||
<Badge className="text-xs bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300">
|
||||
{skill.domain}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedSkills.size > 0 && (
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
||||
<Text className="text-sm text-blue-800">
|
||||
<strong>{selectedSkills.size}</strong> skill{selectedSkills.size !== 1 ? "s" : ""} will be published
|
||||
</Text>
|
||||
<div className="bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 rounded-lg p-3">
|
||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
||||
<strong>{selectedSkills.size}</strong> skill
|
||||
{selectedSkills.size !== 1 ? "s" : ""} will be published
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -173,25 +200,32 @@ const MakeSkillPublicForm: React.FC<MakeSkillPublicFormProps> = ({
|
|||
|
||||
const renderStep2 = () => (
|
||||
<div className="space-y-4">
|
||||
<Title>Confirm Publish to Skill Hub</Title>
|
||||
<h3 className="text-lg font-semibold">Confirm Publish to Skill Hub</h3>
|
||||
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
||||
<Text className="text-sm text-yellow-800">
|
||||
<strong>Note:</strong> Published skills will be visible to all users in the Skill Hub tab.
|
||||
Skills not in the list below will be unpublished.
|
||||
</Text>
|
||||
<div className="bg-amber-50 dark:bg-amber-950/30 border border-amber-200 dark:border-amber-900 rounded-lg p-4">
|
||||
<p className="text-sm text-amber-800 dark:text-amber-200">
|
||||
<strong>Note:</strong> Published skills will be visible to all users
|
||||
in the Skill Hub tab. Skills not in the list below will be unpublished.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Text className="font-medium">Skills to be published:</Text>
|
||||
<div className="max-h-48 overflow-y-auto border rounded-lg p-3">
|
||||
<p className="font-medium">Skills to be published:</p>
|
||||
<div className="max-h-48 overflow-y-auto border border-border rounded-lg p-3">
|
||||
<div className="space-y-2">
|
||||
{Array.from(selectedSkills).map((name) => {
|
||||
const skill = skillsList.find((s) => s.name === name);
|
||||
return (
|
||||
<div key={name} className="flex items-center justify-between p-2 bg-gray-50 rounded">
|
||||
<Text className="font-mono text-sm">{name}</Text>
|
||||
{skill?.domain && <Badge color="blue" size="xs">{skill.domain}</Badge>}
|
||||
<div
|
||||
key={name}
|
||||
className="flex items-center justify-between p-2 bg-muted rounded"
|
||||
>
|
||||
<span className="font-mono text-sm">{name}</span>
|
||||
{skill?.domain && (
|
||||
<Badge className="text-xs bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300">
|
||||
{skill.domain}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
@ -199,50 +233,60 @@ const MakeSkillPublicForm: React.FC<MakeSkillPublicFormProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
||||
<Text className="text-sm text-blue-800">
|
||||
Total: <strong>{selectedSkills.size}</strong> skill{selectedSkills.size !== 1 ? "s" : ""} will be published
|
||||
</Text>
|
||||
<div className="bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 rounded-lg p-3">
|
||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
||||
Total: <strong>{selectedSkills.size}</strong> skill
|
||||
{selectedSkills.size !== 1 ? "s" : ""} will be published
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Publish to Skill Hub"
|
||||
<Dialog
|
||||
open={visible}
|
||||
onCancel={handleClose}
|
||||
footer={null}
|
||||
width={700}
|
||||
maskClosable={false}
|
||||
onOpenChange={(o) => (!o ? handleClose() : undefined)}
|
||||
>
|
||||
<Form form={form} layout="vertical">
|
||||
<Steps current={currentStep} className="mb-6">
|
||||
<Step title="Select Skills" />
|
||||
<Step title="Confirm" />
|
||||
</Steps>
|
||||
<DialogContent className="max-w-[700px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Publish to Skill Hub</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form form={form} layout="vertical">
|
||||
<Steps current={currentStep} className="mb-6">
|
||||
<Step title="Select Skills" />
|
||||
<Step title="Confirm" />
|
||||
</Steps>
|
||||
|
||||
{currentStep === 0 ? renderStep1() : renderStep2()}
|
||||
{currentStep === 0 ? renderStep1() : renderStep2()}
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
<Button onClick={currentStep === 0 ? handleClose : () => setCurrentStep(0)}>
|
||||
{currentStep === 0 ? "Cancel" : "Previous"}
|
||||
</Button>
|
||||
<div className="flex space-x-2">
|
||||
{currentStep === 0 && (
|
||||
<Button onClick={handleNext} disabled={selectedSkills.size === 0}>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{currentStep === 1 && (
|
||||
<Button onClick={handleSubmit} loading={loading}>
|
||||
Publish to Hub
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex justify-between mt-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={
|
||||
currentStep === 0 ? handleClose : () => setCurrentStep(0)
|
||||
}
|
||||
>
|
||||
{currentStep === 0 ? "Cancel" : "Previous"}
|
||||
</Button>
|
||||
<div className="flex space-x-2">
|
||||
{currentStep === 0 && (
|
||||
<Button
|
||||
onClick={handleNext}
|
||||
disabled={selectedSkills.size === 0}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{currentStep === 1 && (
|
||||
<Button onClick={handleSubmit} disabled={loading}>
|
||||
{loading ? "Publishing..." : "Publish to Hub"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue