Add click-to-copy workspace path on Paperclip workspace source label
When a skill's source is "Paperclip workspace", clicking the label now copies the absolute path to the managed skills workspace to the clipboard and shows a toast confirmation. - Add sourcePath field to CompanySkillDetail and CompanySkillListItem types - Return managedRoot path as sourcePath from deriveSkillSourceInfo for Paperclip workspace skills - Make source label a clickable button in SkillPane detail view Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -50,6 +50,7 @@ export interface CompanySkillListItem {
|
||||
editableReason: string | null;
|
||||
sourceLabel: string | null;
|
||||
sourceBadge: CompanySkillSourceBadge;
|
||||
sourcePath: string | null;
|
||||
}
|
||||
|
||||
export interface CompanySkillUsageAgent {
|
||||
@@ -68,6 +69,7 @@ export interface CompanySkillDetail extends CompanySkill {
|
||||
editableReason: string | null;
|
||||
sourceLabel: string | null;
|
||||
sourceBadge: CompanySkillSourceBadge;
|
||||
sourcePath: string | null;
|
||||
}
|
||||
|
||||
export interface CompanySkillUpdateStatus {
|
||||
|
||||
@@ -1233,6 +1233,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: string | null;
|
||||
sourceLabel: string | null;
|
||||
sourceBadge: CompanySkillSourceBadge;
|
||||
sourcePath: string | null;
|
||||
} {
|
||||
const metadata = getSkillMeta(skill);
|
||||
const localSkillDir = normalizeSkillDirectory(skill);
|
||||
@@ -1242,6 +1243,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: "Bundled Paperclip skills are read-only.",
|
||||
sourceLabel: "Paperclip bundled",
|
||||
sourceBadge: "paperclip",
|
||||
sourcePath: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1253,6 +1255,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: "Remote GitHub skills are read-only. Fork or import locally to edit them.",
|
||||
sourceLabel: owner && repo ? `${owner}/${repo}` : skill.sourceLocator,
|
||||
sourceBadge: "github",
|
||||
sourcePath: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1262,6 +1265,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: "URL-based skills are read-only. Save them locally to edit them.",
|
||||
sourceLabel: skill.sourceLocator,
|
||||
sourceBadge: "url",
|
||||
sourcePath: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1276,6 +1280,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: null,
|
||||
sourceLabel: "Paperclip workspace",
|
||||
sourceBadge: "paperclip",
|
||||
sourcePath: managedRoot,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1287,6 +1292,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
|| skill.sourceLocator
|
||||
: skill.sourceLocator,
|
||||
sourceBadge: "local",
|
||||
sourcePath: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1295,6 +1301,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): {
|
||||
editableReason: "This skill source is read-only.",
|
||||
sourceLabel: skill.sourceLocator,
|
||||
sourceBadge: "catalog",
|
||||
sourcePath: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1330,6 +1337,7 @@ function toCompanySkillListItem(skill: CompanySkill, attachedAgentCount: number)
|
||||
editableReason: source.editableReason,
|
||||
sourceLabel: source.sourceLabel,
|
||||
sourceBadge: source.sourceBadge,
|
||||
sourcePath: source.sourcePath,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -523,6 +523,8 @@ function SkillPane({
|
||||
onSave: () => void;
|
||||
savePending: boolean;
|
||||
}) {
|
||||
const { pushToast } = useToast();
|
||||
|
||||
if (!detail) {
|
||||
if (loading) {
|
||||
return <PageSkeleton variant="detail" />;
|
||||
@@ -574,7 +576,19 @@ function SkillPane({
|
||||
<span className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">Source</span>
|
||||
<span className="flex items-center gap-2">
|
||||
<SourceIcon className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="truncate">{source.label}</span>
|
||||
{detail.sourcePath ? (
|
||||
<button
|
||||
className="truncate hover:text-foreground text-muted-foreground transition-colors cursor-pointer"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(detail.sourcePath!);
|
||||
pushToast({ title: "Copied path to workspace" });
|
||||
}}
|
||||
>
|
||||
{source.label}
|
||||
</button>
|
||||
) : (
|
||||
<span className="truncate">{source.label}</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{detail.sourceType === "github" && (
|
||||
|
||||
Reference in New Issue
Block a user