@nospt/plugin-dev-ai-hub 0.2.3 → 0.3.0
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/DevAiHubResourceClient.esm.js +97 -0
- package/dist/api/DevAiHubResourceClient.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/AiResourcesPage.esm.js +150 -0
- package/dist/components/AiResourcesPage/AiResourcesPage.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/AiResourcesPage.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/AiResourcesPage.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceCard.esm.js +158 -0
- package/dist/components/AiResourcesPage/ResourceCard.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceCard.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/ResourceCard.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceDetailPanel.esm.js +234 -0
- package/dist/components/AiResourcesPage/ResourceDetailPanel.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceDetailPanel.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/ResourceDetailPanel.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceFilters.esm.js +242 -0
- package/dist/components/AiResourcesPage/ResourceFilters.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceFilters.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/ResourceFilters.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceInstallDialog.esm.js +366 -0
- package/dist/components/AiResourcesPage/ResourceInstallDialog.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/ResourceInstallDialog.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/ResourceInstallDialog.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/StatTiles.esm.js +49 -0
- package/dist/components/AiResourcesPage/StatTiles.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/StatTiles.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/StatTiles.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/index.esm.js +6 -0
- package/dist/components/AiResourcesPage/typeMeta.esm.js +35 -0
- package/dist/components/AiResourcesPage/typeMeta.esm.js.map +1 -0
- package/dist/components/ToolIcon/ToolIcon.esm.js +26 -9
- package/dist/components/ToolIcon/ToolIcon.esm.js.map +1 -1
- package/dist/hooks/useResourceBody.esm.js +39 -0
- package/dist/hooks/useResourceBody.esm.js.map +1 -0
- package/dist/hooks/useResources.esm.js +26 -0
- package/dist/hooks/useResources.esm.js.map +1 -0
- package/dist/hooks/useTelemetryCounts.esm.js +24 -0
- package/dist/hooks/useTelemetryCounts.esm.js.map +1 -0
- package/dist/index.d.ts +1 -38
- package/dist/index.esm.js +1 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin.esm.js +17 -26
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +1 -2
- package/dist/routes.esm.js.map +1 -1
- package/package.json +17 -10
- package/.eslintrc.js +0 -1
- package/dev/index.tsx +0 -32
- package/dist/api/DevAiHubClient.esm.js +0 -78
- package/dist/api/DevAiHubClient.esm.js.map +0 -1
- package/dist/components/AssetCard/AssetCard.esm.js +0 -120
- package/dist/components/AssetCard/AssetCard.esm.js.map +0 -1
- package/dist/components/AssetCard/AssetCard.module.css.esm.js +0 -8
- package/dist/components/AssetCard/AssetCard.module.css.esm.js.map +0 -1
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js +0 -218
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js.map +0 -1
- package/dist/components/AssetDetailPanel/AssetDetailPanel.module.css.esm.js +0 -8
- package/dist/components/AssetDetailPanel/AssetDetailPanel.module.css.esm.js.map +0 -1
- package/dist/components/AssetFilters/AssetFilters.esm.js +0 -176
- package/dist/components/AssetFilters/AssetFilters.esm.js.map +0 -1
- package/dist/components/AssetFilters/AssetFilters.module.css.esm.js +0 -8
- package/dist/components/AssetFilters/AssetFilters.module.css.esm.js.map +0 -1
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js +0 -138
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js.map +0 -1
- package/dist/components/AssetInstallDialog/AssetInstallDialog.module.css.esm.js +0 -8
- package/dist/components/AssetInstallDialog/AssetInstallDialog.module.css.esm.js.map +0 -1
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js +0 -195
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js.map +0 -1
- package/dist/components/DevAiHubPage/DevAiHubPage.module.css.esm.js +0 -8
- package/dist/components/DevAiHubPage/DevAiHubPage.module.css.esm.js.map +0 -1
- package/dist/components/DevAiHubPage/index.esm.js +0 -6
- package/dist/components/McpConfigPage/McpConfigPage.esm.js +0 -200
- package/dist/components/McpConfigPage/McpConfigPage.esm.js.map +0 -1
- package/dist/components/McpConfigPage/McpConfigPage.module.css.esm.js +0 -8
- package/dist/components/McpConfigPage/McpConfigPage.module.css.esm.js.map +0 -1
- package/dist/components/McpConfigPage/index.esm.js +0 -6
- package/dist/components/McpConfigPage/index.esm.js.map +0 -1
- package/dist/hooks/index.esm.js +0 -114
- package/dist/hooks/index.esm.js.map +0 -1
- package/dist/pluginLegacy.esm.js +0 -27
- package/dist/pluginLegacy.esm.js.map +0 -1
- package/package.json-prepack +0 -85
- package/src/api/DevAiHubClient.ts +0 -110
- package/src/components/AssetCard/AssetCard.module.css +0 -153
- package/src/components/AssetCard/AssetCard.test.tsx +0 -182
- package/src/components/AssetCard/AssetCard.tsx +0 -152
- package/src/components/AssetCard/index.ts +0 -1
- package/src/components/AssetDetailPanel/AssetDetailPanel.module.css +0 -207
- package/src/components/AssetDetailPanel/AssetDetailPanel.tsx +0 -313
- package/src/components/AssetDetailPanel/index.ts +0 -1
- package/src/components/AssetFilters/AssetFilters.module.css +0 -67
- package/src/components/AssetFilters/AssetFilters.tsx +0 -219
- package/src/components/AssetFilters/index.ts +0 -2
- package/src/components/AssetInstallDialog/AssetInstallDialog.module.css +0 -72
- package/src/components/AssetInstallDialog/AssetInstallDialog.tsx +0 -176
- package/src/components/AssetInstallDialog/index.ts +0 -1
- package/src/components/DevAiHubPage/DevAiHubPage.module.css +0 -105
- package/src/components/DevAiHubPage/DevAiHubPage.tsx +0 -197
- package/src/components/DevAiHubPage/index.ts +0 -1
- package/src/components/McpConfigDialog/McpConfigDialog.module.css +0 -111
- package/src/components/McpConfigDialog/McpConfigDialog.tsx +0 -271
- package/src/components/McpConfigDialog/index.ts +0 -1
- package/src/components/McpConfigPage/McpConfigPage.module.css +0 -121
- package/src/components/McpConfigPage/McpConfigPage.tsx +0 -242
- package/src/components/McpConfigPage/index.ts +0 -1
- package/src/components/ToolIcon/ToolIcon.tsx +0 -65
- package/src/components/ToolIcon/index.ts +0 -1
- package/src/css-modules.d.ts +0 -4
- package/src/hooks/index.ts +0 -152
- package/src/index.ts +0 -10
- package/src/plugin.tsx +0 -60
- package/src/pluginLegacy.ts +0 -42
- package/src/routes.ts +0 -4
- package/tests/e2e/.auth.json +0 -14
- package/tests/e2e/asset-detail.spec.ts +0 -90
- package/tests/e2e/asset-filtering.spec.ts +0 -145
- package/tests/e2e/asset-installation.spec.ts +0 -74
- package/tests/e2e/dev-ai-hub-page.spec.ts +0 -89
- package/tests/e2e/fixtures/base.ts +0 -61
- package/tests/e2e/fixtures/mock-api.ts +0 -221
- package/tests/e2e/mcp-config.spec.ts +0 -88
- package/tsconfig.json +0 -10
- /package/dist/components/{DevAiHubPage → AiResourcesPage}/index.esm.js.map +0 -0
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { RiInfinityLine
|
|
2
|
+
import { RiInfinityLine } from '@remixicon/react';
|
|
3
3
|
import { siGooglegemini, siGithub, siAnthropic } from 'simple-icons';
|
|
4
4
|
|
|
5
|
+
const CURSOR_PATH = "m20.42 6.73l-8-4.62a.82.82 0 0 0-.83 0L3.58 6.73c-.22.12-.35.36-.35.61v9.32c0 .25.13.48.35.61l8.01 4.62c.26.15.57.15.83 0l8.01-4.62c.22-.12.35-.36.35-.61V7.34c0-.25-.13-.48-.35-.61Zm-.5.98L12.19 21.1c-.05.09-.19.05-.19-.05v-8.77c0-.18-.09-.34-.25-.43L4.16 7.47c-.09-.05-.05-.19.05-.19h15.46c.22 0 .36.24.25.43";
|
|
5
6
|
const TOOL_ICON = {
|
|
6
|
-
"claude-code": { ...siAnthropic, label: "Claude Code" },
|
|
7
|
-
"github-copilot": { ...siGithub, label: "GitHub Copilot" },
|
|
7
|
+
"claude-code": { ...siAnthropic, label: "Claude Code", monochrome: true },
|
|
8
|
+
"github-copilot": { ...siGithub, label: "GitHub Copilot", monochrome: true },
|
|
8
9
|
"google-gemini": { ...siGooglegemini, label: "Google Gemini" }
|
|
9
10
|
};
|
|
10
|
-
function ToolIcon({
|
|
11
|
+
function ToolIcon({
|
|
12
|
+
tool,
|
|
13
|
+
branded = true,
|
|
14
|
+
className,
|
|
15
|
+
style,
|
|
16
|
+
size = 20
|
|
17
|
+
}) {
|
|
11
18
|
if (tool === "all") {
|
|
12
19
|
return /* @__PURE__ */ jsx(
|
|
13
20
|
RiInfinityLine,
|
|
@@ -21,17 +28,27 @@ function ToolIcon({ tool, branded = true, className, style, size = 20 }) {
|
|
|
21
28
|
}
|
|
22
29
|
if (tool === "cursor") {
|
|
23
30
|
return /* @__PURE__ */ jsx(
|
|
24
|
-
|
|
31
|
+
"svg",
|
|
25
32
|
{
|
|
26
|
-
|
|
33
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
34
|
+
viewBox: "0 0 24 24",
|
|
35
|
+
width: size,
|
|
36
|
+
height: size,
|
|
37
|
+
fill: "currentColor",
|
|
27
38
|
className,
|
|
28
|
-
style: {
|
|
29
|
-
|
|
39
|
+
style: {
|
|
40
|
+
color: branded ? "var(--bui-fg-primary)" : "inherit",
|
|
41
|
+
...style
|
|
42
|
+
},
|
|
43
|
+
"aria-label": "Cursor",
|
|
44
|
+
role: "img",
|
|
45
|
+
children: /* @__PURE__ */ jsx("path", { d: CURSOR_PATH })
|
|
30
46
|
}
|
|
31
47
|
);
|
|
32
48
|
}
|
|
33
49
|
const cfg = TOOL_ICON[tool];
|
|
34
50
|
if (!cfg) return null;
|
|
51
|
+
const brandedColor = cfg.monochrome ? "var(--bui-fg-primary)" : `#${cfg.hex}`;
|
|
35
52
|
return /* @__PURE__ */ jsx(
|
|
36
53
|
"svg",
|
|
37
54
|
{
|
|
@@ -41,7 +58,7 @@ function ToolIcon({ tool, branded = true, className, style, size = 20 }) {
|
|
|
41
58
|
height: size,
|
|
42
59
|
fill: "currentColor",
|
|
43
60
|
className,
|
|
44
|
-
style: { color: branded ?
|
|
61
|
+
style: { color: branded ? brandedColor : "inherit", ...style },
|
|
45
62
|
"aria-label": cfg.label,
|
|
46
63
|
role: "img",
|
|
47
64
|
children: /* @__PURE__ */ jsx("path", { d: cfg.path })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolIcon.esm.js","sources":["../../../src/components/ToolIcon/ToolIcon.tsx"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport { RiInfinityLine
|
|
1
|
+
{"version":3,"file":"ToolIcon.esm.js","sources":["../../../src/components/ToolIcon/ToolIcon.tsx"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport { RiInfinityLine } from '@remixicon/react';\nimport { siAnthropic, siGithub, siGooglegemini } from 'simple-icons';\nimport type { FrameworkToken } from '@nospt/plugin-dev-ai-hub-common';\n\n/* Cursor's cube mark isn't in simple-icons; path from Boxicons Brands\n (`bxl:cursor-ai`, MIT). Monochrome brand — no branded hex. */\nconst CURSOR_PATH =\n 'm20.42 6.73l-8-4.62a.82.82 0 0 0-.83 0L3.58 6.73c-.22.12-.35.36-.35.61v9.32c0 .25.13.48.35.61l8.01 4.62c.26.15.57.15.83 0l8.01-4.62c.22-.12.35-.36.35-.61V7.34c0-.25-.13-.48-.35-.61Zm-.5.98L12.19 21.1c-.05.09-.19.05-.19-.05v-8.77c0-.18-.09-.34-.25-.43L4.16 7.47c-.09-.05-.05-.19.05-.19h15.46c.22 0 .36.24.25.43';\n\ntype SvgTool = Exclude<FrameworkToken, 'all' | 'cursor'>;\n\n/**\n * Anthropic's and GitHub's marks are monochrome brand assets (near-black,\n * `#191919` / `#181717`) meant to be manually inverted per surface — used\n * literally, they're invisible on the dark theme's dark backgrounds. Treat\n * them like `cursor` below (theme-aware `--bui-fg-primary`) instead of their\n * literal hex. Google's mark is an actual mid-tone brand colour (`#8E75B2`)\n * that reads fine on both themes, so it keeps its literal hex.\n */\nconst TOOL_ICON: Record<\n SvgTool,\n { path: string; hex: string; label: string; monochrome?: boolean }\n> = {\n 'claude-code': { ...siAnthropic, label: 'Claude Code', monochrome: true },\n 'github-copilot': { ...siGithub, label: 'GitHub Copilot', monochrome: true },\n 'google-gemini': { ...siGooglegemini, label: 'Google Gemini' },\n};\n\ninterface ToolIconProps {\n tool: FrameworkToken;\n /** Use the brand's official color. Defaults to true. */\n branded?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Icon size in pixels. Defaults to 20. */\n size?: number;\n}\n\nexport function ToolIcon({\n tool,\n branded = true,\n className,\n style,\n size = 20,\n}: ToolIconProps) {\n if (tool === 'all') {\n return (\n <RiInfinityLine\n size={size}\n className={className}\n style={{ color: 'var(--bui-fg-secondary)', ...style }}\n aria-label=\"Universal\"\n />\n );\n }\n\n if (tool === 'cursor') {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n fill=\"currentColor\"\n className={className}\n style={{\n color: branded ? 'var(--bui-fg-primary)' : 'inherit',\n ...style,\n }}\n aria-label=\"Cursor\"\n role=\"img\"\n >\n <path d={CURSOR_PATH} />\n </svg>\n );\n }\n\n const cfg = TOOL_ICON[tool as SvgTool];\n if (!cfg) return null;\n\n const brandedColor = cfg.monochrome ? 'var(--bui-fg-primary)' : `#${cfg.hex}`;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n fill=\"currentColor\"\n className={className}\n style={{ color: branded ? brandedColor : 'inherit', ...style }}\n aria-label={cfg.label}\n role=\"img\"\n >\n <path d={cfg.path} />\n </svg>\n );\n}\n"],"names":[],"mappings":";;;;AAOA,MAAM,WAAA,GACJ,uTAAA;AAYF,MAAM,SAAA,GAGF;AAAA,EACF,eAAe,EAAE,GAAG,aAAa,KAAA,EAAO,aAAA,EAAe,YAAY,IAAA,EAAK;AAAA,EACxE,kBAAkB,EAAE,GAAG,UAAU,KAAA,EAAO,gBAAA,EAAkB,YAAY,IAAA,EAAK;AAAA,EAC3E,eAAA,EAAiB,EAAE,GAAG,cAAA,EAAgB,OAAO,eAAA;AAC/C,CAAA;AAYO,SAAS,QAAA,CAAS;AAAA,EACvB,IAAA;AAAA,EACA,OAAA,GAAU,IAAA;AAAA,EACV,SAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO;AACT,CAAA,EAAkB;AAChB,EAAA,IAAI,SAAS,KAAA,EAAO;AAClB,IAAA,uBACE,GAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,IAAA;AAAA,QACA,SAAA;AAAA,QACA,KAAA,EAAO,EAAE,KAAA,EAAO,yBAAA,EAA2B,GAAG,KAAA,EAAM;AAAA,QACpD,YAAA,EAAW;AAAA;AAAA,KACb;AAAA,EAEJ;AAEA,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAM,4BAAA;AAAA,QACN,OAAA,EAAQ,WAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,MAAA,EAAQ,IAAA;AAAA,QACR,IAAA,EAAK,cAAA;AAAA,QACL,SAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACL,KAAA,EAAO,UAAU,uBAAA,GAA0B,SAAA;AAAA,UAC3C,GAAG;AAAA,SACL;AAAA,QACA,YAAA,EAAW,QAAA;AAAA,QACX,IAAA,EAAK,KAAA;AAAA,QAEL,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAG,WAAA,EAAa;AAAA;AAAA,KACxB;AAAA,EAEJ;AAEA,EAAA,MAAM,GAAA,GAAM,UAAU,IAAe,CAAA;AACrC,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAEjB,EAAA,MAAM,eAAe,GAAA,CAAI,UAAA,GAAa,uBAAA,GAA0B,CAAA,CAAA,EAAI,IAAI,GAAG,CAAA,CAAA;AAE3E,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,4BAAA;AAAA,MACN,OAAA,EAAQ,WAAA;AAAA,MACR,KAAA,EAAO,IAAA;AAAA,MACP,MAAA,EAAQ,IAAA;AAAA,MACR,IAAA,EAAK,cAAA;AAAA,MACL,SAAA;AAAA,MACA,OAAO,EAAE,KAAA,EAAO,UAAU,YAAA,GAAe,SAAA,EAAW,GAAG,KAAA,EAAM;AAAA,MAC7D,cAAY,GAAA,CAAI,KAAA;AAAA,MAChB,IAAA,EAAK,KAAA;AAAA,MAEL,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAG,GAAA,CAAI,IAAA,EAAM;AAAA;AAAA,GACrB;AAEJ;;;;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { devAiHubResourceApiRef, ResourceBodyError } from '../api/DevAiHubResourceClient.esm.js';
|
|
4
|
+
|
|
5
|
+
function useResourceBody(entityRef, enabled) {
|
|
6
|
+
const api = useApi(devAiHubResourceApiRef);
|
|
7
|
+
const [body, setBody] = useState();
|
|
8
|
+
const [loading, setLoading] = useState(false);
|
|
9
|
+
const [error, setError] = useState();
|
|
10
|
+
const [attempt, setAttempt] = useState(0);
|
|
11
|
+
const retry = useCallback(() => setAttempt((a) => a + 1), []);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setBody(void 0);
|
|
14
|
+
setError(void 0);
|
|
15
|
+
if (!entityRef || !enabled) {
|
|
16
|
+
setLoading(false);
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
setLoading(true);
|
|
21
|
+
api.getEntityBody(entityRef).then((result) => {
|
|
22
|
+
if (!cancelled) setBody(result);
|
|
23
|
+
}).catch((err) => {
|
|
24
|
+
if (cancelled) return;
|
|
25
|
+
setError(
|
|
26
|
+
err instanceof ResourceBodyError && err.status === 404 ? "not-found" : "upstream"
|
|
27
|
+
);
|
|
28
|
+
}).finally(() => {
|
|
29
|
+
if (!cancelled) setLoading(false);
|
|
30
|
+
});
|
|
31
|
+
return () => {
|
|
32
|
+
cancelled = true;
|
|
33
|
+
};
|
|
34
|
+
}, [api, entityRef, enabled, attempt]);
|
|
35
|
+
return { body, loading, error, retry };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { useResourceBody };
|
|
39
|
+
//# sourceMappingURL=useResourceBody.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResourceBody.esm.js","sources":["../../src/hooks/useResourceBody.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n devAiHubResourceApiRef,\n ResourceBody,\n ResourceBodyError,\n} from '../api/DevAiHubResourceClient';\n\nexport type ResourceBodyErrorKind = 'not-found' | 'upstream';\n\nexport interface ResourceBodyState {\n body?: ResourceBody;\n loading: boolean;\n error?: ResourceBodyErrorKind;\n retry: () => void;\n}\n\n/**\n * Lazily fetch a resource's viewable body when the detail drawer opens.\n * `enabled` is false for non-actionable resources (no source-location) —\n * nothing is fetched and the state stays empty.\n */\nexport function useResourceBody(\n entityRef: string | undefined,\n enabled: boolean,\n): ResourceBodyState {\n const api = useApi(devAiHubResourceApiRef);\n const [body, setBody] = useState<ResourceBody>();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<ResourceBodyErrorKind>();\n const [attempt, setAttempt] = useState(0);\n\n const retry = useCallback(() => setAttempt(a => a + 1), []);\n\n useEffect(() => {\n setBody(undefined);\n setError(undefined);\n if (!entityRef || !enabled) {\n setLoading(false);\n return undefined;\n }\n\n let cancelled = false;\n setLoading(true);\n api\n .getEntityBody(entityRef)\n .then(result => {\n if (!cancelled) setBody(result);\n })\n .catch(err => {\n if (cancelled) return;\n setError(\n err instanceof ResourceBodyError && err.status === 404\n ? 'not-found'\n : 'upstream',\n );\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [api, entityRef, enabled, attempt]);\n\n return { body, loading, error, retry };\n}\n"],"names":[],"mappings":";;;;AAsBO,SAAS,eAAA,CACd,WACA,OAAA,EACmB;AACnB,EAAA,MAAM,GAAA,GAAM,OAAO,sBAAsB,CAAA;AACzC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,EAAuB;AAC/C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA,EAAgC;AAC1D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,CAAC,CAAA;AAExC,EAAA,MAAM,KAAA,GAAQ,YAAY,MAAM,UAAA,CAAW,OAAK,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAA,CAAQ,MAAS,CAAA;AACjB,IAAA,QAAA,CAAS,MAAS,CAAA;AAClB,IAAA,IAAI,CAAC,SAAA,IAAa,CAAC,OAAA,EAAS;AAC1B,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,GAAA,CACG,aAAA,CAAc,SAAS,CAAA,CACvB,IAAA,CAAK,CAAA,MAAA,KAAU;AACd,MAAA,IAAI,CAAC,SAAA,EAAW,OAAA,CAAQ,MAAM,CAAA;AAAA,IAChC,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,GAAA,KAAO;AACZ,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,QAAA;AAAA,QACE,GAAA,YAAe,iBAAA,IAAqB,GAAA,CAAI,MAAA,KAAW,MAC/C,WAAA,GACA;AAAA,OACN;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAAA,IAClC,CAAC,CAAA;AAEH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,GAAG,CAAC,GAAA,EAAK,SAAA,EAAW,OAAA,EAAS,OAAO,CAAC,CAAA;AAErC,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,KAAA,EAAM;AACvC;;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { devAiHubResourceApiRef } from '../api/DevAiHubResourceClient.esm.js';
|
|
4
|
+
|
|
5
|
+
function useResources() {
|
|
6
|
+
const api = useApi(devAiHubResourceApiRef);
|
|
7
|
+
const [items, setItems] = useState(void 0);
|
|
8
|
+
const [error, setError] = useState(void 0);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
let active = true;
|
|
11
|
+
setItems(void 0);
|
|
12
|
+
setError(void 0);
|
|
13
|
+
api.getResources().then((result) => {
|
|
14
|
+
if (active) setItems(result);
|
|
15
|
+
}).catch((e) => {
|
|
16
|
+
if (active) setError(e instanceof Error ? e : new Error(String(e)));
|
|
17
|
+
});
|
|
18
|
+
return () => {
|
|
19
|
+
active = false;
|
|
20
|
+
};
|
|
21
|
+
}, [api]);
|
|
22
|
+
return { items, error, loading: items === void 0 && error === void 0 };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { useResources };
|
|
26
|
+
//# sourceMappingURL=useResources.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResources.esm.js","sources":["../../src/hooks/useResources.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport type { ResourceSummary } from '@nospt/plugin-dev-ai-hub-common';\nimport { devAiHubResourceApiRef } from '../api/DevAiHubResourceClient';\n\nexport function useResources() {\n const api = useApi(devAiHubResourceApiRef);\n const [items, setItems] = useState<ResourceSummary[] | undefined>(undefined);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n useEffect(() => {\n let active = true;\n setItems(undefined);\n setError(undefined);\n api\n .getResources()\n .then(result => {\n if (active) setItems(result);\n })\n .catch(e => {\n if (active) setError(e instanceof Error ? e : new Error(String(e)));\n });\n return () => {\n active = false;\n };\n }, [api]);\n\n return { items, error, loading: items === undefined && error === undefined };\n}\n"],"names":[],"mappings":";;;;AAKO,SAAS,YAAA,GAAe;AAC7B,EAAA,MAAM,GAAA,GAAM,OAAO,sBAAsB,CAAA;AACzC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwC,MAAS,CAAA;AAC3E,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAA4B,MAAS,CAAA;AAE/D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,QAAA,CAAS,MAAS,CAAA;AAClB,IAAA,QAAA,CAAS,MAAS,CAAA;AAClB,IAAA,GAAA,CACG,YAAA,EAAa,CACb,IAAA,CAAK,CAAA,MAAA,KAAU;AACd,MAAA,IAAI,MAAA,WAAiB,MAAM,CAAA;AAAA,IAC7B,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,CAAA,KAAK;AACV,MAAA,IAAI,MAAA,EAAQ,QAAA,CAAS,CAAA,YAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,IACpE,CAAC,CAAA;AACH,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,GAAS,KAAA;AAAA,IACX,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AAER,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,SAAS,KAAA,KAAU,MAAA,IAAa,UAAU,MAAA,EAAU;AAC7E;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { devAiHubResourceApiRef } from '../api/DevAiHubResourceClient.esm.js';
|
|
4
|
+
|
|
5
|
+
function useTelemetryCounts(entityRef) {
|
|
6
|
+
const api = useApi(devAiHubResourceApiRef);
|
|
7
|
+
const [counts, setCounts] = useState();
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setCounts(void 0);
|
|
10
|
+
if (!entityRef) return void 0;
|
|
11
|
+
let cancelled = false;
|
|
12
|
+
api.getInstallCount(entityRef).then((result) => {
|
|
13
|
+
if (!cancelled) setCounts(result);
|
|
14
|
+
}).catch(() => {
|
|
15
|
+
});
|
|
16
|
+
return () => {
|
|
17
|
+
cancelled = true;
|
|
18
|
+
};
|
|
19
|
+
}, [api, entityRef]);
|
|
20
|
+
return counts;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { useTelemetryCounts };
|
|
24
|
+
//# sourceMappingURL=useTelemetryCounts.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTelemetryCounts.esm.js","sources":["../../src/hooks/useTelemetryCounts.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport type { TelemetryCounts } from '@nospt/plugin-dev-ai-hub-common';\nimport { devAiHubResourceApiRef } from '../api/DevAiHubResourceClient';\n\n/**\n * Raw per-action telemetry counts for a resource (ADR-0007). Fetch failures\n * are swallowed — a missing count is not worth surfacing as a UI error, the\n * card/detail just renders without it.\n */\nexport function useTelemetryCounts(\n entityRef: string | undefined,\n): TelemetryCounts | undefined {\n const api = useApi(devAiHubResourceApiRef);\n const [counts, setCounts] = useState<TelemetryCounts>();\n\n useEffect(() => {\n setCounts(undefined);\n if (!entityRef) return undefined;\n\n let cancelled = false;\n api\n .getInstallCount(entityRef)\n .then(result => {\n if (!cancelled) setCounts(result);\n })\n .catch(() => {\n // ignored — see above\n });\n return () => {\n cancelled = true;\n };\n }, [api, entityRef]);\n\n return counts;\n}\n"],"names":[],"mappings":";;;;AAUO,SAAS,mBACd,SAAA,EAC6B;AAC7B,EAAA,MAAM,GAAA,GAAM,OAAO,sBAAsB,CAAA;AACzC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAA,EAA0B;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,SAAA,CAAU,MAAS,CAAA;AACnB,IAAA,IAAI,CAAC,WAAW,OAAO,MAAA;AAEvB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,GAAA,CACG,eAAA,CAAgB,SAAS,CAAA,CACzB,IAAA,CAAK,CAAA,MAAA,KAAU;AACd,MAAA,IAAI,CAAC,SAAA,EAAW,SAAA,CAAU,MAAM,CAAA;AAAA,IAClC,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AAAA,IAEb,CAAC,CAAA;AACH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAA,EAAK,SAAS,CAAC,CAAA;AAEnB,EAAA,OAAO,MAAA;AACT;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ComponentType } from 'react';
|
|
3
2
|
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
4
|
-
import { AssetListFilter, AiAssetListResponse, AiAsset, AiHubProvider, AiHubStats } from '@nospt/plugin-dev-ai-hub-common';
|
|
5
3
|
|
|
6
4
|
declare const devAiHubPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{
|
|
7
5
|
root: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
8
|
-
mcpConfig: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
9
6
|
}, {}, {
|
|
10
|
-
"api:dev-ai-hub": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
11
|
-
kind: "api";
|
|
12
|
-
name: undefined;
|
|
13
|
-
config: {};
|
|
14
|
-
configInput: {};
|
|
15
|
-
output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
|
|
16
|
-
inputs: {};
|
|
17
|
-
params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
|
|
18
|
-
}>;
|
|
19
7
|
"page:dev-ai-hub": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
20
8
|
kind: "page";
|
|
21
9
|
name: undefined;
|
|
@@ -58,31 +46,6 @@ declare const devAiHubPlugin: _backstage_frontend_plugin_api.OverridableFrontend
|
|
|
58
46
|
}>;
|
|
59
47
|
}>;
|
|
60
48
|
|
|
61
|
-
/**
|
|
62
|
-
* Legacy Backstage frontend system support.
|
|
63
|
-
*
|
|
64
|
-
* For New Frontend System (NFS) use `devAiHubPlugin` from `./plugin` instead.
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
/** Routable page extension for the legacy frontend system. */
|
|
68
|
-
declare const DevAiHubPage: ComponentType;
|
|
69
|
-
|
|
70
|
-
declare const devAiHubApiRef: _backstage_frontend_plugin_api.ApiRef<DevAiHubApi>;
|
|
71
|
-
interface DevAiHubApi {
|
|
72
|
-
listAssets(filter?: AssetListFilter): Promise<AiAssetListResponse>;
|
|
73
|
-
getAsset(id: string): Promise<AiAsset>;
|
|
74
|
-
getAssetRaw(id: string): Promise<string>;
|
|
75
|
-
/** Returns the absolute URL for the download endpoint (zip for skills, md for others). */
|
|
76
|
-
getDownloadUrl(id: string): Promise<string>;
|
|
77
|
-
trackInstall(id: string): Promise<void>;
|
|
78
|
-
listProviders(): Promise<AiHubProvider[]>;
|
|
79
|
-
getProviderStatus(id: string): Promise<AiHubProvider>;
|
|
80
|
-
triggerSync(id: string): Promise<void>;
|
|
81
|
-
getStats(): Promise<AiHubStats>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
49
|
declare const rootRouteRef: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
85
|
-
declare const mcpConfigRouteRef: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
86
50
|
|
|
87
|
-
export {
|
|
88
|
-
export type { DevAiHubApi };
|
|
51
|
+
export { devAiHubPlugin, rootRouteRef };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
export { devAiHubPlugin } from './plugin.esm.js';
|
|
2
|
-
export {
|
|
3
|
-
export { devAiHubApiRef } from './api/DevAiHubClient.esm.js';
|
|
4
|
-
export { mcpConfigRouteRef, rootRouteRef } from './routes.esm.js';
|
|
2
|
+
export { rootRouteRef } from './routes.esm.js';
|
|
5
3
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/plugin.esm.js
CHANGED
|
@@ -1,48 +1,39 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { createFrontendPlugin, ApiBlueprint, createApiFactory, fetchApiRef, discoveryApiRef,
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { createFrontendPlugin, PageBlueprint, ApiBlueprint, createApiFactory, fetchApiRef, discoveryApiRef, SubPageBlueprint } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { RiRobot3Fill } from '@remixicon/react';
|
|
4
|
+
import { DevAiHubResourceClient, devAiHubResourceApiRef } from './api/DevAiHubResourceClient.esm.js';
|
|
5
|
+
import { rootRouteRef } from './routes.esm.js';
|
|
6
6
|
|
|
7
7
|
const devAiHubPlugin = createFrontendPlugin({
|
|
8
8
|
pluginId: "dev-ai-hub",
|
|
9
9
|
routes: {
|
|
10
|
-
root: rootRouteRef
|
|
11
|
-
mcpConfig: mcpConfigRouteRef
|
|
10
|
+
root: rootRouteRef
|
|
12
11
|
},
|
|
13
12
|
extensions: [
|
|
14
|
-
ApiBlueprint.make({
|
|
15
|
-
params: (defineParams) => defineParams(
|
|
16
|
-
createApiFactory({
|
|
17
|
-
api: devAiHubApiRef,
|
|
18
|
-
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
|
|
19
|
-
factory: ({ discoveryApi, fetchApi }) => new DevAiHubClient(discoveryApi, fetchApi)
|
|
20
|
-
})
|
|
21
|
-
)
|
|
22
|
-
}),
|
|
23
13
|
PageBlueprint.make({
|
|
24
14
|
params: {
|
|
25
15
|
path: "/dev-ai-hub",
|
|
26
16
|
title: "Dev AI Hub",
|
|
27
|
-
icon: /* @__PURE__ */ jsx(
|
|
17
|
+
icon: /* @__PURE__ */ jsx(RiRobot3Fill, {}),
|
|
28
18
|
routeRef: rootRouteRef
|
|
29
19
|
}
|
|
30
20
|
}),
|
|
21
|
+
ApiBlueprint.make({
|
|
22
|
+
name: "resources",
|
|
23
|
+
params: (defineParams) => defineParams(
|
|
24
|
+
createApiFactory({
|
|
25
|
+
api: devAiHubResourceApiRef,
|
|
26
|
+
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
|
|
27
|
+
factory: ({ discoveryApi, fetchApi }) => new DevAiHubResourceClient(discoveryApi, fetchApi)
|
|
28
|
+
})
|
|
29
|
+
)
|
|
30
|
+
}),
|
|
31
31
|
SubPageBlueprint.make({
|
|
32
32
|
name: "browse",
|
|
33
33
|
params: {
|
|
34
34
|
path: "browse",
|
|
35
35
|
title: "Browse",
|
|
36
|
-
loader: () => import('./components/
|
|
37
|
-
}
|
|
38
|
-
}),
|
|
39
|
-
SubPageBlueprint.make({
|
|
40
|
-
name: "mcp-config",
|
|
41
|
-
params: {
|
|
42
|
-
path: "mcp-config",
|
|
43
|
-
title: "Configure MCP",
|
|
44
|
-
routeRef: mcpConfigRouteRef,
|
|
45
|
-
loader: () => import('./components/McpConfigPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(m.McpConfigPage, {}))
|
|
36
|
+
loader: () => import('./components/AiResourcesPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(m.AiResourcesPage, {}))
|
|
46
37
|
}
|
|
47
38
|
})
|
|
48
39
|
]
|
package/dist/plugin.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["import {\n createFrontendPlugin,\n PageBlueprint,\n SubPageBlueprint,\n ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport
|
|
1
|
+
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["import {\n createFrontendPlugin,\n PageBlueprint,\n SubPageBlueprint,\n ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { RiRobot3Fill } from '@remixicon/react';\nimport {\n devAiHubResourceApiRef,\n DevAiHubResourceClient,\n} from './api/DevAiHubResourceClient';\nimport { rootRouteRef } from './routes';\n\nexport const devAiHubPlugin = createFrontendPlugin({\n pluginId: 'dev-ai-hub',\n routes: {\n root: rootRouteRef,\n },\n extensions: [\n PageBlueprint.make({\n params: {\n path: '/dev-ai-hub',\n title: 'Dev AI Hub',\n icon: <RiRobot3Fill />,\n routeRef: rootRouteRef,\n },\n }),\n ApiBlueprint.make({\n name: 'resources',\n params: defineParams =>\n defineParams(\n createApiFactory({\n api: devAiHubResourceApiRef,\n deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },\n factory: ({ discoveryApi, fetchApi }) =>\n new DevAiHubResourceClient(discoveryApi, fetchApi),\n }),\n ),\n }),\n SubPageBlueprint.make({\n name: 'browse',\n params: {\n path: 'browse',\n title: 'Browse',\n loader: () =>\n import('./components/AiResourcesPage').then(m => (\n <m.AiResourcesPage />\n )),\n },\n }),\n ],\n});\n"],"names":[],"mappings":";;;;;;AAgBO,MAAM,iBAAiB,oBAAA,CAAqB;AAAA,EACjD,QAAA,EAAU,YAAA;AAAA,EACV,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA,GACR;AAAA,EACA,UAAA,EAAY;AAAA,IACV,cAAc,IAAA,CAAK;AAAA,MACjB,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,aAAA;AAAA,QACN,KAAA,EAAO,YAAA;AAAA,QACP,IAAA,sBAAO,YAAA,EAAA,EAAa,CAAA;AAAA,QACpB,QAAA,EAAU;AAAA;AACZ,KACD,CAAA;AAAA,IACD,aAAa,IAAA,CAAK;AAAA,MAChB,IAAA,EAAM,WAAA;AAAA,MACN,QAAQ,CAAA,YAAA,KACN,YAAA;AAAA,QACE,gBAAA,CAAiB;AAAA,UACf,GAAA,EAAK,sBAAA;AAAA,UACL,IAAA,EAAM,EAAE,YAAA,EAAc,eAAA,EAAiB,UAAU,WAAA,EAAY;AAAA,UAC7D,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,UAAS,KACjC,IAAI,sBAAA,CAAuB,YAAA,EAAc,QAAQ;AAAA,SACpD;AAAA;AACH,KACH,CAAA;AAAA,IACD,iBAAiB,IAAA,CAAK;AAAA,MACpB,IAAA,EAAM,QAAA;AAAA,MACN,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO,QAAA;AAAA,QACP,MAAA,EAAQ,MACN,OAAO,2CAA8B,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAC1C,GAAA,CAAC,CAAA,CAAE,eAAA,EAAF,EAAkB,CACpB;AAAA;AACL,KACD;AAAA;AAEL,CAAC;;;;"}
|
package/dist/routes.esm.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createRouteRef } from '@backstage/frontend-plugin-api';
|
|
2
2
|
|
|
3
3
|
const rootRouteRef = createRouteRef();
|
|
4
|
-
const mcpConfigRouteRef = createRouteRef();
|
|
5
4
|
|
|
6
|
-
export {
|
|
5
|
+
export { rootRouteRef };
|
|
7
6
|
//# sourceMappingURL=routes.esm.js.map
|
package/dist/routes.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["import { createRouteRef } from '@backstage/frontend-plugin-api';\n\nexport const rootRouteRef = createRouteRef();\
|
|
1
|
+
{"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["import { createRouteRef } from '@backstage/frontend-plugin-api';\n\nexport const rootRouteRef = createRouteRef();\n"],"names":[],"mappings":";;AAEO,MAAM,eAAe,cAAA;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nospt/plugin-dev-ai-hub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Frontend plugin for Dev AI Hub",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.esm.js",
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
]
|
|
39
39
|
},
|
|
40
40
|
"sideEffects": false,
|
|
41
|
+
"files": [
|
|
42
|
+
"dist"
|
|
43
|
+
],
|
|
41
44
|
"scripts": {
|
|
42
45
|
"start": "backstage-cli package start --config ../../app-config.dev.yaml",
|
|
43
46
|
"build": "backstage-cli package build",
|
|
@@ -52,13 +55,11 @@
|
|
|
52
55
|
"tsc": "tsc --noEmit"
|
|
53
56
|
},
|
|
54
57
|
"dependencies": {
|
|
55
|
-
"@backstage/core-components": "^0.18.
|
|
56
|
-
"@backstage/core-plugin-api": "^1.12.
|
|
57
|
-
"@backstage/frontend-plugin-api": "^0.
|
|
58
|
-
"@backstage/ui": "^0.
|
|
59
|
-
"@
|
|
60
|
-
"@mui/material": "^5.15.0",
|
|
61
|
-
"@nospt/plugin-dev-ai-hub-common": "^0.2.3",
|
|
58
|
+
"@backstage/core-components": "^0.18.10",
|
|
59
|
+
"@backstage/core-plugin-api": "^1.12.6",
|
|
60
|
+
"@backstage/frontend-plugin-api": "^0.17.0",
|
|
61
|
+
"@backstage/ui": "^0.15.0",
|
|
62
|
+
"@nospt/plugin-dev-ai-hub-common": "^0.3.0",
|
|
62
63
|
"@remixicon/react": "^4.6.0",
|
|
63
64
|
"react-markdown": "^9.0.0",
|
|
64
65
|
"react-syntax-highlighter": "^16.1.1",
|
|
@@ -66,14 +67,20 @@
|
|
|
66
67
|
"simple-icons": "^13.0.0"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
|
-
"@backstage/cli": "^0.36.
|
|
70
|
-
"@backstage/dev-utils": "^1.1.
|
|
70
|
+
"@backstage/cli": "^0.36.2",
|
|
71
|
+
"@backstage/dev-utils": "^1.1.23",
|
|
72
|
+
"@backstage/frontend-defaults": "^0.5.2",
|
|
73
|
+
"@backstage/plugin-app-react": "^0.2.3",
|
|
74
|
+
"@backstage/plugin-catalog": "^2.0.5",
|
|
75
|
+
"@backstage/plugin-catalog-react": "^3.0.0",
|
|
76
|
+
"@backstage/plugin-user-settings": "^0.9.3",
|
|
71
77
|
"@playwright/test": "^1.60.0",
|
|
72
78
|
"@testing-library/dom": "^10.0.0",
|
|
73
79
|
"@testing-library/jest-dom": "^6.0.0",
|
|
74
80
|
"@testing-library/react": "^16.3.1",
|
|
75
81
|
"@types/jest": "^30.0.0",
|
|
76
82
|
"@types/react": "^18.0.0",
|
|
83
|
+
"@types/react-dom": "^18.0.0",
|
|
77
84
|
"@types/react-syntax-highlighter": "^15.0.0",
|
|
78
85
|
"jest": "^30.2.0",
|
|
79
86
|
"jsdom": "^27.1.0",
|
package/.eslintrc.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
package/dev/index.tsx
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createDevApp } from '@backstage/dev-utils';
|
|
2
|
-
import { discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';
|
|
3
|
-
import { DevAiHubPage } from '../src/components/DevAiHubPage';
|
|
4
|
-
import { McpConfigPage } from '../src/components/McpConfigPage';
|
|
5
|
-
import { devAiHubApiRef, DevAiHubClient } from '../src/api/DevAiHubClient';
|
|
6
|
-
|
|
7
|
-
// Bypass Backstage guest auth without a running auth backend.
|
|
8
|
-
// The legacy token path generates the token locally — same keys the e2e
|
|
9
|
-
// base fixture injects via page.addInitScript().
|
|
10
|
-
if (typeof window !== 'undefined') {
|
|
11
|
-
localStorage.setItem('@backstage/core:SignInPage:provider', 'guest');
|
|
12
|
-
localStorage.setItem('enableLegacyGuestToken', 'true');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
createDevApp()
|
|
16
|
-
.registerApi({
|
|
17
|
-
api: devAiHubApiRef,
|
|
18
|
-
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
|
|
19
|
-
factory: ({ discoveryApi, fetchApi }) =>
|
|
20
|
-
new DevAiHubClient(discoveryApi, fetchApi),
|
|
21
|
-
})
|
|
22
|
-
.addPage({
|
|
23
|
-
element: <DevAiHubPage />,
|
|
24
|
-
title: 'Dev AI Hub',
|
|
25
|
-
path: '/dev-ai-hub',
|
|
26
|
-
})
|
|
27
|
-
.addPage({
|
|
28
|
-
element: <McpConfigPage />,
|
|
29
|
-
title: 'MCP Config',
|
|
30
|
-
path: '/mcp-config',
|
|
31
|
-
})
|
|
32
|
-
.render();
|
|
@@ -1,78 +0,0 @@
|
|
|
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
|
-
discoveryApi;
|
|
12
|
-
fetchApi;
|
|
13
|
-
async baseUrl() {
|
|
14
|
-
return this.discoveryApi.getBaseUrl("dev-ai-hub");
|
|
15
|
-
}
|
|
16
|
-
async fetch(path, init) {
|
|
17
|
-
const base = await this.baseUrl();
|
|
18
|
-
const response = await this.fetchApi.fetch(`${base}${path}`, init);
|
|
19
|
-
if (!response.ok) {
|
|
20
|
-
const text = await response.text();
|
|
21
|
-
throw new Error(
|
|
22
|
-
`Dev AI Hub API error ${response.status}: ${text}`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
return response.json();
|
|
26
|
-
}
|
|
27
|
-
async listAssets(filter) {
|
|
28
|
-
const params = new URLSearchParams();
|
|
29
|
-
if (filter?.type) params.set("type", filter.type);
|
|
30
|
-
if (filter?.tool) params.set("tool", filter.tool);
|
|
31
|
-
if (filter?.search) params.set("search", filter.search);
|
|
32
|
-
if (filter?.providerId) params.set("provider", filter.providerId);
|
|
33
|
-
if (filter?.tags?.length) params.set("tags", filter.tags.join(","));
|
|
34
|
-
if (filter?.page) params.set("page", String(filter.page));
|
|
35
|
-
if (filter?.pageSize) params.set("pageSize", String(filter.pageSize));
|
|
36
|
-
const qs = params.toString();
|
|
37
|
-
return this.fetch(`/assets${qs ? `?${qs}` : ""}`);
|
|
38
|
-
}
|
|
39
|
-
async getAsset(id) {
|
|
40
|
-
return this.fetch(`/assets/${encodeURIComponent(id)}`);
|
|
41
|
-
}
|
|
42
|
-
async getAssetRaw(id) {
|
|
43
|
-
const base = await this.baseUrl();
|
|
44
|
-
const response = await this.fetchApi.fetch(
|
|
45
|
-
`${base}/assets/${encodeURIComponent(id)}/raw`
|
|
46
|
-
);
|
|
47
|
-
if (!response.ok) throw new Error(`Failed to fetch raw asset: ${response.status}`);
|
|
48
|
-
return response.text();
|
|
49
|
-
}
|
|
50
|
-
async getDownloadUrl(id) {
|
|
51
|
-
const base = await this.baseUrl();
|
|
52
|
-
return `${base}/assets/${encodeURIComponent(id)}/download`;
|
|
53
|
-
}
|
|
54
|
-
async trackInstall(id) {
|
|
55
|
-
await this.fetch(`/assets/${encodeURIComponent(id)}/track-install`, {
|
|
56
|
-
method: "POST"
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
async listProviders() {
|
|
60
|
-
return this.fetch("/providers");
|
|
61
|
-
}
|
|
62
|
-
async getProviderStatus(id) {
|
|
63
|
-
return this.fetch(
|
|
64
|
-
`/providers/${encodeURIComponent(id)}/status`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
async triggerSync(id) {
|
|
68
|
-
await this.fetch(`/providers/${encodeURIComponent(id)}/sync`, {
|
|
69
|
-
method: "POST"
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
async getStats() {
|
|
73
|
-
return this.fetch("/stats");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export { DevAiHubClient, devAiHubApiRef };
|
|
78
|
-
//# sourceMappingURL=DevAiHubClient.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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 '@nospt/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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"}
|