@nospt/plugin-dev-ai-hub 0.2.4 → 0.3.1
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 +112 -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 +238 -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.aurora.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/StatTiles.aurora.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/StatTiles.console.module.css.esm.js +8 -0
- package/dist/components/AiResourcesPage/StatTiles.console.module.css.esm.js.map +1 -0
- package/dist/components/AiResourcesPage/StatTiles.esm.js +82 -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 +34 -0
- package/dist/components/AiResourcesPage/typeMeta.esm.js.map +1 -0
- package/dist/components/ToolIcon/ToolIcon.esm.js +28 -10
- 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 +15 -24
- 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
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import styleInject from '../../node_modules_dist/style-inject/dist/style-inject.es.esm.js';
|
|
2
|
+
|
|
3
|
+
var css_248z = "@layer components {\n /*\n * The type filter: a row of solid brand-coloured blocks, each carrying a\n * share bar along its bottom edge — the type's proportion of the catalog.\n *\n * The bar is the data-ink. It answers \"what is this catalog made of?\" in the\n * space the tile already occupied, and it breaks the uniformity of six\n * identical tiles, which is what makes attention drop off across a repeated\n * row (eye-tracking: users barely register the last two of five).\n *\n * A full-height proportional fill was built first — the saturated part being\n * the share, the remainder the same hue dimmed — and rejected on sight: the\n * dimmed remainder is the muddy tone this palette has repeatedly failed on,\n * and it covered most of every tile. The bar keeps the encoding and leaves\n * the colour alone.\n *\n * The fill is `--devaihub-tile-*` (the brand hex, identical in both themes),\n * NOT `--devaihub-type-*`: those are darkened in light mode to read against\n * a card surface, and filling with them turns the row olive. See the token\n * block in AiResourcesPage.module.css.\n */\n .StatTiles_grid__0e03a75ccd {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));\n gap: var(--bui-space-3);\n margin-bottom: var(--bui-space-5);\n }\n\n .StatTiles_tile__0e03a75ccd {\n position: relative;\n /* The variant owns its foreground: the components reference these tokens\n inline, which is what lets one DOM serve three treatments. */\n --devaihub-tile-fg: #ffffff;\n --devaihub-tile-fg-muted: rgba(255, 255, 255, 0.92);\n background: var(--tile-fill);\n border-radius: var(--bui-radius-3);\n padding: var(--bui-space-4);\n display: flex;\n align-items: center;\n gap: var(--bui-space-3);\n cursor: pointer;\n /* A lit top edge and a shadow tinted with the tile's own hue, so the row\n sits on the page rather than being pasted onto it. */\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25),\n 0 1px 2px rgba(0, 0, 0, 0.12),\n 0 8px 18px -10px color-mix(in srgb, var(--tile-fill) 60%, transparent);\n /* Room for the share bar under the label. */\n padding-bottom: var(--bui-space-5);\n transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1),\n box-shadow 160ms ease;\n }\n\n .StatTiles_tile__0e03a75ccd:hover {\n transform: translateY(-2px);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.32),\n 0 2px 4px rgba(0, 0, 0, 0.14),\n 0 14px 26px -12px color-mix(in srgb, var(--tile-fill) 70%, transparent);\n }\n\n .StatTiles_tile__0e03a75ccd:focus-visible {\n outline: 2px solid var(--bui-fg-primary);\n outline-offset: 3px;\n }\n\n /* The ring sits OUTSIDE, on the page background, and takes the theme's\n foreground. A tint or an inset white ring cannot read on a solid fill —\n white is invisible on the yellow and turquoise tiles, which is exactly\n where selection has to be legible. */\n .StatTiles_tileActive__0e03a75ccd {\n transform: translateY(-2px);\n outline: 2px solid var(--bui-fg-primary);\n outline-offset: 3px;\n }\n\n /* Share bar: a track across the full width with the fill sized to this\n type's proportion of the catalog. Drawn in the tile's own foreground so it\n works on every hue without a second colour decision. */\n .StatTiles_shareTrack__0e03a75ccd {\n position: absolute;\n left: var(--bui-space-4);\n right: var(--bui-space-4);\n bottom: var(--bui-space-3);\n height: 3px;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.28);\n overflow: hidden;\n }\n\n .StatTiles_shareFill__0e03a75ccd {\n display: block;\n height: 100%;\n width: var(--tile-share);\n border-radius: inherit;\n background: var(--devaihub-tile-fg);\n transition: width 320ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n .StatTiles_tileIconBox__0e03a75ccd {\n background: rgba(255, 255, 255, 0.22);\n color: var(--devaihub-tile-fg);\n border-radius: var(--bui-radius-2);\n padding: var(--bui-space-2);\n display: flex;\n flex-shrink: 0;\n }\n\n .StatTiles_tileText__0e03a75ccd {\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n\n /* Colour and size are set inline on the components too: BUI's Text carries\n its own, and which wins depends on the order BUI's styles land in the host\n app relative to this plugin's. These rules cover hosts where the plugin\n lands last. */\n .StatTiles_tile__0e03a75ccd .StatTiles_tileValue__0e03a75ccd {\n color: var(--devaihub-tile-fg);\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.1;\n letter-spacing: -0.02em;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);\n display: block;\n }\n\n .StatTiles_tile__0e03a75ccd .StatTiles_tileLabel__0e03a75ccd {\n color: var(--devaihub-tile-fg);\n font-size: 0.75rem;\n font-weight: 600;\n letter-spacing: 0.07em;\n text-transform: uppercase;\n line-height: 1.2;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);\n display: block;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .StatTiles_tile__0e03a75ccd {\n transition: none;\n }\n\n .StatTiles_tile__0e03a75ccd:hover,\n .StatTiles_tileActive__0e03a75ccd {\n transform: none;\n }\n\n .StatTiles_shareFill__0e03a75ccd {\n transition: none;\n }\n }\n}\n";
|
|
4
|
+
var solidStyles = {"grid":"StatTiles_grid__0e03a75ccd","tile":"StatTiles_tile__0e03a75ccd","tileActive":"StatTiles_tileActive__0e03a75ccd StatTiles_tile__0e03a75ccd","shareTrack":"StatTiles_shareTrack__0e03a75ccd","shareFill":"StatTiles_shareFill__0e03a75ccd","tileIconBox":"StatTiles_tileIconBox__0e03a75ccd","tileText":"StatTiles_tileText__0e03a75ccd","tileValue":"StatTiles_tileValue__0e03a75ccd","tileLabel":"StatTiles_tileLabel__0e03a75ccd"};
|
|
5
|
+
styleInject(css_248z);
|
|
6
|
+
|
|
7
|
+
export { solidStyles as default };
|
|
8
|
+
//# sourceMappingURL=StatTiles.module.css.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatTiles.module.css.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RiStore2Line, RiPuzzleLine, RiPlugLine, RiFlashlightLine, RiRobot2Line, RiToolsLine } from '@remixicon/react';
|
|
2
|
+
import { RESOURCE_TYPE_REGISTRY } from '@nospt/plugin-dev-ai-hub-common';
|
|
3
|
+
|
|
4
|
+
const ICONS = {
|
|
5
|
+
tools: RiToolsLine,
|
|
6
|
+
robot: RiRobot2Line,
|
|
7
|
+
flash: RiFlashlightLine,
|
|
8
|
+
plug: RiPlugLine,
|
|
9
|
+
puzzle: RiPuzzleLine,
|
|
10
|
+
store: RiStore2Line
|
|
11
|
+
};
|
|
12
|
+
function getTypeMeta(type) {
|
|
13
|
+
const info = RESOURCE_TYPE_REGISTRY[type];
|
|
14
|
+
return {
|
|
15
|
+
...info,
|
|
16
|
+
Icon: ICONS[info.icon],
|
|
17
|
+
color: `var(--devaihub-type-${info.colorRole})`,
|
|
18
|
+
colorBg: `var(--devaihub-type-${info.colorRole}-bg)`,
|
|
19
|
+
tileFill: `var(--devaihub-tile-${info.colorRole})`
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const FRAMEWORK_LABELS = {
|
|
23
|
+
"claude-code": "Claude Code",
|
|
24
|
+
"github-copilot": "GitHub Copilot",
|
|
25
|
+
"google-gemini": "Google Gemini",
|
|
26
|
+
cursor: "Cursor",
|
|
27
|
+
all: "All tools"
|
|
28
|
+
};
|
|
29
|
+
function frameworkLabel(token) {
|
|
30
|
+
return FRAMEWORK_LABELS[token] ?? token;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { frameworkLabel, getTypeMeta };
|
|
34
|
+
//# sourceMappingURL=typeMeta.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeMeta.esm.js","sources":["../../../src/components/AiResourcesPage/typeMeta.tsx"],"sourcesContent":["import type { ElementType } from 'react';\nimport {\n RiFlashlightLine,\n RiPlugLine,\n RiPuzzleLine,\n RiRobot2Line,\n RiStore2Line,\n RiToolsLine,\n} from '@remixicon/react';\nimport {\n RESOURCE_TYPE_REGISTRY,\n type ResourceType,\n type ResourceTypeIcon,\n type ResourceTypeInfo,\n} from '@nospt/plugin-dev-ai-hub-common';\n\n/** Maps the registry's React-free icon identifiers to components. */\nconst ICONS: Record<ResourceTypeIcon, ElementType> = {\n tools: RiToolsLine,\n robot: RiRobot2Line,\n flash: RiFlashlightLine,\n plug: RiPlugLine,\n puzzle: RiPuzzleLine,\n store: RiStore2Line,\n};\n\nexport interface TypeMeta extends ResourceTypeInfo {\n Icon: ElementType;\n /** The plugin-owned colour tokens for this role (ADR-0008). */\n color: string;\n colorBg: string;\n /**\n * The stat tile's solid fill: the brand hex as published, which is NOT\n * `color` — that one is darkened in light mode to read against a card.\n */\n tileFill: string;\n}\n\nexport function getTypeMeta(type: ResourceType): TypeMeta {\n const info = RESOURCE_TYPE_REGISTRY[type];\n return {\n ...info,\n Icon: ICONS[info.icon],\n color: `var(--devaihub-type-${info.colorRole})`,\n colorBg: `var(--devaihub-type-${info.colorRole}-bg)`,\n tileFill: `var(--devaihub-tile-${info.colorRole})`,\n };\n}\n\n/** Display labels for the known framework tokens; unknown pass through. */\nconst FRAMEWORK_LABELS: Record<string, string> = {\n 'claude-code': 'Claude Code',\n 'github-copilot': 'GitHub Copilot',\n 'google-gemini': 'Google Gemini',\n cursor: 'Cursor',\n all: 'All tools',\n};\n\nexport function frameworkLabel(token: string): string {\n return FRAMEWORK_LABELS[token] ?? token;\n}\n"],"names":[],"mappings":";;;AAiBA,MAAM,KAAA,GAA+C;AAAA,EACnD,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,YAAA;AAAA,EACP,KAAA,EAAO,gBAAA;AAAA,EACP,IAAA,EAAM,UAAA;AAAA,EACN,MAAA,EAAQ,YAAA;AAAA,EACR,KAAA,EAAO;AACT,CAAA;AAcO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,MAAM,IAAA,GAAO,uBAAuB,IAAI,CAAA;AACxC,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,IACrB,KAAA,EAAO,CAAA,oBAAA,EAAuB,IAAA,CAAK,SAAS,CAAA,CAAA,CAAA;AAAA,IAC5C,OAAA,EAAS,CAAA,oBAAA,EAAuB,IAAA,CAAK,SAAS,CAAA,IAAA,CAAA;AAAA,IAC9C,QAAA,EAAU,CAAA,oBAAA,EAAuB,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,GACjD;AACF;AAGA,MAAM,gBAAA,GAA2C;AAAA,EAC/C,aAAA,EAAe,aAAA;AAAA,EACf,gBAAA,EAAkB,gBAAA;AAAA,EAClB,eAAA,EAAiB,eAAA;AAAA,EACjB,MAAA,EAAQ,QAAA;AAAA,EACR,GAAA,EAAK;AACP,CAAA;AAEO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,OAAO,gBAAA,CAAiB,KAAK,CAAA,IAAK,KAAA;AACpC;;;;"}
|
|
@@ -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,
|
|
@@ -15,23 +22,34 @@ function ToolIcon({ tool, branded = true, className, style, size = 20 }) {
|
|
|
15
22
|
size,
|
|
16
23
|
className,
|
|
17
24
|
style: { color: "var(--bui-fg-secondary)", ...style },
|
|
18
|
-
"aria-label": "Universal"
|
|
25
|
+
"aria-label": "Universal",
|
|
26
|
+
role: "img"
|
|
19
27
|
}
|
|
20
28
|
);
|
|
21
29
|
}
|
|
22
30
|
if (tool === "cursor") {
|
|
23
31
|
return /* @__PURE__ */ jsx(
|
|
24
|
-
|
|
32
|
+
"svg",
|
|
25
33
|
{
|
|
26
|
-
|
|
34
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
35
|
+
viewBox: "0 0 24 24",
|
|
36
|
+
width: size,
|
|
37
|
+
height: size,
|
|
38
|
+
fill: "currentColor",
|
|
27
39
|
className,
|
|
28
|
-
style: {
|
|
29
|
-
|
|
40
|
+
style: {
|
|
41
|
+
color: branded ? "var(--bui-fg-primary)" : "inherit",
|
|
42
|
+
...style
|
|
43
|
+
},
|
|
44
|
+
"aria-label": "Cursor",
|
|
45
|
+
role: "img",
|
|
46
|
+
children: /* @__PURE__ */ jsx("path", { d: CURSOR_PATH })
|
|
30
47
|
}
|
|
31
48
|
);
|
|
32
49
|
}
|
|
33
50
|
const cfg = TOOL_ICON[tool];
|
|
34
51
|
if (!cfg) return null;
|
|
52
|
+
const brandedColor = cfg.monochrome ? "var(--bui-fg-primary)" : `#${cfg.hex}`;
|
|
35
53
|
return /* @__PURE__ */ jsx(
|
|
36
54
|
"svg",
|
|
37
55
|
{
|
|
@@ -41,7 +59,7 @@ function ToolIcon({ tool, branded = true, className, style, size = 20 }) {
|
|
|
41
59
|
height: size,
|
|
42
60
|
fill: "currentColor",
|
|
43
61
|
className,
|
|
44
|
-
style: { color: branded ?
|
|
62
|
+
style: { color: branded ? brandedColor : "inherit", ...style },
|
|
45
63
|
"aria-label": cfg.label,
|
|
46
64
|
role: "img",
|
|
47
65
|
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 // Without an explicit role the label is not exposed as an image name,\n // which the other two branches already set. It matters wherever the\n // icon stands alone (resource cards), where it is the only thing\n // naming the tool.\n role=\"img\"\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,WAAA;AAAA,QAKX,IAAA,EAAK;AAAA;AAAA,KACP;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,25 +1,15 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { createFrontendPlugin, ApiBlueprint, createApiFactory, fetchApiRef, discoveryApiRef,
|
|
2
|
+
import { createFrontendPlugin, PageBlueprint, ApiBlueprint, createApiFactory, fetchApiRef, discoveryApiRef, SubPageBlueprint } from '@backstage/frontend-plugin-api';
|
|
3
3
|
import { RiRobot3Fill } from '@remixicon/react';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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",
|
|
@@ -28,21 +18,22 @@ const devAiHubPlugin = createFrontendPlugin({
|
|
|
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 { RiRobot3Fill } from '@remixicon/react';\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.1",
|
|
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.4",
|
|
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.1",
|
|
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
|