dsh-cloudq 0.1.0 → 0.1.2
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/README.md +12 -1
- package/lib/client.js +430 -219
- package/lib/index.js +33 -66
- package/package.json +1 -1
- package/skills/cloudq/scripts/login.py +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 CloudQ 集成插件。插件为 Web Profile 提供 CloudQ 模式,内置 `cloudq` Skill,并提供 CloudQ 用量、架构视图、本地凭证配置和插件管理能力。
|
|
4
4
|
|
|
5
|
+
## 截图
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
5
11
|
## 环境要求
|
|
6
12
|
|
|
7
13
|
- Node.js `>=22.19.0`
|
|
@@ -35,7 +41,7 @@ dsh plugin --profile web remove dsh-cloudq
|
|
|
35
41
|
|
|
36
42
|
## 凭证配置
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
设置卡片支持配置腾讯云 `SecretId` 和 `SecretKey` 凭证。
|
|
39
45
|
|
|
40
46
|
- 凭证保存在本机 `~/.tencent-cloudq/credential.json`,文件权限仅允许当前用户访问。
|
|
41
47
|
- 敏感凭证通过标准输入传递给 Python 辅助脚本,不会放入命令行参数。
|
|
@@ -84,6 +90,11 @@ cordis.patch.yml DSH Bundle 配置层
|
|
|
84
90
|
|
|
85
91
|
源码在 [TencentCloud/cloudq-for-dsh](https://github.com/TencentCloud/cloudq-for-dsh) 完成评审和版本管理。只有仓库检查与安装包冒烟测试全部通过后,才可将 npm 版本发布到官方 Registry。
|
|
86
92
|
|
|
93
|
+
## 更多文档
|
|
94
|
+
|
|
95
|
+
- 更新日志:[`CHANGELOG.md`](CHANGELOG.md)
|
|
96
|
+
- 开发与维护指南:[`DEVELOPMENT.md`](DEVELOPMENT.md)
|
|
97
|
+
|
|
87
98
|
## 许可证
|
|
88
99
|
|
|
89
100
|
本项目采用 MIT 许可证,详情请参阅 [`LICENSE`](LICENSE)。
|
package/lib/client.js
CHANGED
|
@@ -100,6 +100,11 @@ window.__ModuleLoader__.load({
|
|
|
100
100
|
background: var(--dsw-alias-bg-layer-3, #fff);
|
|
101
101
|
color: var(--dsw-alias-label-primary, #17191c);
|
|
102
102
|
}
|
|
103
|
+
.dsh-cloudq-settings-card *,
|
|
104
|
+
.dsh-cloudq-settings-card *::before,
|
|
105
|
+
.dsh-cloudq-settings-card *::after {
|
|
106
|
+
box-sizing: border-box;
|
|
107
|
+
}
|
|
103
108
|
.dsh-cloudq-settings-card__summary {
|
|
104
109
|
padding: 15px 16px;
|
|
105
110
|
}
|
|
@@ -215,10 +220,11 @@ window.__ModuleLoader__.load({
|
|
|
215
220
|
flex-wrap: wrap;
|
|
216
221
|
}
|
|
217
222
|
.dsh-cloudq-settings-card__actions--stacked {
|
|
218
|
-
flex-direction: column
|
|
223
|
+
flex-direction: column;
|
|
224
|
+
align-items: stretch;
|
|
219
225
|
}
|
|
220
226
|
.dsh-cloudq-settings-card__actions--stacked button {
|
|
221
|
-
|
|
227
|
+
align-self: flex-end;
|
|
222
228
|
}
|
|
223
229
|
.dsh-cloudq-settings-card__btn {
|
|
224
230
|
display: inline-flex;
|
|
@@ -426,10 +432,6 @@ window.__ModuleLoader__.load({
|
|
|
426
432
|
font-size: 11px;
|
|
427
433
|
font-weight: 500;
|
|
428
434
|
}
|
|
429
|
-
.dsh-cloudq-pm__row-tag--self {
|
|
430
|
-
background: var(--dsw-alias-state-business-primary, #315efb);
|
|
431
|
-
color: #fff;
|
|
432
|
-
}
|
|
433
435
|
.dsh-cloudq-pm__row-tag--off {
|
|
434
436
|
background: var(--dsw-alias-state-danger, #d54941);
|
|
435
437
|
color: #fff;
|
|
@@ -1137,12 +1139,145 @@ body.dsh-cloudq-mode-active [class*=composerHero] [class*=root][class*=hero] {
|
|
|
1137
1139
|
margin-bottom: 16px;
|
|
1138
1140
|
}
|
|
1139
1141
|
.dsh-cloudq-usage__card {
|
|
1140
|
-
flex: 1;
|
|
1142
|
+
flex: 0 1 auto;
|
|
1143
|
+
min-width: 240px;
|
|
1141
1144
|
padding: 14px 16px;
|
|
1142
1145
|
border: 1px solid var(--dsw-alias-border-l2, #e1e4e8);
|
|
1143
1146
|
border-radius: 10px;
|
|
1144
1147
|
background: var(--dsw-alias-bg-sub, #f7f8fa);
|
|
1145
1148
|
}
|
|
1149
|
+
.dsh-cloudq-usage__card-value-row {
|
|
1150
|
+
display: flex;
|
|
1151
|
+
align-items: baseline;
|
|
1152
|
+
gap: 6px;
|
|
1153
|
+
flex-wrap: wrap;
|
|
1154
|
+
}
|
|
1155
|
+
.dsh-cloudq-usage__card-unit {
|
|
1156
|
+
font-size: 13px;
|
|
1157
|
+
color: var(--dsw-alias-label-secondary, #626a76);
|
|
1158
|
+
}
|
|
1159
|
+
.dsh-cloudq-usage__free-badge {
|
|
1160
|
+
position: relative;
|
|
1161
|
+
display: inline-flex;
|
|
1162
|
+
align-items: center;
|
|
1163
|
+
gap: 4px;
|
|
1164
|
+
padding: 1px 8px;
|
|
1165
|
+
border-radius: 999px;
|
|
1166
|
+
background: var(--dsw-alias-state-business-primary-bg, #e8efff);
|
|
1167
|
+
color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1168
|
+
font-size: 12px;
|
|
1169
|
+
cursor: help;
|
|
1170
|
+
}
|
|
1171
|
+
.dsh-cloudq-usage__free-badge .dsh-cloudq-tooltip {
|
|
1172
|
+
opacity: 0;
|
|
1173
|
+
visibility: hidden;
|
|
1174
|
+
transition: opacity .12s ease;
|
|
1175
|
+
}
|
|
1176
|
+
.dsh-cloudq-usage__free-badge:hover .dsh-cloudq-tooltip,
|
|
1177
|
+
.dsh-cloudq-usage__free-badge:focus-visible .dsh-cloudq-tooltip {
|
|
1178
|
+
opacity: 1;
|
|
1179
|
+
visibility: visible;
|
|
1180
|
+
}
|
|
1181
|
+
.dsh-cloudq-usage__range {
|
|
1182
|
+
display: flex;
|
|
1183
|
+
align-items: center;
|
|
1184
|
+
gap: 8px;
|
|
1185
|
+
flex-wrap: wrap;
|
|
1186
|
+
margin-bottom: 12px;
|
|
1187
|
+
}
|
|
1188
|
+
.dsh-cloudq-usage__range-picker {
|
|
1189
|
+
position: relative;
|
|
1190
|
+
}
|
|
1191
|
+
.dsh-cloudq-usage__range-btn {
|
|
1192
|
+
display: inline-flex;
|
|
1193
|
+
align-items: center;
|
|
1194
|
+
gap: 8px;
|
|
1195
|
+
height: 28px;
|
|
1196
|
+
padding: 0 10px;
|
|
1197
|
+
border: 1px solid var(--dsw-alias-interactive-border, #cdd3da);
|
|
1198
|
+
border-radius: 6px;
|
|
1199
|
+
background: var(--dsw-alias-bg-card, #fff);
|
|
1200
|
+
color: var(--dsw-alias-label-primary, #1d2129);
|
|
1201
|
+
font-size: 12px;
|
|
1202
|
+
cursor: pointer;
|
|
1203
|
+
transition: border-color .15s ease, box-shadow .15s ease;
|
|
1204
|
+
}
|
|
1205
|
+
.dsh-cloudq-usage__range-btn:hover {
|
|
1206
|
+
border-color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1207
|
+
}
|
|
1208
|
+
.dsh-cloudq-usage__range-picker.is-open .dsh-cloudq-usage__range-btn {
|
|
1209
|
+
border-color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1210
|
+
box-shadow: 0 0 0 2px rgba(49, 94, 251, .12);
|
|
1211
|
+
}
|
|
1212
|
+
.dsh-cloudq-usage__range-btn-chevron {
|
|
1213
|
+
font-size: 10px;
|
|
1214
|
+
color: var(--dsw-alias-label-tertiary, #9aa1ab);
|
|
1215
|
+
transition: transform .15s ease;
|
|
1216
|
+
}
|
|
1217
|
+
.dsh-cloudq-usage__range-picker.is-open .dsh-cloudq-usage__range-btn-chevron {
|
|
1218
|
+
transform: rotate(180deg);
|
|
1219
|
+
}
|
|
1220
|
+
.dsh-cloudq-usage__range-menu {
|
|
1221
|
+
position: absolute;
|
|
1222
|
+
z-index: 1400;
|
|
1223
|
+
top: calc(100% + 6px);
|
|
1224
|
+
left: 0;
|
|
1225
|
+
min-width: 136px;
|
|
1226
|
+
padding: 4px;
|
|
1227
|
+
border: 1px solid var(--dsw-alias-border-l2, #e1e4e8);
|
|
1228
|
+
border-radius: 8px;
|
|
1229
|
+
background: var(--dsw-alias-bg-card, #fff);
|
|
1230
|
+
box-shadow: 0 8px 24px rgba(29, 33, 41, .12);
|
|
1231
|
+
}
|
|
1232
|
+
.dsh-cloudq-usage__range-option {
|
|
1233
|
+
display: flex;
|
|
1234
|
+
align-items: center;
|
|
1235
|
+
gap: 4px;
|
|
1236
|
+
width: 100%;
|
|
1237
|
+
padding: 6px 8px;
|
|
1238
|
+
border: 0;
|
|
1239
|
+
border-radius: 5px;
|
|
1240
|
+
background: transparent;
|
|
1241
|
+
color: var(--dsw-alias-label-primary, #1d2129);
|
|
1242
|
+
font-size: 12px;
|
|
1243
|
+
text-align: left;
|
|
1244
|
+
cursor: pointer;
|
|
1245
|
+
}
|
|
1246
|
+
.dsh-cloudq-usage__range-option:hover {
|
|
1247
|
+
background: var(--dsw-alias-bg-sub, #f2f4f8);
|
|
1248
|
+
}
|
|
1249
|
+
.dsh-cloudq-usage__range-option.is-active {
|
|
1250
|
+
color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1251
|
+
font-weight: 500;
|
|
1252
|
+
}
|
|
1253
|
+
.dsh-cloudq-usage__range-option-check {
|
|
1254
|
+
width: 14px;
|
|
1255
|
+
flex: none;
|
|
1256
|
+
color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1257
|
+
visibility: hidden;
|
|
1258
|
+
}
|
|
1259
|
+
.dsh-cloudq-usage__range-option.is-active .dsh-cloudq-usage__range-option-check {
|
|
1260
|
+
visibility: visible;
|
|
1261
|
+
}
|
|
1262
|
+
.dsh-cloudq-usage__date {
|
|
1263
|
+
height: 28px;
|
|
1264
|
+
padding: 0 8px;
|
|
1265
|
+
border: 1px solid var(--dsw-alias-interactive-border, #cdd3da);
|
|
1266
|
+
border-radius: 6px;
|
|
1267
|
+
background: var(--dsw-alias-bg-card, #fff);
|
|
1268
|
+
color: var(--dsw-alias-label-primary, #1d2129);
|
|
1269
|
+
font-size: 12px;
|
|
1270
|
+
outline: none;
|
|
1271
|
+
transition: border-color .15s ease, box-shadow .15s ease;
|
|
1272
|
+
}
|
|
1273
|
+
.dsh-cloudq-usage__date:focus {
|
|
1274
|
+
border-color: var(--dsw-alias-state-business-primary, #315efb);
|
|
1275
|
+
box-shadow: 0 0 0 2px rgba(49, 94, 251, .12);
|
|
1276
|
+
}
|
|
1277
|
+
.dsh-cloudq-usage__range-error {
|
|
1278
|
+
font-size: 12px;
|
|
1279
|
+
color: var(--dsw-alias-state-danger, #d54941);
|
|
1280
|
+
}
|
|
1146
1281
|
.dsh-cloudq-usage__card-label {
|
|
1147
1282
|
font-size: 12px;
|
|
1148
1283
|
color: var(--dsw-alias-label-tertiary, #9aa1ab);
|
|
@@ -1745,22 +1880,58 @@ display: none;
|
|
|
1745
1880
|
const API_ARCH_DIRECTORIES = "/api/dsh-cloudq/architecture/directories";
|
|
1746
1881
|
const API_ARCH_LIST = "/api/dsh-cloudq/architecture/list";
|
|
1747
1882
|
const CLOUDQ_ARCH_FOLDER_KEY = "dsh-cloudq.architecture-folder-id";
|
|
1748
|
-
|
|
1883
|
+
const USAGE_RANGE_PRESETS = [
|
|
1884
|
+
{
|
|
1885
|
+
id: "3d",
|
|
1886
|
+
label: "最近 3 天",
|
|
1887
|
+
days: 3
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
id: "7d",
|
|
1891
|
+
label: "最近 1 周",
|
|
1892
|
+
days: 7
|
|
1893
|
+
},
|
|
1894
|
+
{
|
|
1895
|
+
id: "30d",
|
|
1896
|
+
label: "最近 1 月",
|
|
1897
|
+
days: 30
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
id: "custom",
|
|
1901
|
+
label: "自定义",
|
|
1902
|
+
days: 0
|
|
1903
|
+
}
|
|
1904
|
+
];
|
|
1905
|
+
let usagePreset = "7d";
|
|
1906
|
+
let usageCustomStart = "";
|
|
1907
|
+
let usageCustomEnd = "";
|
|
1908
|
+
function formatUsageTimestamp(d) {
|
|
1909
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
1910
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
1911
|
+
}
|
|
1912
|
+
/** Resolve the current range to API timestamps; null when custom dates are incomplete. */
|
|
1913
|
+
function usageRangeTimestamps() {
|
|
1914
|
+
if (usagePreset === "custom") {
|
|
1915
|
+
if (!usageCustomStart || !usageCustomEnd) return null;
|
|
1916
|
+
return {
|
|
1917
|
+
start: `${usageCustomStart} 00:00:00`,
|
|
1918
|
+
end: `${usageCustomEnd} 23:59:59`
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
const preset = USAGE_RANGE_PRESETS.find((item) => item.id === usagePreset) ?? USAGE_RANGE_PRESETS[1];
|
|
1749
1922
|
const end = /* @__PURE__ */ new Date();
|
|
1750
|
-
const start = /* @__PURE__ */ new Date(end.getTime() - 6048e5);
|
|
1751
|
-
const fmt = (d) => {
|
|
1752
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
1753
|
-
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
1754
|
-
};
|
|
1755
1923
|
return {
|
|
1756
|
-
start:
|
|
1757
|
-
end:
|
|
1924
|
+
start: formatUsageTimestamp(/* @__PURE__ */ new Date(end.getTime() - preset.days * 24 * 60 * 60 * 1e3)),
|
|
1925
|
+
end: formatUsageTimestamp(end)
|
|
1758
1926
|
};
|
|
1759
1927
|
}
|
|
1760
1928
|
function formatCredits(value) {
|
|
1761
1929
|
const num = typeof value === "number" ? value : Number(value);
|
|
1762
1930
|
if (!Number.isFinite(num)) return "—";
|
|
1763
|
-
return num.
|
|
1931
|
+
return num.toLocaleString("en-US", {
|
|
1932
|
+
minimumFractionDigits: 2,
|
|
1933
|
+
maximumFractionDigits: 2
|
|
1934
|
+
});
|
|
1764
1935
|
}
|
|
1765
1936
|
function formatDateTime(raw) {
|
|
1766
1937
|
if (!raw) return "—";
|
|
@@ -1822,93 +1993,221 @@ display: none;
|
|
|
1822
1993
|
let architecturePickerCleanup = null;
|
|
1823
1994
|
function renderUsageView() {
|
|
1824
1995
|
panelBody.textContent = "";
|
|
1825
|
-
const
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1996
|
+
const overviewWrap = document.createElement("div");
|
|
1997
|
+
overviewWrap.className = "dsh-cloudq-usage__overview";
|
|
1998
|
+
const card = document.createElement("div");
|
|
1999
|
+
card.className = "dsh-cloudq-usage__card";
|
|
2000
|
+
const label = document.createElement("div");
|
|
2001
|
+
label.className = "dsh-cloudq-usage__card-label";
|
|
2002
|
+
label.textContent = "累计消耗 Credit";
|
|
2003
|
+
const valueRow = document.createElement("div");
|
|
2004
|
+
valueRow.className = "dsh-cloudq-usage__card-value-row";
|
|
2005
|
+
const value = document.createElement("span");
|
|
2006
|
+
value.className = "dsh-cloudq-usage__card-value";
|
|
2007
|
+
value.textContent = "…";
|
|
2008
|
+
const unit = document.createElement("span");
|
|
2009
|
+
unit.className = "dsh-cloudq-usage__card-unit";
|
|
2010
|
+
unit.textContent = "个";
|
|
2011
|
+
const freeBadge = document.createElement("span");
|
|
2012
|
+
freeBadge.className = "dsh-cloudq-usage__free-badge";
|
|
2013
|
+
freeBadge.textContent = "公测期免费 ⓘ";
|
|
2014
|
+
freeBadge.tabIndex = 0;
|
|
2015
|
+
const freeBadgeTip = document.createElement("span");
|
|
2016
|
+
freeBadgeTip.className = "dsh-cloudq-tooltip";
|
|
2017
|
+
freeBadgeTip.setAttribute("role", "tooltip");
|
|
2018
|
+
freeBadgeTip.textContent = "正式计费将提前 1 个月通知";
|
|
2019
|
+
freeBadge.appendChild(freeBadgeTip);
|
|
2020
|
+
valueRow.append(value, unit, freeBadge);
|
|
2021
|
+
card.append(label, valueRow);
|
|
2022
|
+
overviewWrap.appendChild(card);
|
|
2023
|
+
panelBody.appendChild(overviewWrap);
|
|
2024
|
+
const rangeBar = document.createElement("div");
|
|
2025
|
+
rangeBar.className = "dsh-cloudq-usage__range";
|
|
2026
|
+
const picker = document.createElement("div");
|
|
2027
|
+
picker.className = "dsh-cloudq-usage__range-picker";
|
|
2028
|
+
const pickerBtn = document.createElement("button");
|
|
2029
|
+
pickerBtn.type = "button";
|
|
2030
|
+
pickerBtn.className = "dsh-cloudq-usage__range-btn";
|
|
2031
|
+
pickerBtn.setAttribute("aria-haspopup", "listbox");
|
|
2032
|
+
pickerBtn.setAttribute("aria-expanded", "false");
|
|
2033
|
+
pickerBtn.setAttribute("aria-label", "用量时间范围");
|
|
2034
|
+
const pickerLabel = document.createElement("span");
|
|
2035
|
+
pickerLabel.className = "dsh-cloudq-usage__range-btn-label";
|
|
2036
|
+
const pickerChevron = document.createElement("span");
|
|
2037
|
+
pickerChevron.className = "dsh-cloudq-usage__range-btn-chevron";
|
|
2038
|
+
pickerChevron.textContent = "▾";
|
|
2039
|
+
pickerBtn.append(pickerLabel, pickerChevron);
|
|
2040
|
+
const menu = document.createElement("div");
|
|
2041
|
+
menu.className = "dsh-cloudq-usage__range-menu";
|
|
2042
|
+
menu.setAttribute("role", "listbox");
|
|
2043
|
+
menu.hidden = true;
|
|
2044
|
+
const optionButtons = /* @__PURE__ */ new Map();
|
|
2045
|
+
for (const preset of USAGE_RANGE_PRESETS) {
|
|
2046
|
+
const option = document.createElement("button");
|
|
2047
|
+
option.type = "button";
|
|
2048
|
+
option.className = "dsh-cloudq-usage__range-option";
|
|
2049
|
+
option.setAttribute("role", "option");
|
|
2050
|
+
const check = document.createElement("span");
|
|
2051
|
+
check.className = "dsh-cloudq-usage__range-option-check";
|
|
2052
|
+
check.textContent = "✓";
|
|
2053
|
+
const text = document.createElement("span");
|
|
2054
|
+
text.textContent = preset.label;
|
|
2055
|
+
option.append(check, text);
|
|
2056
|
+
option.addEventListener("click", () => {
|
|
2057
|
+
usagePreset = preset.id;
|
|
2058
|
+
syncPicker();
|
|
2059
|
+
closeMenu();
|
|
2060
|
+
syncCustomVisibility();
|
|
2061
|
+
loadUsage();
|
|
2062
|
+
});
|
|
2063
|
+
optionButtons.set(preset.id, option);
|
|
2064
|
+
menu.appendChild(option);
|
|
2065
|
+
}
|
|
2066
|
+
const syncPicker = () => {
|
|
2067
|
+
const active = USAGE_RANGE_PRESETS.find((item) => item.id === usagePreset) ?? USAGE_RANGE_PRESETS[1];
|
|
2068
|
+
pickerLabel.textContent = active.label;
|
|
2069
|
+
for (const [id, option] of optionButtons) {
|
|
2070
|
+
const isActive = id === active.id;
|
|
2071
|
+
option.classList.toggle("is-active", isActive);
|
|
2072
|
+
option.setAttribute("aria-selected", String(isActive));
|
|
1900
2073
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
2074
|
+
};
|
|
2075
|
+
const pickerAbort = new AbortController();
|
|
2076
|
+
const closeMenu = () => {
|
|
2077
|
+
menu.hidden = true;
|
|
2078
|
+
picker.classList.remove("is-open");
|
|
2079
|
+
pickerBtn.setAttribute("aria-expanded", "false");
|
|
2080
|
+
};
|
|
2081
|
+
pickerBtn.addEventListener("click", () => {
|
|
2082
|
+
const willOpen = menu.hidden;
|
|
2083
|
+
menu.hidden = !willOpen;
|
|
2084
|
+
picker.classList.toggle("is-open", willOpen);
|
|
2085
|
+
pickerBtn.setAttribute("aria-expanded", String(willOpen));
|
|
1911
2086
|
});
|
|
2087
|
+
document.addEventListener("mousedown", (event) => {
|
|
2088
|
+
if (!menu.isConnected) {
|
|
2089
|
+
pickerAbort.abort();
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
if (!picker.contains(event.target)) closeMenu();
|
|
2093
|
+
}, { signal: pickerAbort.signal });
|
|
2094
|
+
document.addEventListener("keydown", (event) => {
|
|
2095
|
+
if (!menu.isConnected) return;
|
|
2096
|
+
if (event.key === "Escape") closeMenu();
|
|
2097
|
+
}, { signal: pickerAbort.signal });
|
|
2098
|
+
syncPicker();
|
|
2099
|
+
const startDate = document.createElement("input");
|
|
2100
|
+
startDate.type = "date";
|
|
2101
|
+
startDate.className = "dsh-cloudq-usage__date";
|
|
2102
|
+
startDate.setAttribute("aria-label", "开始日期");
|
|
2103
|
+
startDate.value = usageCustomStart;
|
|
2104
|
+
const endDate = document.createElement("input");
|
|
2105
|
+
endDate.type = "date";
|
|
2106
|
+
endDate.className = "dsh-cloudq-usage__date";
|
|
2107
|
+
endDate.setAttribute("aria-label", "结束日期");
|
|
2108
|
+
endDate.value = usageCustomEnd;
|
|
2109
|
+
const rangeError = document.createElement("span");
|
|
2110
|
+
rangeError.className = "dsh-cloudq-usage__range-error";
|
|
2111
|
+
const syncCustomVisibility = () => {
|
|
2112
|
+
const custom = usagePreset === "custom";
|
|
2113
|
+
startDate.hidden = !custom;
|
|
2114
|
+
endDate.hidden = !custom;
|
|
2115
|
+
};
|
|
2116
|
+
const tableWrap = document.createElement("div");
|
|
2117
|
+
const loadUsage = () => {
|
|
2118
|
+
const range = usageRangeTimestamps();
|
|
2119
|
+
rangeError.textContent = "";
|
|
2120
|
+
if (!range) {
|
|
2121
|
+
tableWrap.textContent = "";
|
|
2122
|
+
const hint = document.createElement("div");
|
|
2123
|
+
hint.className = "dsh-cloudq-panel__hint";
|
|
2124
|
+
hint.textContent = "请选择开始日期与结束日期。";
|
|
2125
|
+
tableWrap.appendChild(hint);
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
if (usagePreset === "custom" && usageCustomStart > usageCustomEnd) {
|
|
2129
|
+
rangeError.textContent = "开始日期不能晚于结束日期。";
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
tableWrap.textContent = "";
|
|
2133
|
+
const hint = document.createElement("div");
|
|
2134
|
+
hint.className = "dsh-cloudq-panel__hint";
|
|
2135
|
+
hint.textContent = "正在加载用量…";
|
|
2136
|
+
tableWrap.appendChild(hint);
|
|
2137
|
+
cloudqRequest(`${API_USAGE}?start=${encodeURIComponent(range.start)}&end=${encodeURIComponent(range.end)}`).then((data) => {
|
|
2138
|
+
if (panelView !== "usage" || !panelExpanded) return;
|
|
2139
|
+
value.textContent = formatCredits(data.overview?.TotalCredits);
|
|
2140
|
+
const rows = Array.isArray(data.detail) ? data.detail : [];
|
|
2141
|
+
tableWrap.textContent = "";
|
|
2142
|
+
const table = document.createElement("table");
|
|
2143
|
+
table.className = "dsh-cloudq-usage__table";
|
|
2144
|
+
const thead = document.createElement("thead");
|
|
2145
|
+
const headerRow = document.createElement("tr");
|
|
2146
|
+
for (const heading of [
|
|
2147
|
+
"时间",
|
|
2148
|
+
"渠道",
|
|
2149
|
+
"内容",
|
|
2150
|
+
"积分"
|
|
2151
|
+
]) {
|
|
2152
|
+
const cell = document.createElement("th");
|
|
2153
|
+
cell.textContent = heading;
|
|
2154
|
+
headerRow.appendChild(cell);
|
|
2155
|
+
}
|
|
2156
|
+
thead.appendChild(headerRow);
|
|
2157
|
+
table.appendChild(thead);
|
|
2158
|
+
const tbody = document.createElement("tbody");
|
|
2159
|
+
if (rows.length === 0) {
|
|
2160
|
+
const tr = document.createElement("tr");
|
|
2161
|
+
const empty = document.createElement("td");
|
|
2162
|
+
empty.colSpan = 4;
|
|
2163
|
+
empty.className = "dsh-cloudq-usage__table__empty";
|
|
2164
|
+
empty.textContent = "当前时间范围内暂无用量记录";
|
|
2165
|
+
tr.appendChild(empty);
|
|
2166
|
+
tbody.appendChild(tr);
|
|
2167
|
+
} else for (const row of rows) {
|
|
2168
|
+
const tr = document.createElement("tr");
|
|
2169
|
+
const time = document.createElement("td");
|
|
2170
|
+
time.textContent = formatDateTime(row.StartTime);
|
|
2171
|
+
const channel = document.createElement("td");
|
|
2172
|
+
channel.textContent = row.Channel ?? "—";
|
|
2173
|
+
const message = document.createElement("td");
|
|
2174
|
+
const msgSpan = document.createElement("span");
|
|
2175
|
+
msgSpan.className = "dsh-cloudq-usage__table__message";
|
|
2176
|
+
msgSpan.textContent = row.Message ?? "";
|
|
2177
|
+
message.appendChild(msgSpan);
|
|
2178
|
+
const credits = document.createElement("td");
|
|
2179
|
+
credits.className = "dsh-cloudq-usage__table__credits";
|
|
2180
|
+
credits.textContent = formatCredits(row.Credits);
|
|
2181
|
+
tr.appendChild(time);
|
|
2182
|
+
tr.appendChild(channel);
|
|
2183
|
+
tr.appendChild(message);
|
|
2184
|
+
tr.appendChild(credits);
|
|
2185
|
+
tbody.appendChild(tr);
|
|
2186
|
+
}
|
|
2187
|
+
table.appendChild(tbody);
|
|
2188
|
+
tableWrap.appendChild(table);
|
|
2189
|
+
}).catch((error) => {
|
|
2190
|
+
if (panelView !== "usage" || !panelExpanded) return;
|
|
2191
|
+
tableWrap.textContent = "";
|
|
2192
|
+
const err = document.createElement("div");
|
|
2193
|
+
err.className = "dsh-cloudq-panel__error";
|
|
2194
|
+
err.textContent = cloudqPanelErrorText(error, "用量加载失败");
|
|
2195
|
+
tableWrap.appendChild(err);
|
|
2196
|
+
});
|
|
2197
|
+
};
|
|
2198
|
+
const onCustomDateChange = () => {
|
|
2199
|
+
usageCustomStart = startDate.value;
|
|
2200
|
+
usageCustomEnd = endDate.value;
|
|
2201
|
+
loadUsage();
|
|
2202
|
+
};
|
|
2203
|
+
startDate.addEventListener("change", onCustomDateChange);
|
|
2204
|
+
endDate.addEventListener("change", onCustomDateChange);
|
|
2205
|
+
picker.append(pickerBtn, menu);
|
|
2206
|
+
rangeBar.append(picker, startDate, endDate, rangeError);
|
|
2207
|
+
syncCustomVisibility();
|
|
2208
|
+
panelBody.appendChild(rangeBar);
|
|
2209
|
+
panelBody.appendChild(tableWrap);
|
|
2210
|
+
loadUsage();
|
|
1912
2211
|
}
|
|
1913
2212
|
const INSPIRATION_TABS = [
|
|
1914
2213
|
{
|
|
@@ -2009,7 +2308,7 @@ display: none;
|
|
|
2009
2308
|
list.textContent = "";
|
|
2010
2309
|
const err = document.createElement("div");
|
|
2011
2310
|
err.className = "dsh-cloudq-panel__error";
|
|
2012
|
-
err.textContent =
|
|
2311
|
+
err.textContent = cloudqPanelErrorText(error, "灵感加载失败");
|
|
2013
2312
|
list.appendChild(err);
|
|
2014
2313
|
});
|
|
2015
2314
|
}
|
|
@@ -2152,7 +2451,7 @@ display: none;
|
|
|
2152
2451
|
panelBody.textContent = "";
|
|
2153
2452
|
const err = document.createElement("div");
|
|
2154
2453
|
err.className = "dsh-cloudq-panel__error";
|
|
2155
|
-
err.textContent =
|
|
2454
|
+
err.textContent = cloudqPanelErrorText(error, "制品加载失败");
|
|
2156
2455
|
panelBody.appendChild(err);
|
|
2157
2456
|
});
|
|
2158
2457
|
}
|
|
@@ -2433,7 +2732,7 @@ display: none;
|
|
|
2433
2732
|
summary.textContent = "加载失败";
|
|
2434
2733
|
const err = document.createElement("div");
|
|
2435
2734
|
err.className = "dsh-cloudq-panel__error";
|
|
2436
|
-
err.textContent =
|
|
2735
|
+
err.textContent = cloudqPanelErrorText(error, "架构图加载失败");
|
|
2437
2736
|
grid.appendChild(err);
|
|
2438
2737
|
});
|
|
2439
2738
|
};
|
|
@@ -2452,7 +2751,7 @@ display: none;
|
|
|
2452
2751
|
panelBody.textContent = "";
|
|
2453
2752
|
const err = document.createElement("div");
|
|
2454
2753
|
err.className = "dsh-cloudq-panel__error";
|
|
2455
|
-
err.textContent =
|
|
2754
|
+
err.textContent = cloudqPanelErrorText(error, "架构目录加载失败");
|
|
2456
2755
|
panelBody.appendChild(err);
|
|
2457
2756
|
});
|
|
2458
2757
|
}
|
|
@@ -2732,8 +3031,6 @@ display: none;
|
|
|
2732
3031
|
};
|
|
2733
3032
|
}
|
|
2734
3033
|
const API_CREDENTIAL = "/api/dsh-cloudq/credential";
|
|
2735
|
-
const API_LOGIN_URL = "/api/dsh-cloudq/login/url";
|
|
2736
|
-
const API_LOGIN_SAVE = "/api/dsh-cloudq/login/save";
|
|
2737
3034
|
const API_LOGOUT = "/api/dsh-cloudq/logout";
|
|
2738
3035
|
const API_CREDENTIAL_TEST = "/api/dsh-cloudq/credential/test";
|
|
2739
3036
|
const API_CREDENTIAL_SAVE = "/api/dsh-cloudq/credential/save";
|
|
@@ -2744,6 +3041,14 @@ display: none;
|
|
|
2744
3041
|
this.code = code;
|
|
2745
3042
|
}
|
|
2746
3043
|
};
|
|
3044
|
+
/**
|
|
3045
|
+
* Panel-facing error text. A missing credential gets an actionable pointer to
|
|
3046
|
+
* the settings card instead of a raw load failure message.
|
|
3047
|
+
*/
|
|
3048
|
+
function cloudqPanelErrorText(error, prefix) {
|
|
3049
|
+
if (error instanceof CloudQApiError && error.code === "NeedAuth") return "尚未配置 AK/SK,请前往「设置 → 插件 → CloudQ」完成配置后重试。";
|
|
3050
|
+
return `${prefix}:${error instanceof Error ? error.message : "未知错误"}`;
|
|
3051
|
+
}
|
|
2747
3052
|
async function cloudqRequest(url, init, timeoutMs = 2e4) {
|
|
2748
3053
|
const controller = new AbortController();
|
|
2749
3054
|
const timeout = window.setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -2788,9 +3093,8 @@ display: none;
|
|
|
2788
3093
|
const [loading, setLoading] = react.useState(true);
|
|
2789
3094
|
const [busy, setBusy] = react.useState();
|
|
2790
3095
|
const [status, setStatus] = react.useState();
|
|
2791
|
-
const [authorizeUrl, setAuthorizeUrl] = react.useState("");
|
|
2792
|
-
const [code, setCode] = react.useState("");
|
|
2793
3096
|
const [feedback, setFeedback] = react.useState();
|
|
3097
|
+
const [validated, setValidated] = react.useState(false);
|
|
2794
3098
|
const [secretId, setSecretId] = react.useState("");
|
|
2795
3099
|
const [secretKey, setSecretKey] = react.useState("");
|
|
2796
3100
|
const refresh = react.useCallback(async () => {
|
|
@@ -2810,61 +3114,13 @@ display: none;
|
|
|
2810
3114
|
react.useEffect(() => {
|
|
2811
3115
|
refresh();
|
|
2812
3116
|
}, [refresh]);
|
|
2813
|
-
const handleGetAuthorizeUrl = async () => {
|
|
2814
|
-
setBusy("url");
|
|
2815
|
-
setFeedback(void 0);
|
|
2816
|
-
try {
|
|
2817
|
-
const response = await cloudqRequest(API_LOGIN_URL, { method: "POST" });
|
|
2818
|
-
setAuthorizeUrl(response.authorize_url);
|
|
2819
|
-
if (response.authorize_url) window.open(response.authorize_url, "_blank", "noopener");
|
|
2820
|
-
} catch (error) {
|
|
2821
|
-
setFeedback({
|
|
2822
|
-
kind: "error",
|
|
2823
|
-
text: error.message
|
|
2824
|
-
});
|
|
2825
|
-
} finally {
|
|
2826
|
-
setBusy(void 0);
|
|
2827
|
-
}
|
|
2828
|
-
};
|
|
2829
|
-
const handleSaveCode = async () => {
|
|
2830
|
-
const trimmed = code.trim();
|
|
2831
|
-
if (!trimmed) {
|
|
2832
|
-
setFeedback({
|
|
2833
|
-
kind: "error",
|
|
2834
|
-
text: "请先在浏览器中完成授权,然后粘贴授权码。"
|
|
2835
|
-
});
|
|
2836
|
-
return;
|
|
2837
|
-
}
|
|
2838
|
-
setBusy("save");
|
|
2839
|
-
setFeedback(void 0);
|
|
2840
|
-
try {
|
|
2841
|
-
const response = await cloudqRequest(API_LOGIN_SAVE, {
|
|
2842
|
-
method: "POST",
|
|
2843
|
-
body: JSON.stringify({ code: trimmed })
|
|
2844
|
-
});
|
|
2845
|
-
setStatus(response.status);
|
|
2846
|
-
setCode("");
|
|
2847
|
-
setFeedback({
|
|
2848
|
-
kind: "success",
|
|
2849
|
-
text: "登录成功,凭证已保存。"
|
|
2850
|
-
});
|
|
2851
|
-
} catch (error) {
|
|
2852
|
-
setFeedback({
|
|
2853
|
-
kind: "error",
|
|
2854
|
-
text: error.message
|
|
2855
|
-
});
|
|
2856
|
-
} finally {
|
|
2857
|
-
setBusy(void 0);
|
|
2858
|
-
}
|
|
2859
|
-
};
|
|
2860
3117
|
const handleLogout = async () => {
|
|
2861
3118
|
setBusy("logout");
|
|
2862
3119
|
setFeedback(void 0);
|
|
2863
3120
|
try {
|
|
2864
3121
|
await cloudqRequest(API_LOGOUT, { method: "POST" });
|
|
2865
3122
|
setStatus({ logged_in: false });
|
|
2866
|
-
|
|
2867
|
-
setCode("");
|
|
3123
|
+
setValidated(false);
|
|
2868
3124
|
setFeedback({
|
|
2869
3125
|
kind: "success",
|
|
2870
3126
|
text: "已退出登录。"
|
|
@@ -2903,26 +3159,27 @@ display: none;
|
|
|
2903
3159
|
setSecretId("");
|
|
2904
3160
|
setSecretKey("");
|
|
2905
3161
|
}
|
|
3162
|
+
setValidated(true);
|
|
2906
3163
|
setFeedback({
|
|
2907
3164
|
kind: "success",
|
|
2908
3165
|
text: successText
|
|
2909
3166
|
});
|
|
2910
3167
|
} catch (error) {
|
|
3168
|
+
setValidated(false);
|
|
3169
|
+
const invalid = error instanceof CloudQApiError && error.code !== "network-error" && error.code !== "invalid-response";
|
|
2911
3170
|
setFeedback({
|
|
2912
3171
|
kind: "error",
|
|
2913
|
-
text: error.message
|
|
3172
|
+
text: invalid ? "AKSK 无效,请检查后重新配置。" : error.message
|
|
2914
3173
|
});
|
|
2915
3174
|
} finally {
|
|
2916
3175
|
setBusy(void 0);
|
|
2917
3176
|
}
|
|
2918
3177
|
};
|
|
2919
|
-
const handleTestConnection = () => submitAccessKey(API_CREDENTIAL_TEST, "test", "
|
|
2920
|
-
const handleSaveAccessKey = () => submitAccessKey(API_CREDENTIAL_SAVE, "save-ak", "
|
|
3178
|
+
const handleTestConnection = () => submitAccessKey(API_CREDENTIAL_TEST, "test", "连接成功,AKSK 有效。");
|
|
3179
|
+
const handleSaveAccessKey = () => submitAccessKey(API_CREDENTIAL_SAVE, "save-ak", "配置已保存,AKSK 有效。");
|
|
2921
3180
|
const loggedIn = status?.logged_in === true;
|
|
2922
|
-
const
|
|
2923
|
-
const
|
|
2924
|
-
const badgeText = expired ? "凭证已过期" : loggedIn ? "已登录" : "未登录";
|
|
2925
|
-
const summarySubtitle = loggedIn ? "腾讯云 CloudQ 凭证已激活,可直接使用 CloudQ 模式。" : "用于在 CloudQ 模式下调用腾讯云 SSE API 与 CLI 工具。";
|
|
3181
|
+
const akskValid = validated || loggedIn;
|
|
3182
|
+
const summarySubtitle = akskValid ? "腾讯云 CloudQ 凭证已激活,可直接使用 CloudQ 模式。" : "用于在 CloudQ 模式下调用腾讯云 SSE API 与 CLI 工具。";
|
|
2926
3183
|
const disabled = loading || busy !== void 0;
|
|
2927
3184
|
return react_jsx_runtime.jsx("section", {
|
|
2928
3185
|
className: "dsh-cloudq-settings-card",
|
|
@@ -2938,9 +3195,9 @@ display: none;
|
|
|
2938
3195
|
children: [react_jsx_runtime.jsx("strong", { children: "CloudQ" }), react_jsx_runtime.jsx("small", { children: summarySubtitle })]
|
|
2939
3196
|
}), react_jsx_runtime.jsx("span", {
|
|
2940
3197
|
className: "dsh-cloudq-settings-card__summary-right",
|
|
2941
|
-
children: [react_jsx_runtime.jsx("span", {
|
|
2942
|
-
className:
|
|
2943
|
-
children: [react_jsx_runtime.jsx("span", { className: "dsh-cloudq-settings-card__badge-dot" }),
|
|
3198
|
+
children: [akskValid && react_jsx_runtime.jsx("span", {
|
|
3199
|
+
className: "dsh-cloudq-settings-card__badge dsh-cloudq-settings-card__badge--ok",
|
|
3200
|
+
children: [react_jsx_runtime.jsx("span", { className: "dsh-cloudq-settings-card__badge-dot" }), "AKSK有效"]
|
|
2944
3201
|
}), react_jsx_runtime.jsx("span", {
|
|
2945
3202
|
className: `dsh-cloudq-settings-card__chevron${expanded ? " is-open" : ""}`,
|
|
2946
3203
|
children: "▾"
|
|
@@ -2952,20 +3209,10 @@ display: none;
|
|
|
2952
3209
|
children: [
|
|
2953
3210
|
loading ? react_jsx_runtime.jsx("div", {
|
|
2954
3211
|
className: "dsh-cloudq-settings-card__hint",
|
|
2955
|
-
children: "
|
|
3212
|
+
children: "正在检查凭证状态…"
|
|
2956
3213
|
}) : react_jsx_runtime.jsx("div", {
|
|
2957
3214
|
className: "dsh-cloudq-settings-card__rows",
|
|
2958
3215
|
children: [
|
|
2959
|
-
react_jsx_runtime.jsx("div", {
|
|
2960
|
-
className: "dsh-cloudq-settings-card__row",
|
|
2961
|
-
children: [react_jsx_runtime.jsx("span", {
|
|
2962
|
-
className: "dsh-cloudq-settings-card__row-key",
|
|
2963
|
-
children: "状态"
|
|
2964
|
-
}), react_jsx_runtime.jsx("span", {
|
|
2965
|
-
className: "dsh-cloudq-settings-card__row-val",
|
|
2966
|
-
children: badgeText
|
|
2967
|
-
})]
|
|
2968
|
-
}),
|
|
2969
3216
|
status?.credential_file ? react_jsx_runtime.jsx("div", {
|
|
2970
3217
|
className: "dsh-cloudq-settings-card__row",
|
|
2971
3218
|
children: [react_jsx_runtime.jsx("span", {
|
|
@@ -3023,35 +3270,6 @@ display: none;
|
|
|
3023
3270
|
children: feedback.text
|
|
3024
3271
|
}) : null,
|
|
3025
3272
|
!loggedIn && react_jsx_runtime.jsx("div", { children: [
|
|
3026
|
-
react_jsx_runtime.jsx("div", {
|
|
3027
|
-
className: "dsh-cloudq-settings-card__actions",
|
|
3028
|
-
children: [react_jsx_runtime.jsx("button", {
|
|
3029
|
-
type: "button",
|
|
3030
|
-
className: "dsh-cloudq-settings-card__btn dsh-cloudq-settings-card__btn--primary",
|
|
3031
|
-
disabled,
|
|
3032
|
-
onClick: handleGetAuthorizeUrl,
|
|
3033
|
-
children: busy === "url" ? "获取中…" : "获取授权链接"
|
|
3034
|
-
})]
|
|
3035
|
-
}),
|
|
3036
|
-
authorizeUrl && react_jsx_runtime.jsx("div", {
|
|
3037
|
-
className: "dsh-cloudq-settings-card__hint",
|
|
3038
|
-
children: "已在新标签页打开授权页。授权完成后,请将页面显示的授权码粘贴到下方:"
|
|
3039
|
-
}),
|
|
3040
|
-
react_jsx_runtime.jsx("div", {
|
|
3041
|
-
className: "dsh-cloudq-settings-card__actions dsh-cloudq-settings-card__actions--stacked",
|
|
3042
|
-
children: [react_jsx_runtime.jsx("input", {
|
|
3043
|
-
className: "dsh-cloudq-settings-card__input",
|
|
3044
|
-
placeholder: "粘贴授权码",
|
|
3045
|
-
value: code,
|
|
3046
|
-
onChange: (event) => setCode(event.target.value)
|
|
3047
|
-
}), react_jsx_runtime.jsx("button", {
|
|
3048
|
-
type: "button",
|
|
3049
|
-
className: "dsh-cloudq-settings-card__btn",
|
|
3050
|
-
disabled,
|
|
3051
|
-
onClick: handleSaveCode,
|
|
3052
|
-
children: busy === "save" ? "登录中…" : "完成登录"
|
|
3053
|
-
})]
|
|
3054
|
-
}),
|
|
3055
3273
|
react_jsx_runtime.jsx("div", {
|
|
3056
3274
|
className: "dsh-cloudq-settings-card__field",
|
|
3057
3275
|
children: [
|
|
@@ -3281,17 +3499,10 @@ display: none;
|
|
|
3281
3499
|
className: "dsh-cloudq-pm__row-info",
|
|
3282
3500
|
children: [react_jsx_runtime.jsx("div", {
|
|
3283
3501
|
className: "dsh-cloudq-pm__row-name",
|
|
3284
|
-
children: [
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
children: "本插件"
|
|
3289
|
-
}) : null,
|
|
3290
|
-
!on ? react_jsx_runtime.jsx("span", {
|
|
3291
|
-
className: "dsh-cloudq-pm__row-tag dsh-cloudq-pm__row-tag--off",
|
|
3292
|
-
children: "已停用"
|
|
3293
|
-
}) : null
|
|
3294
|
-
]
|
|
3502
|
+
children: [plugin.name, !on ? react_jsx_runtime.jsx("span", {
|
|
3503
|
+
className: "dsh-cloudq-pm__row-tag dsh-cloudq-pm__row-tag--off",
|
|
3504
|
+
children: "已停用"
|
|
3505
|
+
}) : null]
|
|
3295
3506
|
}), react_jsx_runtime.jsx("div", {
|
|
3296
3507
|
className: "dsh-cloudq-pm__row-bundle",
|
|
3297
3508
|
children: `${plugin.id} · ${plugin.bundle}`
|
package/lib/index.js
CHANGED
|
@@ -392,9 +392,9 @@ function runScript$1(scriptsDirectory, scriptName, args, { timeoutMs = 3e4, json
|
|
|
392
392
|
* and referenced through a directory `resourceBase`, so every `{baseDir}`
|
|
393
393
|
* placeholder in the body resolves against the installed package directory.
|
|
394
394
|
*
|
|
395
|
-
* It also exposes a small credential-management API (status /
|
|
396
|
-
* save
|
|
397
|
-
*
|
|
395
|
+
* It also exposes a small credential-management API (status / AK-SK test &
|
|
396
|
+
* save / logout) that the client half renders in the settings panel, so the
|
|
397
|
+
* CloudQ credential flow no longer requires touching a terminal.
|
|
398
398
|
*
|
|
399
399
|
* @module dsh-cloudq
|
|
400
400
|
*/
|
|
@@ -420,8 +420,13 @@ function renderedSkillContent() {
|
|
|
420
420
|
return rawSkillContent().replace(/\{baseDir\}/g, baseDir);
|
|
421
421
|
}
|
|
422
422
|
/** Run one helper from the bundled CloudQ skill. */
|
|
423
|
-
function runScript(scriptName, args, options) {
|
|
424
|
-
|
|
423
|
+
async function runScript(scriptName, args, options) {
|
|
424
|
+
try {
|
|
425
|
+
return await runScript$1(resolve(skillDirectory(), "scripts"), scriptName, args, options);
|
|
426
|
+
} catch (error) {
|
|
427
|
+
if (error instanceof HttpError && error.code === "NeedAuth") throw new HttpError(401, "NeedAuth", "尚未配置 AK/SK,请前往「设置 → 插件 → CloudQ」完成配置。");
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
425
430
|
}
|
|
426
431
|
/** Remove host filesystem details before returning credential state to the browser. */
|
|
427
432
|
function publicCredentialStatus(status) {
|
|
@@ -434,15 +439,6 @@ function publicCredentialStatus(status) {
|
|
|
434
439
|
async function credentialStatus() {
|
|
435
440
|
return publicCredentialStatus(await runScript("login.py", ["--status"]));
|
|
436
441
|
}
|
|
437
|
-
function authorizeUrl() {
|
|
438
|
-
return runScript("login.py", ["--authorize-url"]);
|
|
439
|
-
}
|
|
440
|
-
async function saveAuthCode(code) {
|
|
441
|
-
return publicCredentialStatus(await runScript("login.py", ["--save", "--stdin"], {
|
|
442
|
-
stdin: JSON.stringify({ code }),
|
|
443
|
-
sensitiveValues: [code]
|
|
444
|
-
}));
|
|
445
|
-
}
|
|
446
442
|
function logout() {
|
|
447
443
|
return runScript("logout.py", [], { jsonOnly: false });
|
|
448
444
|
}
|
|
@@ -616,23 +612,29 @@ const inject = [
|
|
|
616
612
|
"sessionQuery"
|
|
617
613
|
];
|
|
618
614
|
function apply(ctx) {
|
|
619
|
-
ctx.effect(() =>
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
615
|
+
ctx.effect(() => {
|
|
616
|
+
ctx.settings.register(SETTINGS_NAMESPACE, Config, { base: {} });
|
|
617
|
+
}, "dsh-cloudq: settings namespace");
|
|
618
|
+
ctx.effect(() => {
|
|
619
|
+
ctx.settings.register(PLUGIN_MANAGER_NAMESPACE, Config, { base: {} });
|
|
620
|
+
}, "dsh-cloudq: plugin-manager settings namespace");
|
|
621
|
+
ctx.effect(() => {
|
|
622
|
+
ctx.skills.register({
|
|
623
|
+
name: "cloudq",
|
|
624
|
+
description: "用户咨询腾讯云产品资源、AWS、阿里云等多云资源时,查看智能顾问架构图、架构目录、架构详情、架构评估结果、绘制架构图、开通智能顾问时、AI智能巡检、AI容量监测、AI混沌演练、AI云诊断、主动预警、架构健康度、云运维问答、云资源查询、云成本优化、安全合规、云资源盘点、闲置资源检查、云产品最佳实践等AIOps、ChatOps、CloudOps操作时使用。",
|
|
625
|
+
whenToUse: "用户要求进入 CloudQ 模式、使用 CloudQ、咨询云上架构/资源/成本/巡检/诊断等多云或腾讯云运维问题,或点击输入栏 CloudQ 按钮时使用;也适用于架构图查看/评估、AI 巡检、容量监测、混沌演练、云诊断等场景。",
|
|
626
|
+
source: "bundled",
|
|
627
|
+
resourceBase: {
|
|
628
|
+
kind: "directory",
|
|
629
|
+
path: skillDirectory()
|
|
630
|
+
},
|
|
631
|
+
content: renderedSkillContent(),
|
|
632
|
+
invocation: {
|
|
633
|
+
modelInvocable: true,
|
|
634
|
+
userInvocable: true
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
}, "dsh-cloudq: CloudQ skill");
|
|
636
638
|
ctx.effect(() => {
|
|
637
639
|
const disposers = [];
|
|
638
640
|
disposers.push(ctx.webServer.register({
|
|
@@ -650,41 +652,6 @@ function apply(ctx) {
|
|
|
650
652
|
}
|
|
651
653
|
}
|
|
652
654
|
}));
|
|
653
|
-
disposers.push(ctx.webServer.register({
|
|
654
|
-
kind: "exact",
|
|
655
|
-
path: "/api/dsh-cloudq/login/url",
|
|
656
|
-
handler: async (request, response) => {
|
|
657
|
-
try {
|
|
658
|
-
assertSafeRequest(request, "POST");
|
|
659
|
-
const result = await authorizeUrl();
|
|
660
|
-
sendJson(response, 200, {
|
|
661
|
-
ok: true,
|
|
662
|
-
authorize_url: result.authorize_url,
|
|
663
|
-
state: result.state
|
|
664
|
-
});
|
|
665
|
-
} catch (error) {
|
|
666
|
-
sendError(response, error);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}));
|
|
670
|
-
disposers.push(ctx.webServer.register({
|
|
671
|
-
kind: "exact",
|
|
672
|
-
path: "/api/dsh-cloudq/login/save",
|
|
673
|
-
handler: async (request, response) => {
|
|
674
|
-
try {
|
|
675
|
-
assertSafeRequest(request, "POST");
|
|
676
|
-
const body = await readJsonBody(request);
|
|
677
|
-
const code = typeof body?.code === "string" ? body.code.trim() : "";
|
|
678
|
-
if (!code) throw new HttpError(400, "missing-code", "缺少授权码。");
|
|
679
|
-
sendJson(response, 200, {
|
|
680
|
-
ok: true,
|
|
681
|
-
status: await saveAuthCode(code)
|
|
682
|
-
});
|
|
683
|
-
} catch (error) {
|
|
684
|
-
sendError(response, error);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}));
|
|
688
655
|
disposers.push(ctx.webServer.register({
|
|
689
656
|
kind: "exact",
|
|
690
657
|
path: "/api/dsh-cloudq/logout",
|
package/package.json
CHANGED