@julianpedro/plugin-dev-ai-hub 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/DevAiHubClient.esm.js +76 -0
- package/dist/api/DevAiHubClient.esm.js.map +1 -0
- package/dist/components/AssetCard/AssetCard.esm.js +200 -0
- package/dist/components/AssetCard/AssetCard.esm.js.map +1 -0
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js +327 -0
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js.map +1 -0
- package/dist/components/AssetFilters/AssetFilters.esm.js +216 -0
- package/dist/components/AssetFilters/AssetFilters.esm.js.map +1 -0
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js +194 -0
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js.map +1 -0
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js +320 -0
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js.map +1 -0
- package/dist/components/DevAiHubPage/index.esm.js +6 -0
- package/dist/components/DevAiHubPage/index.esm.js.map +1 -0
- package/dist/components/McpConfigDialog/McpConfigDialog.esm.js +314 -0
- package/dist/components/McpConfigDialog/McpConfigDialog.esm.js.map +1 -0
- package/dist/components/ToolIcon/ToolIcon.esm.js +41 -0
- package/dist/components/ToolIcon/ToolIcon.esm.js.map +1 -0
- package/dist/hooks/index.esm.js +114 -0
- package/dist/hooks/index.esm.js.map +1 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.esm.js +5 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +40 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/pluginLegacy.esm.js +27 -0
- package/dist/pluginLegacy.esm.js.map +1 -0
- package/dist/routes.esm.js +6 -0
- package/dist/routes.esm.js.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createApiRef } from '@backstage/core-plugin-api';
|
|
2
|
+
|
|
3
|
+
const devAiHubApiRef = createApiRef({
|
|
4
|
+
id: "plugin.dev-ai-hub.service"
|
|
5
|
+
});
|
|
6
|
+
class DevAiHubClient {
|
|
7
|
+
constructor(discoveryApi, fetchApi) {
|
|
8
|
+
this.discoveryApi = discoveryApi;
|
|
9
|
+
this.fetchApi = fetchApi;
|
|
10
|
+
}
|
|
11
|
+
async baseUrl() {
|
|
12
|
+
return this.discoveryApi.getBaseUrl("dev-ai-hub");
|
|
13
|
+
}
|
|
14
|
+
async fetch(path, init) {
|
|
15
|
+
const base = await this.baseUrl();
|
|
16
|
+
const response = await this.fetchApi.fetch(`${base}${path}`, init);
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const text = await response.text();
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Dev AI Hub API error ${response.status}: ${text}`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return response.json();
|
|
24
|
+
}
|
|
25
|
+
async listAssets(filter) {
|
|
26
|
+
const params = new URLSearchParams();
|
|
27
|
+
if (filter?.type) params.set("type", filter.type);
|
|
28
|
+
if (filter?.tool) params.set("tool", filter.tool);
|
|
29
|
+
if (filter?.search) params.set("search", filter.search);
|
|
30
|
+
if (filter?.providerId) params.set("provider", filter.providerId);
|
|
31
|
+
if (filter?.tags?.length) params.set("tags", filter.tags.join(","));
|
|
32
|
+
if (filter?.page) params.set("page", String(filter.page));
|
|
33
|
+
if (filter?.pageSize) params.set("pageSize", String(filter.pageSize));
|
|
34
|
+
const qs = params.toString();
|
|
35
|
+
return this.fetch(`/assets${qs ? `?${qs}` : ""}`);
|
|
36
|
+
}
|
|
37
|
+
async getAsset(id) {
|
|
38
|
+
return this.fetch(`/assets/${encodeURIComponent(id)}`);
|
|
39
|
+
}
|
|
40
|
+
async getAssetRaw(id) {
|
|
41
|
+
const base = await this.baseUrl();
|
|
42
|
+
const response = await this.fetchApi.fetch(
|
|
43
|
+
`${base}/assets/${encodeURIComponent(id)}/raw`
|
|
44
|
+
);
|
|
45
|
+
if (!response.ok) throw new Error(`Failed to fetch raw asset: ${response.status}`);
|
|
46
|
+
return response.text();
|
|
47
|
+
}
|
|
48
|
+
async getDownloadUrl(id) {
|
|
49
|
+
const base = await this.baseUrl();
|
|
50
|
+
return `${base}/assets/${encodeURIComponent(id)}/download`;
|
|
51
|
+
}
|
|
52
|
+
async trackInstall(id) {
|
|
53
|
+
await this.fetch(`/assets/${encodeURIComponent(id)}/track-install`, {
|
|
54
|
+
method: "POST"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async listProviders() {
|
|
58
|
+
return this.fetch("/providers");
|
|
59
|
+
}
|
|
60
|
+
async getProviderStatus(id) {
|
|
61
|
+
return this.fetch(
|
|
62
|
+
`/providers/${encodeURIComponent(id)}/status`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
async triggerSync(id) {
|
|
66
|
+
await this.fetch(`/providers/${encodeURIComponent(id)}/sync`, {
|
|
67
|
+
method: "POST"
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async getStats() {
|
|
71
|
+
return this.fetch("/stats");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { DevAiHubClient, devAiHubApiRef };
|
|
76
|
+
//# sourceMappingURL=DevAiHubClient.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevAiHubClient.esm.js","sources":["../../src/api/DevAiHubClient.ts"],"sourcesContent":["import {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport type {\n AiAsset,\n AiAssetListResponse,\n AiHubProvider,\n AiHubStats,\n AssetListFilter,\n} from '@julianpedro/plugin-dev-ai-hub-common';\n\nexport const devAiHubApiRef = createApiRef<DevAiHubApi>({\n id: 'plugin.dev-ai-hub.service',\n});\n\nexport interface DevAiHubApi {\n listAssets(filter?: AssetListFilter): Promise<AiAssetListResponse>;\n getAsset(id: string): Promise<AiAsset>;\n getAssetRaw(id: string): Promise<string>;\n /** Returns the absolute URL for the download endpoint (zip for skills, md for others). */\n getDownloadUrl(id: string): Promise<string>;\n trackInstall(id: string): Promise<void>;\n listProviders(): Promise<AiHubProvider[]>;\n getProviderStatus(id: string): Promise<AiHubProvider>;\n triggerSync(id: string): Promise<void>;\n getStats(): Promise<AiHubStats>;\n}\n\nexport class DevAiHubClient implements DevAiHubApi {\n constructor(\n private readonly discoveryApi: DiscoveryApi,\n private readonly fetchApi: FetchApi,\n ) {}\n\n private async baseUrl(): Promise<string> {\n return this.discoveryApi.getBaseUrl('dev-ai-hub');\n }\n\n private async fetch<T>(path: string, init?: RequestInit): Promise<T> {\n const base = await this.baseUrl();\n const response = await this.fetchApi.fetch(`${base}${path}`, init);\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Dev AI Hub API error ${response.status}: ${text}`,\n );\n }\n return response.json() as Promise<T>;\n }\n\n async listAssets(filter?: AssetListFilter): Promise<AiAssetListResponse> {\n const params = new URLSearchParams();\n if (filter?.type) params.set('type', filter.type);\n if (filter?.tool) params.set('tool', filter.tool);\n if (filter?.search) params.set('search', filter.search);\n if (filter?.providerId) params.set('provider', filter.providerId);\n if (filter?.tags?.length) params.set('tags', filter.tags.join(','));\n if (filter?.page) params.set('page', String(filter.page));\n if (filter?.pageSize) params.set('pageSize', String(filter.pageSize));\n\n const qs = params.toString();\n return this.fetch<AiAssetListResponse>(`/assets${qs ? `?${qs}` : ''}`);\n }\n\n async getAsset(id: string): Promise<AiAsset> {\n return this.fetch<AiAsset>(`/assets/${encodeURIComponent(id)}`);\n }\n\n async getAssetRaw(id: string): Promise<string> {\n const base = await this.baseUrl();\n const response = await this.fetchApi.fetch(\n `${base}/assets/${encodeURIComponent(id)}/raw`,\n );\n if (!response.ok) throw new Error(`Failed to fetch raw asset: ${response.status}`);\n return response.text();\n }\n\n async getDownloadUrl(id: string): Promise<string> {\n const base = await this.baseUrl();\n return `${base}/assets/${encodeURIComponent(id)}/download`;\n }\n\n async trackInstall(id: string): Promise<void> {\n await this.fetch(`/assets/${encodeURIComponent(id)}/track-install`, {\n method: 'POST',\n });\n }\n\n async listProviders(): Promise<AiHubProvider[]> {\n return this.fetch<AiHubProvider[]>('/providers');\n }\n\n async getProviderStatus(id: string): Promise<AiHubProvider> {\n return this.fetch<AiHubProvider>(\n `/providers/${encodeURIComponent(id)}/status`,\n );\n }\n\n async triggerSync(id: string): Promise<void> {\n await this.fetch(`/providers/${encodeURIComponent(id)}/sync`, {\n method: 'POST',\n });\n }\n\n async getStats(): Promise<AiHubStats> {\n return this.fetch<AiHubStats>('/stats');\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useTheme, alpha } from '@mui/material/styles';
|
|
3
|
+
import Box from '@mui/material/Box';
|
|
4
|
+
import Card from '@mui/material/Card';
|
|
5
|
+
import CardActions from '@mui/material/CardActions';
|
|
6
|
+
import CardContent from '@mui/material/CardContent';
|
|
7
|
+
import Chip from '@mui/material/Chip';
|
|
8
|
+
import IconButton from '@mui/material/IconButton';
|
|
9
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
10
|
+
import Typography from '@mui/material/Typography';
|
|
11
|
+
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
|
12
|
+
import DownloadIcon from '@mui/icons-material/Download';
|
|
13
|
+
import ArticleIcon from '@mui/icons-material/Article';
|
|
14
|
+
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
|
15
|
+
import BuildIcon from '@mui/icons-material/Build';
|
|
16
|
+
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
17
|
+
import { ToolIcon } from '../ToolIcon/ToolIcon.esm.js';
|
|
18
|
+
|
|
19
|
+
const POPULAR_THRESHOLD = 5;
|
|
20
|
+
const NEW_DAYS_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
21
|
+
const TOOL_LABELS = {
|
|
22
|
+
"all": "Universal",
|
|
23
|
+
"claude-code": "Claude Code",
|
|
24
|
+
"github-copilot": "GitHub Copilot",
|
|
25
|
+
"google-gemini": "Google Gemini",
|
|
26
|
+
"cursor": "Cursor"
|
|
27
|
+
};
|
|
28
|
+
const TYPE_CONFIG = {
|
|
29
|
+
instruction: { label: "Instruction", color: "#2563EB", Icon: ArticleIcon },
|
|
30
|
+
agent: { label: "Agent", color: "#7C3AED", Icon: SmartToyIcon },
|
|
31
|
+
skill: { label: "Skill", color: "#059669", Icon: BuildIcon },
|
|
32
|
+
workflow: { label: "Workflow", color: "#D97706", Icon: AccountTreeIcon }
|
|
33
|
+
};
|
|
34
|
+
function AssetCard({ asset, onView, onInstall }) {
|
|
35
|
+
const theme = useTheme();
|
|
36
|
+
const isDark = theme.palette.mode === "dark" || theme.palette.type === "dark";
|
|
37
|
+
const cfg = TYPE_CONFIG[asset.type];
|
|
38
|
+
const TypeIcon = cfg.Icon;
|
|
39
|
+
const isPopular = asset.installCount >= POPULAR_THRESHOLD;
|
|
40
|
+
const isNew = Date.now() - new Date(asset.updatedAt).getTime() < NEW_DAYS_MS;
|
|
41
|
+
return /* @__PURE__ */ jsxs(
|
|
42
|
+
Card,
|
|
43
|
+
{
|
|
44
|
+
variant: "outlined",
|
|
45
|
+
sx: {
|
|
46
|
+
height: "100%",
|
|
47
|
+
display: "flex",
|
|
48
|
+
flexDirection: "column",
|
|
49
|
+
borderRadius: 2,
|
|
50
|
+
border: "1px solid",
|
|
51
|
+
borderColor: "divider",
|
|
52
|
+
borderLeft: `3px solid ${cfg.color}`,
|
|
53
|
+
transition: "all 0.18s ease",
|
|
54
|
+
"&:hover": {
|
|
55
|
+
boxShadow: `0 6px 24px ${cfg.color}30`,
|
|
56
|
+
borderColor: cfg.color,
|
|
57
|
+
transform: "translateY(-2px)"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsxs(CardContent, { sx: { p: 1.5, pb: "0 !important", flex: 1 }, children: [
|
|
62
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "flex-start", gap: 1, mb: 1 }, children: [
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
Box,
|
|
65
|
+
{
|
|
66
|
+
sx: {
|
|
67
|
+
width: 40,
|
|
68
|
+
height: 40,
|
|
69
|
+
borderRadius: 1.5,
|
|
70
|
+
backgroundColor: alpha(cfg.color, 0.12),
|
|
71
|
+
display: "flex",
|
|
72
|
+
alignItems: "center",
|
|
73
|
+
justifyContent: "center",
|
|
74
|
+
flexShrink: 0,
|
|
75
|
+
boxShadow: `0 2px 8px ${cfg.color}25`
|
|
76
|
+
},
|
|
77
|
+
children: asset.icon ? /* @__PURE__ */ jsx(
|
|
78
|
+
Box,
|
|
79
|
+
{
|
|
80
|
+
component: "img",
|
|
81
|
+
src: asset.icon,
|
|
82
|
+
alt: asset.label ?? asset.name,
|
|
83
|
+
sx: { width: 26, height: 26, objectFit: "contain" },
|
|
84
|
+
onError: (e) => {
|
|
85
|
+
e.target.style.display = "none";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
) : /* @__PURE__ */ jsx(TypeIcon, { sx: { color: cfg.color, fontSize: "1.3rem" } })
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
/* @__PURE__ */ jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
92
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5, mb: 0.2 }, children: [
|
|
93
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", fontWeight: 700, noWrap: true, title: asset.label ?? asset.name, sx: { lineHeight: 1.2, flex: 1 }, children: asset.label ?? asset.name }),
|
|
94
|
+
isNew && /* @__PURE__ */ jsx(
|
|
95
|
+
Chip,
|
|
96
|
+
{
|
|
97
|
+
label: "New",
|
|
98
|
+
size: "small",
|
|
99
|
+
sx: {
|
|
100
|
+
height: 18,
|
|
101
|
+
fontSize: "0.6rem",
|
|
102
|
+
fontWeight: 700,
|
|
103
|
+
backgroundColor: alpha("#059669", isDark ? 0.25 : 0.14),
|
|
104
|
+
backdropFilter: "blur(8px)",
|
|
105
|
+
color: isDark ? "#fff" : "#059669",
|
|
106
|
+
border: "1px solid",
|
|
107
|
+
borderColor: alpha("#059669", isDark ? 0.5 : 0.3),
|
|
108
|
+
borderRadius: 1,
|
|
109
|
+
flexShrink: 0,
|
|
110
|
+
"& .MuiChip-label": { px: "6px" }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", sx: { color: cfg.color, fontWeight: 600 }, children: cfg.label })
|
|
116
|
+
] })
|
|
117
|
+
] }),
|
|
118
|
+
/* @__PURE__ */ jsx(
|
|
119
|
+
Typography,
|
|
120
|
+
{
|
|
121
|
+
variant: "caption",
|
|
122
|
+
color: "text.secondary",
|
|
123
|
+
sx: {
|
|
124
|
+
mb: 1,
|
|
125
|
+
display: "-webkit-box",
|
|
126
|
+
WebkitLineClamp: 2,
|
|
127
|
+
WebkitBoxOrient: "vertical",
|
|
128
|
+
overflow: "hidden",
|
|
129
|
+
lineHeight: 1.4
|
|
130
|
+
},
|
|
131
|
+
children: asset.description
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsx(Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mb: asset.tags.length > 0 ? 0.75 : 0 }, children: asset.tools.map((tool) => /* @__PURE__ */ jsx(
|
|
135
|
+
Chip,
|
|
136
|
+
{
|
|
137
|
+
icon: /* @__PURE__ */ jsx(ToolIcon, { tool, sx: { fontSize: "0.75rem !important" } }),
|
|
138
|
+
label: TOOL_LABELS[tool] ?? tool,
|
|
139
|
+
size: "small",
|
|
140
|
+
sx: {
|
|
141
|
+
height: 18,
|
|
142
|
+
fontSize: "0.65rem",
|
|
143
|
+
fontWeight: 600,
|
|
144
|
+
backgroundColor: "action.hover",
|
|
145
|
+
color: "text.secondary",
|
|
146
|
+
borderRadius: 1,
|
|
147
|
+
"& .MuiChip-icon": { ml: "4px" }
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
tool
|
|
151
|
+
)) }),
|
|
152
|
+
asset.tags.length > 0 && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" }, children: [
|
|
153
|
+
asset.tags.slice(0, 3).map((tag) => /* @__PURE__ */ jsx(
|
|
154
|
+
Chip,
|
|
155
|
+
{
|
|
156
|
+
label: `#${tag}`,
|
|
157
|
+
size: "small",
|
|
158
|
+
sx: {
|
|
159
|
+
height: 16,
|
|
160
|
+
fontSize: "0.6rem",
|
|
161
|
+
color: "text.disabled",
|
|
162
|
+
backgroundColor: "transparent",
|
|
163
|
+
border: "1px solid",
|
|
164
|
+
borderColor: "divider",
|
|
165
|
+
borderRadius: 1
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
tag
|
|
169
|
+
)),
|
|
170
|
+
asset.tags.length > 3 && /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "text.disabled", sx: { alignSelf: "center" }, children: [
|
|
171
|
+
"+",
|
|
172
|
+
asset.tags.length - 3
|
|
173
|
+
] })
|
|
174
|
+
] })
|
|
175
|
+
] }),
|
|
176
|
+
/* @__PURE__ */ jsxs(CardActions, { sx: { px: 1.5, py: 1, justifyContent: "space-between", mt: "auto", borderTop: "1px solid", borderColor: "divider" }, children: [
|
|
177
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
178
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "text.disabled", sx: { fontSize: "0.65rem" }, children: [
|
|
179
|
+
"v",
|
|
180
|
+
asset.version,
|
|
181
|
+
" \xB7 ",
|
|
182
|
+
asset.author
|
|
183
|
+
] }),
|
|
184
|
+
asset.installCount > 0 && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.25 }, children: [
|
|
185
|
+
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.65rem", lineHeight: 1 }, children: isPopular ? "\u{1F525}" : "\u2193" }),
|
|
186
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.disabled", sx: { fontSize: "0.65rem" }, children: asset.installCount })
|
|
187
|
+
] })
|
|
188
|
+
] }),
|
|
189
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 0.25 }, children: [
|
|
190
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Install in editor", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: () => onInstall(asset.id), color: "primary", children: /* @__PURE__ */ jsx(DownloadIcon, { fontSize: "small" }) }) }),
|
|
191
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "View details", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: () => onView(asset.id), children: /* @__PURE__ */ jsx(OpenInNewIcon, { fontSize: "small" }) }) })
|
|
192
|
+
] })
|
|
193
|
+
] })
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { AssetCard };
|
|
200
|
+
//# sourceMappingURL=AssetCard.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetCard.esm.js","sources":["../../../src/components/AssetCard/AssetCard.tsx"],"sourcesContent":["import type { ElementType } from 'react';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\nimport Card from '@mui/material/Card';\nimport CardActions from '@mui/material/CardActions';\nimport CardContent from '@mui/material/CardContent';\nimport Chip from '@mui/material/Chip';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport DownloadIcon from '@mui/icons-material/Download';\nimport ArticleIcon from '@mui/icons-material/Article';\nimport SmartToyIcon from '@mui/icons-material/SmartToy';\nimport BuildIcon from '@mui/icons-material/Build';\nimport AccountTreeIcon from '@mui/icons-material/AccountTree';\nimport type { AiAssetSummary, AssetType, AiTool } from '@julianpedro/plugin-dev-ai-hub-common';\nimport { ToolIcon } from '../ToolIcon';\n\nconst POPULAR_THRESHOLD = 5;\nconst NEW_DAYS_MS = 14 * 24 * 60 * 60 * 1000;\n\nconst TOOL_LABELS: Record<AiTool, string> = {\n 'all': 'Universal',\n 'claude-code': 'Claude Code',\n 'github-copilot': 'GitHub Copilot',\n 'google-gemini': 'Google Gemini',\n 'cursor': 'Cursor',\n};\n\nconst TYPE_CONFIG: Record<AssetType, { label: string; color: string; Icon: ElementType }> = {\n instruction: { label: 'Instruction', color: '#2563EB', Icon: ArticleIcon },\n agent: { label: 'Agent', color: '#7C3AED', Icon: SmartToyIcon },\n skill: { label: 'Skill', color: '#059669', Icon: BuildIcon },\n workflow: { label: 'Workflow', color: '#D97706', Icon: AccountTreeIcon },\n};\n\ninterface AssetCardProps {\n asset: AiAssetSummary;\n onView: (id: string) => void;\n onInstall: (id: string) => void;\n}\n\nexport function AssetCard({ asset, onView, onInstall }: AssetCardProps) {\n const theme = useTheme();\n const isDark = (theme.palette as any).mode === 'dark' || (theme.palette as any).type === 'dark';\n const cfg = TYPE_CONFIG[asset.type];\n const TypeIcon = cfg.Icon;\n const isPopular = asset.installCount >= POPULAR_THRESHOLD;\n const isNew = Date.now() - new Date(asset.updatedAt).getTime() < NEW_DAYS_MS;\n\n return (\n <Card\n variant=\"outlined\"\n sx={{\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n borderRadius: 2,\n border: '1px solid',\n borderColor: 'divider',\n borderLeft: `3px solid ${cfg.color}`,\n transition: 'all 0.18s ease',\n '&:hover': {\n boxShadow: `0 6px 24px ${cfg.color}30`,\n borderColor: cfg.color,\n transform: 'translateY(-2px)',\n },\n }}\n >\n <CardContent sx={{ p: 1.5, pb: '0 !important', flex: 1 }}>\n {/* Header */}\n <Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 1, mb: 1 }}>\n <Box\n sx={{\n width: 40,\n height: 40,\n borderRadius: 1.5,\n backgroundColor: alpha(cfg.color, 0.12),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n boxShadow: `0 2px 8px ${cfg.color}25`,\n }}\n >\n {asset.icon ? (\n <Box\n component=\"img\"\n src={asset.icon}\n alt={asset.label ?? asset.name}\n sx={{ width: 26, height: 26, objectFit: 'contain' }}\n onError={e => { (e.target as HTMLImageElement).style.display = 'none'; }}\n />\n ) : (\n <TypeIcon sx={{ color: cfg.color, fontSize: '1.3rem' }} />\n )}\n </Box>\n\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mb: 0.2 }}>\n <Typography variant=\"body2\" fontWeight={700} noWrap title={asset.label ?? asset.name} sx={{ lineHeight: 1.2, flex: 1 }}>\n {asset.label ?? asset.name}\n </Typography>\n {isNew && (\n <Chip\n label=\"New\"\n size=\"small\"\n sx={{\n height: 18,\n fontSize: '0.6rem',\n fontWeight: 700,\n backgroundColor: alpha('#059669', isDark ? 0.25 : 0.14),\n backdropFilter: 'blur(8px)',\n color: isDark ? '#fff' : '#059669',\n border: '1px solid',\n borderColor: alpha('#059669', isDark ? 0.5 : 0.3),\n borderRadius: 1,\n flexShrink: 0,\n '& .MuiChip-label': { px: '6px' },\n }}\n />\n )}\n </Box>\n <Typography variant=\"caption\" sx={{ color: cfg.color, fontWeight: 600 }}>\n {cfg.label}\n </Typography>\n </Box>\n </Box>\n\n {/* Description */}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n mb: 1,\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n lineHeight: 1.4,\n }}\n >\n {asset.description}\n </Typography>\n\n {/* Tools */}\n <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap', mb: asset.tags.length > 0 ? 0.75 : 0 }}>\n {asset.tools.map(tool => (\n <Chip\n key={tool}\n icon={<ToolIcon tool={tool as AiTool} sx={{ fontSize: '0.75rem !important' }} />}\n label={TOOL_LABELS[tool as AiTool] ?? tool}\n size=\"small\"\n sx={{\n height: 18,\n fontSize: '0.65rem',\n fontWeight: 600,\n backgroundColor: 'action.hover',\n color: 'text.secondary',\n borderRadius: 1,\n '& .MuiChip-icon': { ml: '4px' },\n }}\n />\n ))}\n </Box>\n\n {/* Tags */}\n {asset.tags.length > 0 && (\n <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>\n {asset.tags.slice(0, 3).map(tag => (\n <Chip\n key={tag}\n label={`#${tag}`}\n size=\"small\"\n sx={{\n height: 16,\n fontSize: '0.6rem',\n color: 'text.disabled',\n backgroundColor: 'transparent',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n }}\n />\n ))}\n {asset.tags.length > 3 && (\n <Typography variant=\"caption\" color=\"text.disabled\" sx={{ alignSelf: 'center' }}>\n +{asset.tags.length - 3}\n </Typography>\n )}\n </Box>\n )}\n </CardContent>\n\n <CardActions sx={{ px: 1.5, py: 1, justifyContent: 'space-between', mt: 'auto', borderTop: '1px solid', borderColor: 'divider' }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Typography variant=\"caption\" color=\"text.disabled\" sx={{ fontSize: '0.65rem' }}>\n v{asset.version} · {asset.author}\n </Typography>\n {asset.installCount > 0 && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25 }}>\n <Typography sx={{ fontSize: '0.65rem', lineHeight: 1 }}>\n {isPopular ? '🔥' : '↓'}\n </Typography>\n <Typography variant=\"caption\" color=\"text.disabled\" sx={{ fontSize: '0.65rem' }}>\n {asset.installCount}\n </Typography>\n </Box>\n )}\n </Box>\n <Box sx={{ display: 'flex', gap: 0.25 }}>\n <Tooltip title=\"Install in editor\">\n <IconButton size=\"small\" onClick={() => onInstall(asset.id)} color=\"primary\">\n <DownloadIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"View details\">\n <IconButton size=\"small\" onClick={() => onView(asset.id)}>\n <OpenInNewIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Box>\n </CardActions>\n </Card>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { useTheme } from '@mui/material/styles';
|
|
4
|
+
import ReactMarkdown from 'react-markdown';
|
|
5
|
+
import remarkGfm from 'remark-gfm';
|
|
6
|
+
import Alert from '@mui/material/Alert';
|
|
7
|
+
import Box from '@mui/material/Box';
|
|
8
|
+
import Button from '@mui/material/Button';
|
|
9
|
+
import Chip from '@mui/material/Chip';
|
|
10
|
+
import CircularProgress from '@mui/material/CircularProgress';
|
|
11
|
+
import Divider from '@mui/material/Divider';
|
|
12
|
+
import Drawer from '@mui/material/Drawer';
|
|
13
|
+
import IconButton from '@mui/material/IconButton';
|
|
14
|
+
import Link from '@mui/material/Link';
|
|
15
|
+
import Snackbar from '@mui/material/Snackbar';
|
|
16
|
+
import Tab from '@mui/material/Tab';
|
|
17
|
+
import Tabs from '@mui/material/Tabs';
|
|
18
|
+
import Typography from '@mui/material/Typography';
|
|
19
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
20
|
+
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
21
|
+
import FolderZipIcon from '@mui/icons-material/FolderZip';
|
|
22
|
+
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
|
23
|
+
import { useAssetDetail } from '../../hooks/index.esm.js';
|
|
24
|
+
|
|
25
|
+
const SyntaxHighlighter = require("react-syntax-highlighter/dist/esm/prism").default;
|
|
26
|
+
const { oneLight, oneDark } = require("react-syntax-highlighter/dist/esm/styles/prism");
|
|
27
|
+
const TYPE_COLORS = {
|
|
28
|
+
instruction: "#1976d2",
|
|
29
|
+
agent: "#7b1fa2",
|
|
30
|
+
skill: "#388e3c",
|
|
31
|
+
workflow: "#f57c00"
|
|
32
|
+
};
|
|
33
|
+
function AssetDetailPanel({ assetId, onClose }) {
|
|
34
|
+
const [tab, setTab] = useState(0);
|
|
35
|
+
const [snackbar, setSnackbar] = useState(null);
|
|
36
|
+
const { asset, loading } = useAssetDetail(assetId);
|
|
37
|
+
const theme = useTheme();
|
|
38
|
+
const syntaxTheme = theme.palette.mode === "dark" ? oneDark : oneLight;
|
|
39
|
+
const handleCopy = () => {
|
|
40
|
+
if (!asset) return;
|
|
41
|
+
navigator.clipboard.writeText(asset.content).then(
|
|
42
|
+
() => setSnackbar("Markdown copied to clipboard!")
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
Drawer,
|
|
48
|
+
{
|
|
49
|
+
anchor: "right",
|
|
50
|
+
open: !!assetId,
|
|
51
|
+
onClose,
|
|
52
|
+
PaperProps: { sx: { width: { xs: "100vw", md: 640 } } },
|
|
53
|
+
children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", height: "100%" }, children: [
|
|
54
|
+
/* @__PURE__ */ jsxs(
|
|
55
|
+
Box,
|
|
56
|
+
{
|
|
57
|
+
sx: {
|
|
58
|
+
p: 2,
|
|
59
|
+
display: "flex",
|
|
60
|
+
alignItems: "flex-start",
|
|
61
|
+
gap: 2,
|
|
62
|
+
borderBottom: 1,
|
|
63
|
+
borderColor: "divider"
|
|
64
|
+
},
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Box, { sx: { flex: 1 }, children: loading || !asset ? /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
67
|
+
/* @__PURE__ */ jsx(CircularProgress, { size: 16 }),
|
|
68
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "Loading..." })
|
|
69
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
70
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.5 }, children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", fontWeight: 700, children: asset.name }),
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
Chip,
|
|
74
|
+
{
|
|
75
|
+
label: asset.type,
|
|
76
|
+
size: "small",
|
|
77
|
+
sx: {
|
|
78
|
+
backgroundColor: `${TYPE_COLORS[asset.type]}20`,
|
|
79
|
+
color: TYPE_COLORS[asset.type],
|
|
80
|
+
fontWeight: 600
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: asset.description })
|
|
86
|
+
] }) }),
|
|
87
|
+
/* @__PURE__ */ jsx(IconButton, { onClick: onClose, size: "small", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
/* @__PURE__ */ jsxs(
|
|
92
|
+
Tabs,
|
|
93
|
+
{
|
|
94
|
+
value: tab,
|
|
95
|
+
onChange: (_, v) => setTab(v),
|
|
96
|
+
sx: { borderBottom: 1, borderColor: "divider", px: 2 },
|
|
97
|
+
children: [
|
|
98
|
+
/* @__PURE__ */ jsx(Tab, { label: "Preview" }),
|
|
99
|
+
/* @__PURE__ */ jsx(Tab, { label: "Metadata" }),
|
|
100
|
+
/* @__PURE__ */ jsx(Tab, { label: "Raw YAML" })
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
/* @__PURE__ */ jsxs(Box, { sx: { flex: 1, overflow: "auto", p: 2 }, children: [
|
|
105
|
+
loading && /* @__PURE__ */ jsx(Box, { sx: { display: "flex", justifyContent: "center", pt: 4 }, children: /* @__PURE__ */ jsx(CircularProgress, {}) }),
|
|
106
|
+
!loading && asset && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
107
|
+
tab === 0 && /* @__PURE__ */ jsx(
|
|
108
|
+
Box,
|
|
109
|
+
{
|
|
110
|
+
sx: {
|
|
111
|
+
"& h1,h2,h3,h4,h5,h6": { mt: 2, mb: 1, fontWeight: 700 },
|
|
112
|
+
"& p": { mb: 1, lineHeight: 1.7 },
|
|
113
|
+
"& ul, & ol": { pl: 2.5, mb: 1 },
|
|
114
|
+
"& li": { mb: 0.5 },
|
|
115
|
+
"& blockquote": {
|
|
116
|
+
borderLeft: "3px solid",
|
|
117
|
+
borderColor: "primary.main",
|
|
118
|
+
pl: 1.5,
|
|
119
|
+
color: "text.secondary",
|
|
120
|
+
my: 1,
|
|
121
|
+
ml: 0
|
|
122
|
+
},
|
|
123
|
+
"& table": { width: "100%", borderCollapse: "collapse", mb: 1 },
|
|
124
|
+
"& th, & td": {
|
|
125
|
+
border: "1px solid",
|
|
126
|
+
borderColor: "divider",
|
|
127
|
+
px: 1.5,
|
|
128
|
+
py: 0.75,
|
|
129
|
+
fontSize: "0.875rem"
|
|
130
|
+
},
|
|
131
|
+
"& th": { backgroundColor: "action.hover", fontWeight: 700 },
|
|
132
|
+
"& code": {
|
|
133
|
+
bgcolor: "action.hover",
|
|
134
|
+
px: 0.5,
|
|
135
|
+
py: 0.2,
|
|
136
|
+
borderRadius: 0.5,
|
|
137
|
+
fontFamily: "monospace",
|
|
138
|
+
fontSize: "0.875em"
|
|
139
|
+
},
|
|
140
|
+
"& pre code": { bgcolor: "transparent", px: 0, py: 0 }
|
|
141
|
+
},
|
|
142
|
+
children: /* @__PURE__ */ jsx(
|
|
143
|
+
ReactMarkdown,
|
|
144
|
+
{
|
|
145
|
+
remarkPlugins: [remarkGfm],
|
|
146
|
+
components: {
|
|
147
|
+
pre: ({ children }) => /* @__PURE__ */ jsx(Box, { sx: { my: 1 }, children }),
|
|
148
|
+
code({ className, children }) {
|
|
149
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
150
|
+
const code = String(children).replace(/\n$/, "");
|
|
151
|
+
const isBlock = code.includes("\n") || !!match;
|
|
152
|
+
return isBlock ? /* @__PURE__ */ jsx(
|
|
153
|
+
SyntaxHighlighter,
|
|
154
|
+
{
|
|
155
|
+
style: syntaxTheme,
|
|
156
|
+
language: match?.[1] ?? "text",
|
|
157
|
+
PreTag: "div",
|
|
158
|
+
customStyle: {
|
|
159
|
+
borderRadius: 8,
|
|
160
|
+
fontSize: "0.8rem",
|
|
161
|
+
margin: 0,
|
|
162
|
+
border: `1px solid ${theme.palette.divider}`
|
|
163
|
+
},
|
|
164
|
+
children: code
|
|
165
|
+
}
|
|
166
|
+
) : /* @__PURE__ */ jsx("code", { className, children });
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
children: asset.content
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
),
|
|
174
|
+
tab === 1 && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
175
|
+
/* @__PURE__ */ jsx(MetaRow, { label: "Author", value: asset.author }),
|
|
176
|
+
/* @__PURE__ */ jsx(MetaRow, { label: "Version", value: asset.version }),
|
|
177
|
+
/* @__PURE__ */ jsx(MetaRow, { label: "Provider", value: asset.providerId }),
|
|
178
|
+
asset.commitSha && /* @__PURE__ */ jsx(MetaRow, { label: "Commit", value: asset.commitSha.slice(0, 8) }),
|
|
179
|
+
/* @__PURE__ */ jsx(MetaRow, { label: "Last synced", value: new Date(asset.syncedAt).toLocaleString() }),
|
|
180
|
+
/* @__PURE__ */ jsx(MetaRow, { label: "Branch", value: asset.branch }),
|
|
181
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
182
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
183
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: "Compatible tools" }),
|
|
184
|
+
/* @__PURE__ */ jsx(Box, { sx: { display: "flex", gap: 1, mt: 0.5 }, children: asset.tools.map((t) => /* @__PURE__ */ jsx(Chip, { label: t, size: "small" }, t)) })
|
|
185
|
+
] }),
|
|
186
|
+
asset.tags.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
|
|
187
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: "Tags" }),
|
|
188
|
+
/* @__PURE__ */ jsx(Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mt: 0.5 }, children: asset.tags.map((t) => /* @__PURE__ */ jsx(Chip, { label: t, size: "small", variant: "outlined" }, t)) })
|
|
189
|
+
] }),
|
|
190
|
+
asset.type === "skill" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
191
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
192
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
193
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.75, mb: 0.5 }, children: [
|
|
194
|
+
/* @__PURE__ */ jsx(FolderZipIcon, { sx: { fontSize: "0.85rem", color: "text.secondary" } }),
|
|
195
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: "Bundled files" })
|
|
196
|
+
] }),
|
|
197
|
+
asset.resourcesContent && Object.keys(asset.resourcesContent).length > 0 ? /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 0.5, mt: 0.5 }, children: [
|
|
198
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" }, children: [
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
Chip,
|
|
201
|
+
{
|
|
202
|
+
label: "SKILL.md",
|
|
203
|
+
size: "small",
|
|
204
|
+
sx: { fontFamily: "monospace", fontSize: "0.7rem", height: 20 }
|
|
205
|
+
}
|
|
206
|
+
),
|
|
207
|
+
Object.keys(asset.resourcesContent).map((p) => /* @__PURE__ */ jsx(
|
|
208
|
+
Chip,
|
|
209
|
+
{
|
|
210
|
+
label: p,
|
|
211
|
+
size: "small",
|
|
212
|
+
variant: "outlined",
|
|
213
|
+
sx: { fontFamily: "monospace", fontSize: "0.7rem", height: 20 }
|
|
214
|
+
},
|
|
215
|
+
p
|
|
216
|
+
))
|
|
217
|
+
] }),
|
|
218
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.disabled", children: "Downloads as .zip containing all files above." })
|
|
219
|
+
] }) : /* @__PURE__ */ jsx(Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mt: 0.5 }, children: /* @__PURE__ */ jsx(
|
|
220
|
+
Chip,
|
|
221
|
+
{
|
|
222
|
+
label: "SKILL.md",
|
|
223
|
+
size: "small",
|
|
224
|
+
sx: { fontFamily: "monospace", fontSize: "0.7rem", height: 20 }
|
|
225
|
+
}
|
|
226
|
+
) })
|
|
227
|
+
] })
|
|
228
|
+
] }),
|
|
229
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
230
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
231
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: "Repository" }),
|
|
232
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(
|
|
233
|
+
Link,
|
|
234
|
+
{
|
|
235
|
+
href: asset.repoUrl,
|
|
236
|
+
target: "_blank",
|
|
237
|
+
rel: "noopener noreferrer",
|
|
238
|
+
variant: "body2",
|
|
239
|
+
children: [
|
|
240
|
+
asset.repoUrl,
|
|
241
|
+
" ",
|
|
242
|
+
/* @__PURE__ */ jsx(OpenInNewIcon, { sx: { fontSize: 12 } })
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
) })
|
|
246
|
+
] })
|
|
247
|
+
] }),
|
|
248
|
+
tab === 2 && /* @__PURE__ */ jsx(
|
|
249
|
+
Box,
|
|
250
|
+
{
|
|
251
|
+
component: "pre",
|
|
252
|
+
sx: {
|
|
253
|
+
bgcolor: "action.hover",
|
|
254
|
+
p: 2,
|
|
255
|
+
borderRadius: 1,
|
|
256
|
+
overflow: "auto",
|
|
257
|
+
fontSize: "0.8rem",
|
|
258
|
+
fontFamily: "monospace",
|
|
259
|
+
whiteSpace: "pre-wrap",
|
|
260
|
+
wordBreak: "break-word",
|
|
261
|
+
border: "1px solid",
|
|
262
|
+
borderColor: "divider"
|
|
263
|
+
},
|
|
264
|
+
children: asset.yamlRaw
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
] })
|
|
268
|
+
] }),
|
|
269
|
+
/* @__PURE__ */ jsxs(
|
|
270
|
+
Box,
|
|
271
|
+
{
|
|
272
|
+
sx: {
|
|
273
|
+
p: 2,
|
|
274
|
+
borderTop: 1,
|
|
275
|
+
borderColor: "divider",
|
|
276
|
+
display: "flex",
|
|
277
|
+
gap: 1,
|
|
278
|
+
flexWrap: "wrap"
|
|
279
|
+
},
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ jsx(
|
|
282
|
+
Button,
|
|
283
|
+
{
|
|
284
|
+
variant: "contained",
|
|
285
|
+
startIcon: /* @__PURE__ */ jsx(ContentCopyIcon, {}),
|
|
286
|
+
onClick: handleCopy,
|
|
287
|
+
disabled: !asset,
|
|
288
|
+
children: "Copy Markdown"
|
|
289
|
+
}
|
|
290
|
+
),
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
Button,
|
|
293
|
+
{
|
|
294
|
+
variant: "outlined",
|
|
295
|
+
startIcon: /* @__PURE__ */ jsx(OpenInNewIcon, {}),
|
|
296
|
+
onClick: () => asset && window.open(asset.repoUrl, "_blank"),
|
|
297
|
+
disabled: !asset,
|
|
298
|
+
children: "Open in Repo"
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
] })
|
|
305
|
+
}
|
|
306
|
+
),
|
|
307
|
+
/* @__PURE__ */ jsx(
|
|
308
|
+
Snackbar,
|
|
309
|
+
{
|
|
310
|
+
open: !!snackbar,
|
|
311
|
+
autoHideDuration: 2500,
|
|
312
|
+
onClose: () => setSnackbar(null),
|
|
313
|
+
anchorOrigin: { vertical: "bottom", horizontal: "center" },
|
|
314
|
+
children: /* @__PURE__ */ jsx(Alert, { severity: "success", onClose: () => setSnackbar(null), children: snackbar })
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
] });
|
|
318
|
+
}
|
|
319
|
+
function MetaRow({ label, value }) {
|
|
320
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
321
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: label }),
|
|
322
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", children: value })
|
|
323
|
+
] });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export { AssetDetailPanel };
|
|
327
|
+
//# sourceMappingURL=AssetDetailPanel.esm.js.map
|