refactor(skills): reorganize imports and improve code formatting

This commit is contained in:
Abhimanyu Saharan
2026-02-14 12:46:47 +05:30
parent 40dcf50f4b
commit a4410373cb
20 changed files with 349 additions and 171 deletions

View File

@@ -177,7 +177,8 @@ export function DashboardSidebar() {
href="/skills/marketplace"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname === "/skills" || pathname.startsWith("/skills/marketplace")
pathname === "/skills" ||
pathname.startsWith("/skills/marketplace")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}

View File

@@ -11,9 +11,13 @@ import {
} from "@tanstack/react-table";
import type { MarketplaceSkillCardRead } from "@/api/generated/model";
import { DataTable, type DataTableEmptyState } from "@/components/tables/DataTable";
import {
DataTable,
type DataTableEmptyState,
} from "@/components/tables/DataTable";
import { dateCell } from "@/components/tables/cell-formatters";
import { Button, buttonVariants } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
SKILLS_TABLE_EMPTY_ICON,
useTableSortingState,
@@ -25,9 +29,32 @@ import {
packsHrefFromPackUrl,
} from "@/lib/skills-source";
function riskBadgeVariant(risk: string | null | undefined) {
const normalizedRisk = (risk || "unknown").trim().toLowerCase();
switch (normalizedRisk) {
case "low":
return "success";
case "medium":
case "moderate":
return "warning";
case "high":
case "critical":
return "danger";
case "unknown":
return "outline";
default:
return "accent";
}
}
function riskBadgeLabel(risk: string | null | undefined) {
return (risk || "unknown").trim() || "unknown";
}
type MarketplaceSkillsTableProps = {
skills: MarketplaceSkillCardRead[];
installedGatewayNamesBySkillId?: Record<string, string[]>;
installedGatewayNamesBySkillId?: Record<string, { id: string; name: string }[]>;
isLoading?: boolean;
sorting?: SortingState;
onSortingChange?: OnChangeFn<SortingState>;
@@ -78,7 +105,9 @@ export function MarketplaceSkillsTable({
{row.original.name}
</button>
) : (
<p className="text-sm font-medium text-slate-900">{row.original.name}</p>
<p className="text-sm font-medium text-slate-900">
{row.original.name}
</p>
)}
<p
className="mt-1 line-clamp-2 text-xs text-slate-500"
@@ -117,9 +146,12 @@ export function MarketplaceSkillsTable({
accessorKey: "risk",
header: "Risk",
cell: ({ row }) => (
<span className="text-sm text-slate-700">
{row.original.risk || "unknown"}
</span>
<Badge
variant={riskBadgeVariant(row.original.risk)}
className="px-2 py-0.5"
>
{riskBadgeLabel(row.original.risk)}
</Badge>
),
},
{
@@ -127,6 +159,11 @@ export function MarketplaceSkillsTable({
header: "Source",
cell: ({ row }) => {
const sourceHref = row.original.source || row.original.source_url;
if (!sourceHref) {
return <span className="text-sm text-slate-400">No source</span>;
}
return (
<Link
href={sourceHref}
@@ -145,15 +182,32 @@ export function MarketplaceSkillsTable({
header: "Installed On",
enableSorting: false,
cell: ({ row }) => {
const installedOn = installedGatewayNamesBySkillId?.[row.original.id] ?? [];
const installedOn =
installedGatewayNamesBySkillId?.[row.original.id] ?? [];
if (installedOn.length === 0) {
return <span className="text-sm text-slate-500">-</span>;
}
const installedOnText = installedOn.join(", ");
return (
<span className="text-sm text-slate-700" title={installedOnText}>
{installedOnText}
</span>
<div className="flex flex-wrap gap-1">
{installedOn.map((gateway, index) => {
const isLast = index === installedOn.length - 1;
return (
<span
key={`${gateway.id}-${index}`}
className="inline-flex items-center gap-1 text-sm text-slate-700"
title={gateway.name}
>
<Link
href={`/gateways/${gateway.id}`}
className="text-blue-700 hover:text-blue-600 hover:underline"
>
{gateway.name}
</Link>
{!isLast ? "," : ""}
</span>
);
})}
</div>
);
},
},

View File

@@ -48,7 +48,9 @@ export function SkillInstallDialog({
className="max-w-xl p-6 sm:p-7"
>
<DialogHeader className="pb-1">
<DialogTitle>{selectedSkill ? selectedSkill.name : "Install skill"}</DialogTitle>
<DialogTitle>
{selectedSkill ? selectedSkill.name : "Install skill"}
</DialogTitle>
<DialogDescription>
Choose one or more gateways where this skill should be installed.
</DialogDescription>
@@ -60,14 +62,17 @@ export function SkillInstallDialog({
) : (
gateways.map((gateway) => {
const isInstalled = gatewayInstalledById[gateway.id] === true;
const isUpdatingGateway = installingGatewayId === gateway.id && isMutating;
const isUpdatingGateway =
installingGatewayId === gateway.id && isMutating;
return (
<div
key={gateway.id}
className="flex items-center justify-between rounded-xl border border-slate-200 bg-white p-4"
>
<div>
<p className="text-sm font-medium text-slate-900">{gateway.name}</p>
<p className="text-sm font-medium text-slate-900">
{gateway.name}
</p>
</div>
<Button
type="button"
@@ -91,11 +96,17 @@ export function SkillInstallDialog({
{gatewayStatusError ? (
<p className="text-sm text-rose-600">{gatewayStatusError}</p>
) : null}
{mutationError ? <p className="text-sm text-rose-600">{mutationError}</p> : null}
{mutationError ? (
<p className="text-sm text-rose-600">{mutationError}</p>
) : null}
</div>
<DialogFooter className="mt-6 border-t border-slate-200 pt-4">
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={isMutating}>
<Button
variant="outline"
onClick={() => onOpenChange(false)}
disabled={isMutating}
>
Close
</Button>
</DialogFooter>

View File

@@ -11,7 +11,10 @@ import {
} from "@tanstack/react-table";
import type { SkillPackRead } from "@/api/generated/model";
import { DataTable, type DataTableEmptyState } from "@/components/tables/DataTable";
import {
DataTable,
type DataTableEmptyState,
} from "@/components/tables/DataTable";
import { dateCell } from "@/components/tables/cell-formatters";
import { Button } from "@/components/ui/button";
import {
@@ -62,7 +65,9 @@ export function SkillPacksTable({
header: "Pack",
cell: ({ row }) => (
<div>
<p className="text-sm font-medium text-slate-900">{row.original.name}</p>
<p className="text-sm font-medium text-slate-900">
{row.original.name}
</p>
<p className="mt-1 line-clamp-2 text-xs text-slate-500">
{row.original.description || "No description provided."}
</p>
@@ -86,7 +91,11 @@ export function SkillPacksTable({
{
accessorKey: "branch",
header: "Branch",
cell: ({ row }) => <p className="text-sm text-slate-900">{row.original.branch || "main"}</p>,
cell: ({ row }) => (
<p className="text-sm text-slate-900">
{row.original.branch || "main"}
</p>
),
},
{
accessorKey: "skill_count",
@@ -111,7 +120,9 @@ export function SkillPacksTable({
enableSorting: false,
cell: ({ row }) => {
if (!onSync) return null;
const isThisPackSyncing = Boolean(syncingPackIds?.has(row.original.id));
const isThisPackSyncing = Boolean(
syncingPackIds?.has(row.original.id),
);
return (
<div className="flex justify-end">
<Button

View File

@@ -34,7 +34,8 @@ export const useTableSortingState = (
resolvedSorting: SortingState;
handleSortingChange: OnChangeFn<SortingState>;
} => {
const [internalSorting, setInternalSorting] = useState<SortingState>(defaultSorting);
const [internalSorting, setInternalSorting] =
useState<SortingState>(defaultSorting);
const resolvedSorting = sorting ?? internalSorting;
const handleSortingChange: OnChangeFn<SortingState> =
onSortingChange ??