@finebi/finebi-cli 1.6.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/agent-installation-guide.md +70 -0
- package/package.json +2 -1
- package/skills/finebi-cli-agent/references/dashboard-data-result.md +191 -191
- package/skills/finebi-cli-agent/references/dashboard-dsl-api.md +44 -44
- package/skills/finebi-cli-agent/scripts/finebi-cli/package.json +1 -1
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/app.js +160 -157
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/config.js +27 -27
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/help.js +55 -55
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/install-skill.js +89 -89
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/profiles.js +158 -158
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/skill-files.js +95 -94
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/docs/acceptance.md +80 -80
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/examples/cockpit.config.json +22 -22
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/examples/retail.config.json +185 -185
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/gitignore.template +6 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/index.html +2 -2
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/public/app-config.json +11 -11
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/App.tsx +63 -63
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/cockpit.css +3 -3
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/Chart.tsx +40 -40
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/Insights.tsx +17 -17
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/MonthPicker.tsx +32 -32
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/OptionFilter.tsx +7 -7
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/RangeFilter.tsx +9 -9
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/Widget.tsx +40 -40
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/calendar-locales.ts +3 -3
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/calendar.ts +14 -14
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/charts/Bar.tsx +6 -6
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/charts/Line.tsx +6 -6
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/charts/Pie.tsx +6 -6
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/components/month-picker.css +1 -1
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/config.d.ts +3 -3
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/config.js +58 -58
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/date.d.ts +1 -1
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/date.js +5 -5
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/filters.d.ts +4 -4
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/filters.js +106 -106
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/normalize.ts +235 -235
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/finebi/types.ts +20 -20
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/main.tsx +5 -5
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/retail.css +12 -12
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/services/presentation.ts +36 -36
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/services/table-data.ts +47 -47
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/services/view-data.ts +18 -18
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/src/services/widget-queries.ts +18 -18
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/browser/fixtures.mjs +28 -28
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/browser/index.html +16 -16
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/browser/main.tsx +149 -149
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/browser/test-page.css +4 -4
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/browser/vite.config.mjs +13 -13
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/bundle.test.mjs +19 -19
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/cockpit.test.mjs +73 -73
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/field-selection.test.mjs +70 -70
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/retail.test.mjs +31 -31
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tests/table-normalize.test.mjs +189 -189
- package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/tsconfig.json +4 -4
- package/skills/finebi-cli-agent/scripts/finebi-cli-runner.mjs +4 -4
- package/src/app.js +160 -157
- package/src/config.js +27 -27
- package/src/help.js +55 -55
- package/src/install-skill.js +89 -89
- package/src/profiles.js +158 -158
- package/src/skill-files.js +95 -94
- package/templates/web-app/docs/acceptance.md +80 -80
- package/templates/web-app/examples/cockpit.config.json +22 -22
- package/templates/web-app/examples/retail.config.json +185 -185
- package/templates/web-app/gitignore.template +6 -0
- package/templates/web-app/index.html +2 -2
- package/templates/web-app/public/app-config.json +11 -11
- package/templates/web-app/src/App.tsx +63 -63
- package/templates/web-app/src/cockpit.css +3 -3
- package/templates/web-app/src/components/Chart.tsx +40 -40
- package/templates/web-app/src/components/Insights.tsx +17 -17
- package/templates/web-app/src/components/MonthPicker.tsx +32 -32
- package/templates/web-app/src/components/OptionFilter.tsx +7 -7
- package/templates/web-app/src/components/RangeFilter.tsx +9 -9
- package/templates/web-app/src/components/Widget.tsx +40 -40
- package/templates/web-app/src/components/calendar-locales.ts +3 -3
- package/templates/web-app/src/components/calendar.ts +14 -14
- package/templates/web-app/src/components/charts/Bar.tsx +6 -6
- package/templates/web-app/src/components/charts/Line.tsx +6 -6
- package/templates/web-app/src/components/charts/Pie.tsx +6 -6
- package/templates/web-app/src/components/month-picker.css +1 -1
- package/templates/web-app/src/finebi/config.d.ts +3 -3
- package/templates/web-app/src/finebi/config.js +58 -58
- package/templates/web-app/src/finebi/date.d.ts +1 -1
- package/templates/web-app/src/finebi/date.js +5 -5
- package/templates/web-app/src/finebi/filters.d.ts +4 -4
- package/templates/web-app/src/finebi/filters.js +106 -106
- package/templates/web-app/src/finebi/normalize.ts +235 -235
- package/templates/web-app/src/finebi/types.ts +20 -20
- package/templates/web-app/src/main.tsx +5 -5
- package/templates/web-app/src/retail.css +12 -12
- package/templates/web-app/src/services/presentation.ts +36 -36
- package/templates/web-app/src/services/table-data.ts +47 -47
- package/templates/web-app/src/services/view-data.ts +18 -18
- package/templates/web-app/src/services/widget-queries.ts +18 -18
- package/templates/web-app/tests/browser/fixtures.mjs +28 -28
- package/templates/web-app/tests/browser/index.html +16 -16
- package/templates/web-app/tests/browser/main.tsx +149 -149
- package/templates/web-app/tests/browser/test-page.css +4 -4
- package/templates/web-app/tests/browser/vite.config.mjs +13 -13
- package/templates/web-app/tests/bundle.test.mjs +19 -19
- package/templates/web-app/tests/cockpit.test.mjs +73 -73
- package/templates/web-app/tests/field-selection.test.mjs +70 -70
- package/templates/web-app/tests/retail.test.mjs +31 -31
- package/templates/web-app/tests/table-normalize.test.mjs +189 -189
- package/templates/web-app/tsconfig.json +4 -4
|
@@ -1,94 +1,95 @@
|
|
|
1
|
-
import {createHash, randomUUID} from "node:crypto";
|
|
2
|
-
import {existsSync} from "node:fs";
|
|
3
|
-
import {cp, mkdir, lstat, mkdtemp, readFile, readdir, rename, rm} from "node:fs/promises";
|
|
4
|
-
import {homedir} from "node:os";
|
|
5
|
-
import {join, dirname, resolve} from "node:path";
|
|
6
|
-
|
|
7
|
-
export function agentCatalog({home = homedir(), env = process.env} = {}) {
|
|
8
|
-
const config = env.XDG_CONFIG_HOME || join(home, ".config");
|
|
9
|
-
return [
|
|
10
|
-
["claude-code", "Claude Code", env.CLAUDE_CONFIG_DIR || join(home, ".claude")],
|
|
11
|
-
["codex", "Codex", env.CODEX_HOME || join(home, ".codex")],
|
|
12
|
-
["
|
|
13
|
-
["
|
|
14
|
-
["
|
|
15
|
-
["
|
|
16
|
-
["
|
|
17
|
-
["
|
|
18
|
-
["
|
|
19
|
-
["trae
|
|
20
|
-
["
|
|
21
|
-
["
|
|
22
|
-
["
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (entry.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
import {createHash, randomUUID} from "node:crypto";
|
|
2
|
+
import {existsSync} from "node:fs";
|
|
3
|
+
import {cp, mkdir, lstat, mkdtemp, readFile, readdir, rename, rm} from "node:fs/promises";
|
|
4
|
+
import {homedir} from "node:os";
|
|
5
|
+
import {join, dirname, resolve} from "node:path";
|
|
6
|
+
|
|
7
|
+
export function agentCatalog({home = homedir(), env = process.env} = {}) {
|
|
8
|
+
const config = env.XDG_CONFIG_HOME || join(home, ".config");
|
|
9
|
+
return [
|
|
10
|
+
["claude-code", "Claude Code", env.CLAUDE_CONFIG_DIR || join(home, ".claude")],
|
|
11
|
+
["codex", "Codex", env.CODEX_HOME || join(home, ".codex")],
|
|
12
|
+
["dsh", "DeepSeek Harness", env.DSH_HOME || join(home, ".dsh")],
|
|
13
|
+
["cursor", "Cursor", join(home, ".cursor")],
|
|
14
|
+
["gemini-cli", "Gemini CLI", join(home, ".gemini")],
|
|
15
|
+
["github-copilot", "GitHub Copilot", join(home, ".copilot")],
|
|
16
|
+
["opencode", "OpenCode", join(config, "opencode")],
|
|
17
|
+
["cline", "Cline", join(home, ".agents")],
|
|
18
|
+
["windsurf", "Windsurf", join(home, ".codeium", "windsurf")],
|
|
19
|
+
["trae", "Trae", join(home, ".trae")],
|
|
20
|
+
["trae-cn", "Trae CN", join(home, ".trae-cn")],
|
|
21
|
+
["openclaw", "OpenClaw", [".openclaw", ".clawdbot", ".moltbot"].map(p => join(home, p)).find(existsSync) || join(home, ".openclaw")],
|
|
22
|
+
["roo", "Roo Code", join(home, ".roo")],
|
|
23
|
+
["qwen-code", "Qwen Code", join(home, ".qwen")],
|
|
24
|
+
].map(([id, name, root]) => ({id, name, directory: join(root, "skills"), detected: existsSync(root)}));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function hashTree(root, prefix = "") {
|
|
28
|
+
const files = {};
|
|
29
|
+
for (const entry of (await readdir(join(root, prefix), {withFileTypes: true})).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
30
|
+
const name = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
31
|
+
if (entry.isSymbolicLink()) throw new Error(`Skill contains a symbolic link: ${name}`);
|
|
32
|
+
if (entry.isDirectory()) Object.assign(files, await hashTree(root, name));
|
|
33
|
+
else files[name] = createHash("sha256").update(await readFile(join(root, name))).digest("hex");
|
|
34
|
+
}
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sameHashes(left, right) {
|
|
39
|
+
return left && right && Object.keys(left).length === Object.keys(right).length
|
|
40
|
+
&& Object.keys(left).every(key => left[key] === right[key]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function installSkills({source, home, env, agents, replace = false, previous = []}) {
|
|
44
|
+
const catalog = agentCatalog({home, env});
|
|
45
|
+
const selected = agents.map(id => {
|
|
46
|
+
const agent = catalog.find(item => item.id === id);
|
|
47
|
+
if (!agent) throw new Error(`Unknown Agent: ${id}`);
|
|
48
|
+
return agent;
|
|
49
|
+
});
|
|
50
|
+
const sourceHashes = await hashTree(source);
|
|
51
|
+
const results = [];
|
|
52
|
+
for (const agent of selected) {
|
|
53
|
+
const target = join(agent.directory, "finebi-cli-agent");
|
|
54
|
+
let backup;
|
|
55
|
+
let candidate;
|
|
56
|
+
try {
|
|
57
|
+
const stat = await lstat(target).catch(error => { if (error.code !== "ENOENT") throw error; });
|
|
58
|
+
if (stat) {
|
|
59
|
+
if (stat.isSymbolicLink()) throw new Error("Skill target is a symbolic link; refusing to replace it.");
|
|
60
|
+
const actual = await hashTree(target);
|
|
61
|
+
if (sameHashes(sourceHashes, actual)) {
|
|
62
|
+
results.push({agent: agent.id, path: target, status: "unchanged", hashes: sourceHashes});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const recorded = previous.find(item => item.agent === agent.id && item.path === target)?.hashes;
|
|
66
|
+
if (!replace && !sameHashes(recorded, actual)) {
|
|
67
|
+
results.push({agent: agent.id, path: target, status: "kept"});
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
backup = join(home, ".finebi-cli", "skill-backups", `${agent.id}-${randomUUID()}`);
|
|
71
|
+
await mkdir(dirname(backup), {recursive: true});
|
|
72
|
+
await cp(target, backup, {recursive: true, errorOnExist: true, force: false});
|
|
73
|
+
if (!sameHashes(actual, await hashTree(backup))) throw new Error("Skill backup integrity check failed.");
|
|
74
|
+
}
|
|
75
|
+
await mkdir(agent.directory, {recursive: true});
|
|
76
|
+
candidate = await mkdtemp(join(agent.directory, ".finebi-cli-stage-"));
|
|
77
|
+
await cp(source, candidate, {recursive: true});
|
|
78
|
+
if (!sameHashes(sourceHashes, await hashTree(candidate))) throw new Error("Skill copy integrity check failed.");
|
|
79
|
+
const old = `${candidate}-old`;
|
|
80
|
+
if (stat) await rename(target, old);
|
|
81
|
+
try { await rename(candidate, target); }
|
|
82
|
+
catch (error) { if (stat) await rename(old, target); throw error; }
|
|
83
|
+
candidate = undefined;
|
|
84
|
+
// Delete only the relocated, backed-up directory inside this Agent's skills directory.
|
|
85
|
+
if (stat && backup && dirname(resolve(old)) === resolve(agent.directory)) await rm(old, {recursive: true});
|
|
86
|
+
if (!sameHashes(sourceHashes, await hashTree(target))) throw new Error("Installed Skill integrity check failed.");
|
|
87
|
+
results.push({agent: agent.id, path: target, status: "installed", hashes: sourceHashes, ...(backup ? {backup} : {})});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
results.push({agent: agent.id, path: target, status: "failed", error: error.message, ...(backup ? {backup} : {})});
|
|
90
|
+
} finally {
|
|
91
|
+
if (candidate && dirname(resolve(candidate)) === resolve(agent.directory)) await rm(candidate, {recursive: true, force: true});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
# 开发与验收
|
|
2
|
-
|
|
3
|
-
本文件用于生成项目的独立验收,无需 CLI 源仓库。测试夹具、真实开发身份和生产访问者身份分别记录,不能互相代替。协议以[数据契约](data-contract.md)、[筛选](filters.md)和[认证部署](auth-and-deploy.md)为准。
|
|
4
|
-
|
|
5
|
-
## 1. 绑定与设计准备
|
|
6
|
-
|
|
7
|
-
先记录以下最小清单,证据与临时文件放项目 `temp/`;不记录密码、token 或 Cookie。
|
|
8
|
-
|
|
9
|
-
| 项目 | 核实内容 |
|
|
10
|
-
|---|---|
|
|
11
|
-
| 来源 | CLI profile、目标地址、dashboardId、目录入口或分析主题;板内实例 entryId |
|
|
12
|
-
| 字段与指标 | queryFields.dId、选定 datasetId、维度/指标、公式或聚合、单位;记录数不能自动解释为去重对象数 |
|
|
13
|
-
| 字段选择 | 常规绑定省略 dimensionIds;配置时核对完整白名单与输出列,分别验证省略、维度加指标、仅指标和空列表;同实例不同展示绑定分别核对请求 |
|
|
14
|
-
| 时间 | 时间粒度、原值编码、显示时区;日期条件与时间戳轴标签分开核实 |
|
|
15
|
-
| 筛选 | 真实控件名、类型、默认行为、候选项来源、组件作用范围;无源控件时不添加服务端筛选 |
|
|
16
|
-
| 范围 | 返回行数、hasNext、normalization、warnings;不根据首页推算全量 |
|
|
17
|
-
| 设计 | 使用者和主要决策、首屏重点、导航/分组/密度,与既有布局的区别 |
|
|
18
|
-
|
|
19
|
-
清单先覆盖最小绑定,扩展组件时逐项补齐;不必先完成整板配置。证据不足时说明未知项,继续不依赖该项的工作。
|
|
20
|
-
|
|
21
|
-
### 1.1 最小真实查询
|
|
22
|
-
|
|
23
|
-
在配置整页组件之前,先验证开发页面的真实取数链路:
|
|
24
|
-
|
|
25
|
-
1. 用同一来源的 CLI info/data 选择一个模板支持且有可核对数据的组件,例如单行 KPI;检查 resultType、normalization、warnings、range 和结果字段,不按标题或 chartType 判断可用性。CLI 查询成功仅用于准备绑定,不能证明浏览器适配和开发身份可用。
|
|
26
|
-
2. 在 public/app-config.json 中只填写该组件的真实绑定及必要配置;目录来源保留 directoryEntryId,需要字段选择时保留相同 dimensionIds。不要先复制整页占位组件,也不为测试凭空创建源指标或控件。
|
|
27
|
-
3. 按 [README 开始](../README.md#开始)安装依赖、配置开发身份并运行 npm run dev。打开实际应用,通过开发代理触发原生查询;优先复用已有会话,需要登录时遵循[本地开发认证](auth-and-deploy.md#本地开发),不要把 CLI Access Key 当作会话 token,也不要在已有会话可用时重复索要密码。
|
|
28
|
-
4. 核对请求来源和参数、业务响应、适配状态与页面显示值。单凭 HTTP 200、CLI 成功或合成验收页 PASS 不算通过;空结果只能证明当前空态,需另选有可核对数据的组件或条件验证值的消费。脱敏证据放项目 temp/,不得记录凭证。
|
|
29
|
-
5. 该组件通过后,按本页需求补齐一个指标和一张图的代表性绑定;源中不存在或本页不需要的类型注明不适用。有真实筛选时验证“源结果 → 页面值 → 应用条件 → 恢复保存默认”,确认请求及显示与条件一致。完成这些适用检查后再扩展整页,并继续验证新增绑定。
|
|
30
|
-
|
|
31
|
-
身份、权限、接口或适配失败时,记录失败层与原因,先解决当前链路再扩大绑定;缺少访问条件时可继续不依赖真实数据的设计工作,但真实查询须标记未验证。开发身份通过不代表生产 Cookie 验证通过,身份边界见第 4 节。
|
|
32
|
-
|
|
33
|
-
## 2. 本地自动检查
|
|
34
|
-
|
|
35
|
-
1. 首次安装使用 `npm ci`。
|
|
36
|
-
2. `npm test` 验证已覆盖的数据、配置、认证、交互逻辑和分包行为。
|
|
37
|
-
3. `npm run build` 完成类型检查与生产构建。
|
|
38
|
-
4. `npm run test:browser` 启动独立浏览器验收页,打开终端给出的本机地址。选择布局后运行检查;按第 3 节调整浏览器视口并重复运行。页面必须显示 PASS,FAIL 或未完成不能视为通过。
|
|
39
|
-
|
|
40
|
-
浏览器验收页只使用 `tests/browser/` 中的合成响应,复用实际 App、查询编码、适配器和图表组件;不读取 `.env.local`、不使用开发代理、不访问 FineBI。它检查图形实际绘制、运行错误、筛选草稿/应用/恢复、目录入口与组件作用范围、空/部分/失败状态、单项重试和组件边界。截图判断、真实权限、生产部署和未覆盖控件仍需人工或对应专项验证。
|
|
41
|
-
|
|
42
|
-
测试页和夹具不得复制到 public/ 或生产配置。`npm run build` 只构建正式入口;浏览器测试服务仅在回环地址使用,完成后停止。
|
|
43
|
-
|
|
44
|
-
## 3. 浏览器视觉与交互
|
|
45
|
-
|
|
46
|
-
检查实际应用整页,包括首屏、图表中段、最后一行和明细。推荐 1440、1024、390px 视口;记录实际宽度,不把桌面缩放当成小屏验证。共享组件改变时至少覆盖 overview、workbench、cockpit、retail;只改某布局样式时重点验证该布局及相邻断点。
|
|
47
|
-
|
|
48
|
-
- 正常/空结果、部分适配、截断、受限值、失败与重试有清楚状态,失败不保留旧值充当最新结果。
|
|
49
|
-
- 图表画布有实际内容,控制台没有新增运行错误或图表模块缺失告警;图例、轴标签、大数值和长标题不裁切。
|
|
50
|
-
- 检查实际组件数量,同时用奇数/偶数组合观察排列;无异常空洞、重叠和页面横向溢出。表格内部滚动允许存在。
|
|
51
|
-
- 逐个点击页内导航并滚动到页面底部,确认导航仍可操作、目标标题不被遮挡;retail 同时检查桌面单行与窄屏两行导航,以及返回经营概览。
|
|
52
|
-
- 草稿不触发查询,应用后核对请求及页面值;恢复默认按源保存条件重新查询。检查键盘焦点、窄屏控件、单组件失败与重试;有年月/区间等控件时验证其实际操作。
|
|
53
|
-
- 展开范围和适配说明,确认技术详情可读,影响业务判断的限制没有被隐藏。
|
|
54
|
-
|
|
55
|
-
自动边界检查不能判断所有视觉问题。保存有上下文的截图,并人工检查留白、密度、文字和绘图质量。
|
|
56
|
-
|
|
57
|
-
## 4. 真实取数与身份
|
|
58
|
-
|
|
59
|
-
| 验证层 | 必须记录的证据 | 不证明什么 |
|
|
60
|
-
|---|---|---|
|
|
61
|
-
| CLI | 同一 profile 的资源、字段与查询结果 | 浏览器身份或原生查询接口可用 |
|
|
62
|
-
| 开发页面 | 脱敏请求参数、真实返回、页面值;应用/恢复条件的前后对照 | 所有生产用户均有权限 |
|
|
63
|
-
| 生产 Cookie | 部署后的同源静态页面,目标访问者身份及目录入口下的取数、失效和无权限表现 | 其他账号、SSO 环境或部署拓扑也可用 |
|
|
64
|
-
|
|
65
|
-
目录来源检查每次查询保留 reportEntryId。存在过滤作用范围差异时同时检查受影响和不受影响组件。不要仅用 HTTP 200、组件数量或 CLI 返回证明页面值正确。生产环境未提供时明确写“未验证”,不为完成验收新增部署或扩大权限。
|
|
66
|
-
|
|
67
|
-
## 5. 交付记录
|
|
68
|
-
|
|
69
|
-
记录应用路径/启动命令、CLI 与模板版本、绑定来源和口径、改动范围,以及下表。结果使用“通过 / 失败 / 未验证 / 不适用”,附原因和证据路径。
|
|
70
|
-
|
|
71
|
-
| 项目 | 结果 | 证据或限制 |
|
|
72
|
-
|---|---|---|
|
|
73
|
-
| 本地测试 / 类型检查 / 构建 | 待记录 | 命令、退出码与日志 |
|
|
74
|
-
| 浏览器夹具 | 待记录 | 布局、实际视口、PASS/FAIL 与截图 |
|
|
75
|
-
| 真实开发取数 / 筛选 / 恢复 | 待记录 | 请求和显示值对照,未覆盖控件 |
|
|
76
|
-
| 生产 Cookie / 权限 | 待记录 | 环境、身份范围;未部署注明未验证 |
|
|
77
|
-
| 整页视觉 / 键盘 | 待记录 | 桌面与小屏截图、人工检查结果 |
|
|
78
|
-
| 交付包 | 待记录 | 包含同一次构建的 dist;排除 .env*、temp、node_modules、凭证和抓取样本 |
|
|
79
|
-
|
|
80
|
-
修复后重新执行受影响检查。既有项目不会随模板自动升级;记录采用的模板版本和本次应用的修复,保留业务绑定与本地凭证。
|
|
1
|
+
# 开发与验收
|
|
2
|
+
|
|
3
|
+
本文件用于生成项目的独立验收,无需 CLI 源仓库。测试夹具、真实开发身份和生产访问者身份分别记录,不能互相代替。协议以[数据契约](data-contract.md)、[筛选](filters.md)和[认证部署](auth-and-deploy.md)为准。
|
|
4
|
+
|
|
5
|
+
## 1. 绑定与设计准备
|
|
6
|
+
|
|
7
|
+
先记录以下最小清单,证据与临时文件放项目 `temp/`;不记录密码、token 或 Cookie。
|
|
8
|
+
|
|
9
|
+
| 项目 | 核实内容 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| 来源 | CLI profile、目标地址、dashboardId、目录入口或分析主题;板内实例 entryId |
|
|
12
|
+
| 字段与指标 | queryFields.dId、选定 datasetId、维度/指标、公式或聚合、单位;记录数不能自动解释为去重对象数 |
|
|
13
|
+
| 字段选择 | 常规绑定省略 dimensionIds;配置时核对完整白名单与输出列,分别验证省略、维度加指标、仅指标和空列表;同实例不同展示绑定分别核对请求 |
|
|
14
|
+
| 时间 | 时间粒度、原值编码、显示时区;日期条件与时间戳轴标签分开核实 |
|
|
15
|
+
| 筛选 | 真实控件名、类型、默认行为、候选项来源、组件作用范围;无源控件时不添加服务端筛选 |
|
|
16
|
+
| 范围 | 返回行数、hasNext、normalization、warnings;不根据首页推算全量 |
|
|
17
|
+
| 设计 | 使用者和主要决策、首屏重点、导航/分组/密度,与既有布局的区别 |
|
|
18
|
+
|
|
19
|
+
清单先覆盖最小绑定,扩展组件时逐项补齐;不必先完成整板配置。证据不足时说明未知项,继续不依赖该项的工作。
|
|
20
|
+
|
|
21
|
+
### 1.1 最小真实查询
|
|
22
|
+
|
|
23
|
+
在配置整页组件之前,先验证开发页面的真实取数链路:
|
|
24
|
+
|
|
25
|
+
1. 用同一来源的 CLI info/data 选择一个模板支持且有可核对数据的组件,例如单行 KPI;检查 resultType、normalization、warnings、range 和结果字段,不按标题或 chartType 判断可用性。CLI 查询成功仅用于准备绑定,不能证明浏览器适配和开发身份可用。
|
|
26
|
+
2. 在 public/app-config.json 中只填写该组件的真实绑定及必要配置;目录来源保留 directoryEntryId,需要字段选择时保留相同 dimensionIds。不要先复制整页占位组件,也不为测试凭空创建源指标或控件。
|
|
27
|
+
3. 按 [README 开始](../README.md#开始)安装依赖、配置开发身份并运行 npm run dev。打开实际应用,通过开发代理触发原生查询;优先复用已有会话,需要登录时遵循[本地开发认证](auth-and-deploy.md#本地开发),不要把 CLI Access Key 当作会话 token,也不要在已有会话可用时重复索要密码。
|
|
28
|
+
4. 核对请求来源和参数、业务响应、适配状态与页面显示值。单凭 HTTP 200、CLI 成功或合成验收页 PASS 不算通过;空结果只能证明当前空态,需另选有可核对数据的组件或条件验证值的消费。脱敏证据放项目 temp/,不得记录凭证。
|
|
29
|
+
5. 该组件通过后,按本页需求补齐一个指标和一张图的代表性绑定;源中不存在或本页不需要的类型注明不适用。有真实筛选时验证“源结果 → 页面值 → 应用条件 → 恢复保存默认”,确认请求及显示与条件一致。完成这些适用检查后再扩展整页,并继续验证新增绑定。
|
|
30
|
+
|
|
31
|
+
身份、权限、接口或适配失败时,记录失败层与原因,先解决当前链路再扩大绑定;缺少访问条件时可继续不依赖真实数据的设计工作,但真实查询须标记未验证。开发身份通过不代表生产 Cookie 验证通过,身份边界见第 4 节。
|
|
32
|
+
|
|
33
|
+
## 2. 本地自动检查
|
|
34
|
+
|
|
35
|
+
1. 首次安装使用 `npm ci`。
|
|
36
|
+
2. `npm test` 验证已覆盖的数据、配置、认证、交互逻辑和分包行为。
|
|
37
|
+
3. `npm run build` 完成类型检查与生产构建。
|
|
38
|
+
4. `npm run test:browser` 启动独立浏览器验收页,打开终端给出的本机地址。选择布局后运行检查;按第 3 节调整浏览器视口并重复运行。页面必须显示 PASS,FAIL 或未完成不能视为通过。
|
|
39
|
+
|
|
40
|
+
浏览器验收页只使用 `tests/browser/` 中的合成响应,复用实际 App、查询编码、适配器和图表组件;不读取 `.env.local`、不使用开发代理、不访问 FineBI。它检查图形实际绘制、运行错误、筛选草稿/应用/恢复、目录入口与组件作用范围、空/部分/失败状态、单项重试和组件边界。截图判断、真实权限、生产部署和未覆盖控件仍需人工或对应专项验证。
|
|
41
|
+
|
|
42
|
+
测试页和夹具不得复制到 public/ 或生产配置。`npm run build` 只构建正式入口;浏览器测试服务仅在回环地址使用,完成后停止。
|
|
43
|
+
|
|
44
|
+
## 3. 浏览器视觉与交互
|
|
45
|
+
|
|
46
|
+
检查实际应用整页,包括首屏、图表中段、最后一行和明细。推荐 1440、1024、390px 视口;记录实际宽度,不把桌面缩放当成小屏验证。共享组件改变时至少覆盖 overview、workbench、cockpit、retail;只改某布局样式时重点验证该布局及相邻断点。
|
|
47
|
+
|
|
48
|
+
- 正常/空结果、部分适配、截断、受限值、失败与重试有清楚状态,失败不保留旧值充当最新结果。
|
|
49
|
+
- 图表画布有实际内容,控制台没有新增运行错误或图表模块缺失告警;图例、轴标签、大数值和长标题不裁切。
|
|
50
|
+
- 检查实际组件数量,同时用奇数/偶数组合观察排列;无异常空洞、重叠和页面横向溢出。表格内部滚动允许存在。
|
|
51
|
+
- 逐个点击页内导航并滚动到页面底部,确认导航仍可操作、目标标题不被遮挡;retail 同时检查桌面单行与窄屏两行导航,以及返回经营概览。
|
|
52
|
+
- 草稿不触发查询,应用后核对请求及页面值;恢复默认按源保存条件重新查询。检查键盘焦点、窄屏控件、单组件失败与重试;有年月/区间等控件时验证其实际操作。
|
|
53
|
+
- 展开范围和适配说明,确认技术详情可读,影响业务判断的限制没有被隐藏。
|
|
54
|
+
|
|
55
|
+
自动边界检查不能判断所有视觉问题。保存有上下文的截图,并人工检查留白、密度、文字和绘图质量。
|
|
56
|
+
|
|
57
|
+
## 4. 真实取数与身份
|
|
58
|
+
|
|
59
|
+
| 验证层 | 必须记录的证据 | 不证明什么 |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| CLI | 同一 profile 的资源、字段与查询结果 | 浏览器身份或原生查询接口可用 |
|
|
62
|
+
| 开发页面 | 脱敏请求参数、真实返回、页面值;应用/恢复条件的前后对照 | 所有生产用户均有权限 |
|
|
63
|
+
| 生产 Cookie | 部署后的同源静态页面,目标访问者身份及目录入口下的取数、失效和无权限表现 | 其他账号、SSO 环境或部署拓扑也可用 |
|
|
64
|
+
|
|
65
|
+
目录来源检查每次查询保留 reportEntryId。存在过滤作用范围差异时同时检查受影响和不受影响组件。不要仅用 HTTP 200、组件数量或 CLI 返回证明页面值正确。生产环境未提供时明确写“未验证”,不为完成验收新增部署或扩大权限。
|
|
66
|
+
|
|
67
|
+
## 5. 交付记录
|
|
68
|
+
|
|
69
|
+
记录应用路径/启动命令、CLI 与模板版本、绑定来源和口径、改动范围,以及下表。结果使用“通过 / 失败 / 未验证 / 不适用”,附原因和证据路径。
|
|
70
|
+
|
|
71
|
+
| 项目 | 结果 | 证据或限制 |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| 本地测试 / 类型检查 / 构建 | 待记录 | 命令、退出码与日志 |
|
|
74
|
+
| 浏览器夹具 | 待记录 | 布局、实际视口、PASS/FAIL 与截图 |
|
|
75
|
+
| 真实开发取数 / 筛选 / 恢复 | 待记录 | 请求和显示值对照,未覆盖控件 |
|
|
76
|
+
| 生产 Cookie / 权限 | 待记录 | 环境、身份范围;未部署注明未验证 |
|
|
77
|
+
| 整页视觉 / 键盘 | 待记录 | 桌面与小屏截图、人工检查结果 |
|
|
78
|
+
| 交付包 | 待记录 | 包含同一次构建的 dist;排除 .env*、temp、node_modules、凭证和抓取样本 |
|
|
79
|
+
|
|
80
|
+
修复后重新执行受影响检查。既有项目不会随模板自动升级;记录采用的模板版本和本次应用的修复,保留业务绑定与本地凭证。
|
package/skills/finebi-cli-agent/scripts/finebi-cli/templates/web-app/examples/cockpit.config.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schemaVersion": "1",
|
|
3
|
-
"title": "经营概览",
|
|
4
|
-
"description": "资源绑定示例:替换所有 REPLACE_*,不包含业务数据",
|
|
5
|
-
"basePath": "/webroot/decision",
|
|
6
|
-
"layout": "cockpit",
|
|
7
|
-
"dashboardId": "REPLACE_DASHBOARD_ID",
|
|
8
|
-
"maxRows": 1000,
|
|
9
|
-
"pageSize": 8,
|
|
10
|
-
"insights": true,
|
|
11
|
-
"dataNotes": ["请填写经过核实的数据单位、组件口径与筛选作用范围。"],
|
|
12
|
-
"widgets": [
|
|
13
|
-
{"entryId":"REPLACE_KPI_1", "name":"指标一", "type":"kpi", "valueFieldId":"REPLACE_VALUE_1", "filterNames":["REPLACE_MONTH_CONTROL"]},
|
|
14
|
-
{"entryId":"REPLACE_KPI_2", "name":"指标二", "type":"kpi", "valueFieldId":"REPLACE_VALUE_2", "filterNames":[]},
|
|
15
|
-
{"entryId":"REPLACE_KPI_3", "name":"指标三", "type":"kpi", "valueFieldId":"REPLACE_VALUE_3", "filterNames":[]},
|
|
16
|
-
{"entryId":"REPLACE_KPI_4", "name":"指标四", "type":"kpi", "valueFieldId":"REPLACE_VALUE_4", "filterNames":[]},
|
|
17
|
-
{"entryId":"REPLACE_TREND", "name":"年度趋势", "type":"line", "categoryFieldId":"REPLACE_TIME_FIELD", "series":[{"fieldId":"REPLACE_MEASURE_A", "label":"指标 A"},{"fieldId":"REPLACE_MEASURE_B", "label":"指标 B"}], "filterNames":[]},
|
|
18
|
-
{"entryId":"REPLACE_COMPARISON", "name":"分类对比", "type":"bar", "categoryFieldId":"REPLACE_CATEGORY_FIELD", "valueFieldId":"REPLACE_MEASURE", "filterNames":[]},
|
|
19
|
-
{"entryId":"REPLACE_TABLE", "name":"分组明细", "type":"table", "tableFieldIds":["REPLACE_GROUP_FIELD","REPLACE_MEASURE"], "localFilterFieldIds":["REPLACE_GROUP_FIELD"], "filterNames":["REPLACE_MONTH_CONTROL"]}
|
|
20
|
-
],
|
|
21
|
-
"filters": [{"name":"REPLACE_MONTH_CONTROL", "label":"年月", "type":"month"}]
|
|
22
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1",
|
|
3
|
+
"title": "经营概览",
|
|
4
|
+
"description": "资源绑定示例:替换所有 REPLACE_*,不包含业务数据",
|
|
5
|
+
"basePath": "/webroot/decision",
|
|
6
|
+
"layout": "cockpit",
|
|
7
|
+
"dashboardId": "REPLACE_DASHBOARD_ID",
|
|
8
|
+
"maxRows": 1000,
|
|
9
|
+
"pageSize": 8,
|
|
10
|
+
"insights": true,
|
|
11
|
+
"dataNotes": ["请填写经过核实的数据单位、组件口径与筛选作用范围。"],
|
|
12
|
+
"widgets": [
|
|
13
|
+
{"entryId":"REPLACE_KPI_1", "name":"指标一", "type":"kpi", "valueFieldId":"REPLACE_VALUE_1", "filterNames":["REPLACE_MONTH_CONTROL"]},
|
|
14
|
+
{"entryId":"REPLACE_KPI_2", "name":"指标二", "type":"kpi", "valueFieldId":"REPLACE_VALUE_2", "filterNames":[]},
|
|
15
|
+
{"entryId":"REPLACE_KPI_3", "name":"指标三", "type":"kpi", "valueFieldId":"REPLACE_VALUE_3", "filterNames":[]},
|
|
16
|
+
{"entryId":"REPLACE_KPI_4", "name":"指标四", "type":"kpi", "valueFieldId":"REPLACE_VALUE_4", "filterNames":[]},
|
|
17
|
+
{"entryId":"REPLACE_TREND", "name":"年度趋势", "type":"line", "categoryFieldId":"REPLACE_TIME_FIELD", "series":[{"fieldId":"REPLACE_MEASURE_A", "label":"指标 A"},{"fieldId":"REPLACE_MEASURE_B", "label":"指标 B"}], "filterNames":[]},
|
|
18
|
+
{"entryId":"REPLACE_COMPARISON", "name":"分类对比", "type":"bar", "categoryFieldId":"REPLACE_CATEGORY_FIELD", "valueFieldId":"REPLACE_MEASURE", "filterNames":[]},
|
|
19
|
+
{"entryId":"REPLACE_TABLE", "name":"分组明细", "type":"table", "tableFieldIds":["REPLACE_GROUP_FIELD","REPLACE_MEASURE"], "localFilterFieldIds":["REPLACE_GROUP_FIELD"], "filterNames":["REPLACE_MONTH_CONTROL"]}
|
|
20
|
+
],
|
|
21
|
+
"filters": [{"name":"REPLACE_MONTH_CONTROL", "label":"年月", "type":"month"}]
|
|
22
|
+
}
|