refactor(skills): reorganize imports and improve code formatting
This commit is contained in:
@@ -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",
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ??
|
||||
|
||||
Reference in New Issue
Block a user