itismyskillmarket 1.3.20 → 1.3.21
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/index.js +39 -1
- package/gui/app.js +96 -4
- package/gui/index.html +9 -1
- package/gui/style.css +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2164,7 +2164,8 @@ API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
|
|
|
2164
2164
|
id: adapter.id,
|
|
2165
2165
|
name: adapter.name,
|
|
2166
2166
|
available: !!isAvailable,
|
|
2167
|
-
installedCount: Array.isArray(installed) ? installed.length : 0
|
|
2167
|
+
installedCount: Array.isArray(installed) ? installed.length : 0,
|
|
2168
|
+
installedSkills: Array.isArray(installed) ? installed : []
|
|
2168
2169
|
};
|
|
2169
2170
|
})
|
|
2170
2171
|
);
|
|
@@ -2173,6 +2174,34 @@ API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
|
|
|
2173
2174
|
jsonResponse(res, 500, { error: String(err) });
|
|
2174
2175
|
}
|
|
2175
2176
|
};
|
|
2177
|
+
API_ROUTES.GET["/api/platform-info"] = async (_req, res, url) => {
|
|
2178
|
+
try {
|
|
2179
|
+
const platformId = url.searchParams.get("id") || "";
|
|
2180
|
+
if (!platformId) {
|
|
2181
|
+
jsonResponse(res, 400, { error: 'Missing "id" query parameter' });
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
const allAdapters = getAllAdapters();
|
|
2185
|
+
const adapter = allAdapters.find((a) => a.id === platformId);
|
|
2186
|
+
if (!adapter) {
|
|
2187
|
+
jsonResponse(res, 404, { error: `Platform "${platformId}" not found` });
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
const available = await detectPlatforms();
|
|
2191
|
+
const isAvailable = available.find((a) => a.id === adapter.id);
|
|
2192
|
+
const installed = await adapter.listInstalled();
|
|
2193
|
+
const installedSkills = Array.isArray(installed) ? installed : [];
|
|
2194
|
+
jsonResponse(res, 200, {
|
|
2195
|
+
id: adapter.id,
|
|
2196
|
+
name: adapter.name,
|
|
2197
|
+
available: !!isAvailable,
|
|
2198
|
+
installedCount: installedSkills.length,
|
|
2199
|
+
installedSkills
|
|
2200
|
+
});
|
|
2201
|
+
} catch (err) {
|
|
2202
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
2203
|
+
}
|
|
2204
|
+
};
|
|
2176
2205
|
API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
|
|
2177
2206
|
try {
|
|
2178
2207
|
const skillName = url.searchParams.get("skill") || "";
|
|
@@ -2213,6 +2242,15 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
|
|
|
2213
2242
|
jsonResponse(res, 500, { error: String(err) });
|
|
2214
2243
|
}
|
|
2215
2244
|
};
|
|
2245
|
+
API_ROUTES.GET["/api/version"] = async (_req, res, _url) => {
|
|
2246
|
+
try {
|
|
2247
|
+
const pkgPath = join4(__dirname2, "..", "package.json");
|
|
2248
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
2249
|
+
jsonResponse(res, 200, { version: pkg.version || "1.0.0" });
|
|
2250
|
+
} catch {
|
|
2251
|
+
jsonResponse(res, 200, { version: "1.0.0" });
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2216
2254
|
API_ROUTES.GET["/api/config"] = async (_req, res, _url) => {
|
|
2217
2255
|
jsonResponse(res, 200, {
|
|
2218
2256
|
npmScope: NPM_SCOPE,
|
package/gui/app.js
CHANGED
|
@@ -470,6 +470,23 @@ function applyI18nToStaticElements() {
|
|
|
470
470
|
if (backBtn) backBtn.innerHTML = `← ${t('nav.back')}`;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
+
// -----------------------------------------------------------------------------
|
|
474
|
+
// 版本号加载
|
|
475
|
+
// -----------------------------------------------------------------------------
|
|
476
|
+
|
|
477
|
+
async function loadVersion() {
|
|
478
|
+
try {
|
|
479
|
+
const response = await fetch('/api/version');
|
|
480
|
+
const data = await response.json();
|
|
481
|
+
const el = document.getElementById('gui-version');
|
|
482
|
+
if (el && data.version) {
|
|
483
|
+
el.textContent = `v${data.version}`;
|
|
484
|
+
}
|
|
485
|
+
} catch {
|
|
486
|
+
// 静默失败,保留 HTML 中的占位符
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
473
490
|
// 重新渲染当前视图
|
|
474
491
|
function reRenderCurrentView() {
|
|
475
492
|
// 更新语言选项
|
|
@@ -508,6 +525,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
508
525
|
initializeNavigation();
|
|
509
526
|
initializeControls();
|
|
510
527
|
initializeCollapsibleSections();
|
|
528
|
+
loadVersion();
|
|
511
529
|
loadSkills();
|
|
512
530
|
});
|
|
513
531
|
|
|
@@ -561,8 +579,8 @@ function switchView(view) {
|
|
|
561
579
|
targetView.classList.add('active');
|
|
562
580
|
}
|
|
563
581
|
|
|
564
|
-
// 加载对应数据 (skill-detail
|
|
565
|
-
if (view !== 'skill-detail') {
|
|
582
|
+
// 加载对应数据 (skill-detail / platform-detail 视图的数据由各自函数加载)
|
|
583
|
+
if (view !== 'skill-detail' && view !== 'platform-detail') {
|
|
566
584
|
switch(view) {
|
|
567
585
|
case 'skills':
|
|
568
586
|
loadSkills();
|
|
@@ -801,7 +819,7 @@ function renderPlatforms(platforms, container) {
|
|
|
801
819
|
}
|
|
802
820
|
|
|
803
821
|
container.innerHTML = platforms.map(platform => `
|
|
804
|
-
<div class="platform-card">
|
|
822
|
+
<div class="platform-card" onclick="showPlatformDetail('${platform.id}')" style="cursor: pointer;">
|
|
805
823
|
<div>
|
|
806
824
|
<h3>${platform.name}</h3>
|
|
807
825
|
<div class="status ${platform.available ? 'status-available' : 'status-unavailable'}">
|
|
@@ -809,12 +827,86 @@ function renderPlatforms(platforms, container) {
|
|
|
809
827
|
</div>
|
|
810
828
|
</div>
|
|
811
829
|
<div>
|
|
812
|
-
${platform.installedCount ? `<span>${t('status.skillsInstalled', { count: platform.installedCount })}</span>` : ''}
|
|
830
|
+
${platform.installedCount ? `<span>${t('status.skillsInstalled', { count: platform.installedCount })}</span>` : '<span style="color: var(--text-muted); font-size: 0.85rem;">0 installed</span>'}
|
|
813
831
|
</div>
|
|
814
832
|
</div>
|
|
815
833
|
`).join('');
|
|
816
834
|
}
|
|
817
835
|
|
|
836
|
+
// -----------------------------------------------------------------------------
|
|
837
|
+
// Platform 详情视图
|
|
838
|
+
// -----------------------------------------------------------------------------
|
|
839
|
+
|
|
840
|
+
async function showPlatformDetail(platformId) {
|
|
841
|
+
const content = document.getElementById('platform-detail-content');
|
|
842
|
+
content.innerHTML = `<div class="loading">${t('loading.generic')}</div>`;
|
|
843
|
+
|
|
844
|
+
state.previousView = state.currentView;
|
|
845
|
+
state.currentView = 'platform-detail';
|
|
846
|
+
|
|
847
|
+
document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
|
|
848
|
+
const targetView = document.getElementById('view-platform-detail');
|
|
849
|
+
if (targetView) targetView.classList.add('active');
|
|
850
|
+
|
|
851
|
+
try {
|
|
852
|
+
const response = await fetch(`/api/platform-info?id=${encodeURIComponent(platformId)}`);
|
|
853
|
+
const platform = await response.json();
|
|
854
|
+
|
|
855
|
+
if (platform.error) {
|
|
856
|
+
content.innerHTML = `<div class="loading">${t('error.generic')}: ${platform.error}</div>`;
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const skills = platform.installedSkills || [];
|
|
861
|
+
|
|
862
|
+
content.innerHTML = `
|
|
863
|
+
<div class="platform-detail">
|
|
864
|
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
|
865
|
+
<div>
|
|
866
|
+
<h2 style="color: var(--accent); font-size: 1.5rem; margin: 0;">${platform.name}</h2>
|
|
867
|
+
<span class="status ${platform.available ? 'status-available' : 'status-unavailable'}">
|
|
868
|
+
${platform.available ? t('status.available') : t('status.unavailable')}
|
|
869
|
+
</span>
|
|
870
|
+
<span style="color: var(--text-muted); font-size: 0.85rem; margin-left: 12px;">
|
|
871
|
+
${t('status.skillsInstalled', { count: platform.installedCount })}
|
|
872
|
+
</span>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
<div class="admin-skill-row" style="background: var(--bg-card); padding: 10px 16px; margin-bottom: 12px;">
|
|
876
|
+
<span style="color: var(--text-muted); font-size: 0.85rem;">Platform ID</span>
|
|
877
|
+
<span style="color: var(--text-secondary); font-size: 0.9rem; font-family: monospace;">${platform.id}</span>
|
|
878
|
+
</div>
|
|
879
|
+
<h3 style="color: var(--text-secondary); margin-bottom: 10px; font-size: 1rem;">
|
|
880
|
+
Installed Skills (${skills.length})
|
|
881
|
+
</h3>
|
|
882
|
+
${skills.length === 0 ? '<div class="loading" style="padding: 20px;">No skills installed on this platform.</div>' : `
|
|
883
|
+
<div style="display: flex; flex-direction: column; gap: 6px;">
|
|
884
|
+
${skills.map((skill, i) => `
|
|
885
|
+
<div class="admin-skill-row" style="cursor: pointer;" onclick="showSkillDetail('${skill.id}')">
|
|
886
|
+
<div class="admin-skill-info">
|
|
887
|
+
<h4>${skill.displayName || skill.id}</h4>
|
|
888
|
+
<div class="admin-skill-meta">${skill.id}@${skill.version || 'latest'}</div>
|
|
889
|
+
</div>
|
|
890
|
+
<button class="btn btn-secondary btn-sm" onclick="event.stopPropagation(); showSkillDetail('${skill.id}')">${t('btn.info')}</button>
|
|
891
|
+
</div>
|
|
892
|
+
`).join('')}
|
|
893
|
+
</div>
|
|
894
|
+
`}
|
|
895
|
+
</div>
|
|
896
|
+
`;
|
|
897
|
+
} catch (err) {
|
|
898
|
+
content.innerHTML = `<div class="loading">${t('error.generic')}: ${err.message}</div>`;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function goBackFromPlatformDetail() {
|
|
903
|
+
const target = state.previousView || 'platforms';
|
|
904
|
+
document.querySelectorAll('.nav-btn').forEach(b => {
|
|
905
|
+
b.classList.toggle('active', b.dataset.view === target);
|
|
906
|
+
});
|
|
907
|
+
switchView(target);
|
|
908
|
+
}
|
|
909
|
+
|
|
818
910
|
// -----------------------------------------------------------------------------
|
|
819
911
|
// Help 视图
|
|
820
912
|
// -----------------------------------------------------------------------------
|
package/gui/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<header class="topbar">
|
|
13
13
|
<div class="topbar-left">
|
|
14
14
|
<span class="topbar-logo">📦 SkillMarket</span>
|
|
15
|
-
<span class="topbar-version" id="gui-version"
|
|
15
|
+
<span class="topbar-version" id="gui-version">...</span>
|
|
16
16
|
</div>
|
|
17
17
|
<nav class="topbar-nav">
|
|
18
18
|
<button class="nav-btn active" data-view="skills">📋 Skills</button>
|
|
@@ -66,6 +66,14 @@
|
|
|
66
66
|
<div id="platforms-list" class="platforms-list"></div>
|
|
67
67
|
</div>
|
|
68
68
|
|
|
69
|
+
<!-- Platform 详情视图 -->
|
|
70
|
+
<div id="view-platform-detail" class="view">
|
|
71
|
+
<div class="view-header">
|
|
72
|
+
<button class="btn btn-secondary" onclick="goBackFromPlatformDetail()">← Back to Platforms</button>
|
|
73
|
+
</div>
|
|
74
|
+
<div id="platform-detail-content"></div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
69
77
|
<!-- Help 视图 -->
|
|
70
78
|
<div id="view-help" class="view">
|
|
71
79
|
<div class="view-header">
|
package/gui/style.css
CHANGED
|
@@ -40,6 +40,13 @@ body {
|
|
|
40
40
|
overflow: hidden;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
#app {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
flex: 1;
|
|
47
|
+
min-height: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
/* -----------------------------------------------------------------------------
|
|
44
51
|
顶部导航栏
|
|
45
52
|
----------------------------------------------------------------------------- */
|