@josephyan/qingflow-cli 1.1.7 → 1.1.8
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 +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +89 -4
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-cli@1.1.
|
|
6
|
+
npm install @josephyan/qingflow-cli@1.1.8
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-cli@1.1.
|
|
12
|
+
npx -y -p @josephyan/qingflow-cli@1.1.8 qingflow
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -6524,6 +6524,7 @@ class AiBuilderFacade:
|
|
|
6524
6524
|
)
|
|
6525
6525
|
charts = _summarize_charts(items)
|
|
6526
6526
|
chart_visibility_read_errors: list[dict[str, Any]] = []
|
|
6527
|
+
chart_config_read_errors: list[dict[str, Any]] = []
|
|
6527
6528
|
for chart in charts:
|
|
6528
6529
|
chart_id = str(chart.get("chart_id") or "").strip()
|
|
6529
6530
|
if not chart_id:
|
|
@@ -6546,6 +6547,24 @@ class AiBuilderFacade:
|
|
|
6546
6547
|
base_info.get("visibleAuth") if isinstance(base_info, dict) else None
|
|
6547
6548
|
)
|
|
6548
6549
|
)
|
|
6550
|
+
try:
|
|
6551
|
+
config_response = self.charts.qingbi_report_get_config(profile=profile, chart_id=chart_id)
|
|
6552
|
+
config = config_response.get("result") or {}
|
|
6553
|
+
except (QingflowApiError, RuntimeError) as error:
|
|
6554
|
+
api_error = _coerce_api_error(error)
|
|
6555
|
+
chart_config_read_errors.append(
|
|
6556
|
+
{
|
|
6557
|
+
"chart_id": chart_id,
|
|
6558
|
+
"request_id": api_error.request_id,
|
|
6559
|
+
"http_status": api_error.http_status,
|
|
6560
|
+
"backend_code": api_error.backend_code,
|
|
6561
|
+
}
|
|
6562
|
+
)
|
|
6563
|
+
continue
|
|
6564
|
+
if isinstance(config, dict):
|
|
6565
|
+
chart["group_by"] = _public_chart_group_by_from_qingbi_config(config)
|
|
6566
|
+
chart["metrics"] = _public_chart_metrics_from_qingbi_config(config)
|
|
6567
|
+
chart["filters"] = _public_chart_filter_groups_from_qingbi_config(config)
|
|
6549
6568
|
response = AppChartsReadResponse(
|
|
6550
6569
|
app_key=resolved_app_key,
|
|
6551
6570
|
charts=charts,
|
|
@@ -6559,7 +6578,10 @@ class AiBuilderFacade:
|
|
|
6559
6578
|
"normalized_args": {"app_key": resolved_app_key},
|
|
6560
6579
|
"missing_fields": [],
|
|
6561
6580
|
"allowed_values": {},
|
|
6562
|
-
"details": {
|
|
6581
|
+
"details": {
|
|
6582
|
+
**({"chart_visibility_read_errors": chart_visibility_read_errors} if chart_visibility_read_errors else {}),
|
|
6583
|
+
**({"chart_config_read_errors": chart_config_read_errors} if chart_config_read_errors else {}),
|
|
6584
|
+
},
|
|
6563
6585
|
"request_id": None,
|
|
6564
6586
|
"suggested_next_call": None,
|
|
6565
6587
|
"noop": False,
|
|
@@ -6570,14 +6592,20 @@ class AiBuilderFacade:
|
|
|
6570
6592
|
if chart_visibility_read_errors
|
|
6571
6593
|
else []
|
|
6572
6594
|
)
|
|
6595
|
+
+ (
|
|
6596
|
+
[_warning("CHART_CONFIG_READ_PARTIAL", "some chart configs could not be read back; metrics/group_by/filters are incomplete for those charts")]
|
|
6597
|
+
if chart_config_read_errors
|
|
6598
|
+
else []
|
|
6599
|
+
)
|
|
6573
6600
|
),
|
|
6574
6601
|
"verification": {
|
|
6575
6602
|
"app_exists": True,
|
|
6576
6603
|
"chart_order_verified": list_source == "sorted",
|
|
6577
6604
|
"chart_list_source": list_source,
|
|
6578
6605
|
"chart_visibility_readback_complete": not chart_visibility_read_errors,
|
|
6606
|
+
"chart_config_readback_complete": not chart_config_read_errors,
|
|
6579
6607
|
},
|
|
6580
|
-
"verified":
|
|
6608
|
+
"verified": not chart_config_read_errors,
|
|
6581
6609
|
**response.model_dump(mode="json"),
|
|
6582
6610
|
}
|
|
6583
6611
|
|
|
@@ -23330,6 +23358,24 @@ def _extract_view_question_entries(questions: Any) -> list[dict[str, Any]]:
|
|
|
23330
23358
|
"visible": visible,
|
|
23331
23359
|
"display_order": display_order if display_order is not None else fallback_order,
|
|
23332
23360
|
}
|
|
23361
|
+
option_details: list[dict[str, Any]] = []
|
|
23362
|
+
option_values: list[str] = []
|
|
23363
|
+
raw_options = item.get("options")
|
|
23364
|
+
if isinstance(raw_options, list):
|
|
23365
|
+
for raw_option in raw_options:
|
|
23366
|
+
if not isinstance(raw_option, dict):
|
|
23367
|
+
continue
|
|
23368
|
+
option_id = raw_option.get("optId")
|
|
23369
|
+
option_value = str(raw_option.get("optValue") or "").strip()
|
|
23370
|
+
if not option_value and option_id is None:
|
|
23371
|
+
continue
|
|
23372
|
+
if option_value:
|
|
23373
|
+
option_values.append(option_value)
|
|
23374
|
+
option_details.append({"id": option_id, "value": option_value or str(option_id)})
|
|
23375
|
+
if option_values:
|
|
23376
|
+
entry["options"] = option_values
|
|
23377
|
+
if option_details:
|
|
23378
|
+
entry["option_details"] = option_details
|
|
23333
23379
|
width = _coerce_positive_int(item.get("width"))
|
|
23334
23380
|
if width is not None:
|
|
23335
23381
|
entry["width"] = width
|
|
@@ -23348,7 +23394,14 @@ def _view_field_lookup_from_question_entries(entries: list[dict[str, Any]]) -> d
|
|
|
23348
23394
|
que_id = _coerce_positive_int(entry.get("field_id") or entry.get("que_id") or entry.get("queId"))
|
|
23349
23395
|
if not name or que_id is None:
|
|
23350
23396
|
continue
|
|
23351
|
-
|
|
23397
|
+
field_entry: dict[str, Any] = {"name": name, "que_id": que_id}
|
|
23398
|
+
options = entry.get("options")
|
|
23399
|
+
if isinstance(options, list) and options:
|
|
23400
|
+
field_entry["options"] = [str(value) for value in options if str(value or "").strip()]
|
|
23401
|
+
option_details = entry.get("option_details")
|
|
23402
|
+
if isinstance(option_details, list) and option_details:
|
|
23403
|
+
field_entry["option_details"] = [deepcopy(value) for value in option_details if isinstance(value, dict)]
|
|
23404
|
+
fields_by_name.setdefault(name, field_entry)
|
|
23352
23405
|
return fields_by_name
|
|
23353
23406
|
|
|
23354
23407
|
|
|
@@ -26464,6 +26517,38 @@ def _view_filter_rule_values_for_signature(rule: dict[str, Any]) -> list[str]:
|
|
|
26464
26517
|
return fallback_values
|
|
26465
26518
|
|
|
26466
26519
|
|
|
26520
|
+
def _view_filter_option_value_by_id(field: dict[str, Any]) -> dict[str, str]:
|
|
26521
|
+
value_by_id: dict[str, str] = {}
|
|
26522
|
+
for detail in field.get("option_details") or []:
|
|
26523
|
+
if not isinstance(detail, dict):
|
|
26524
|
+
continue
|
|
26525
|
+
option_id = detail.get("id")
|
|
26526
|
+
option_value = str(detail.get("value") or "").strip()
|
|
26527
|
+
if option_id is None or not option_value:
|
|
26528
|
+
continue
|
|
26529
|
+
value_by_id[str(option_id)] = option_value
|
|
26530
|
+
return value_by_id
|
|
26531
|
+
|
|
26532
|
+
|
|
26533
|
+
def _public_view_filter_rule_values(rule: dict[str, Any], *, field: dict[str, Any]) -> list[str]:
|
|
26534
|
+
value_by_id = _view_filter_option_value_by_id(field)
|
|
26535
|
+
detail_value_by_id: dict[str, str] = {}
|
|
26536
|
+
ordered_detail_values: list[str] = []
|
|
26537
|
+
for detail in rule.get("judgeValueDetails") or []:
|
|
26538
|
+
if not isinstance(detail, dict):
|
|
26539
|
+
continue
|
|
26540
|
+
detail_value = str(detail.get("value") or "").strip()
|
|
26541
|
+
detail_id = detail.get("id")
|
|
26542
|
+
if detail_value:
|
|
26543
|
+
ordered_detail_values.append(detail_value)
|
|
26544
|
+
if detail_id is not None:
|
|
26545
|
+
detail_value_by_id[str(detail_id)] = detail_value
|
|
26546
|
+
values = [str(value) for value in (rule.get("judgeValues") or []) if str(value or "").strip()]
|
|
26547
|
+
if values:
|
|
26548
|
+
return [value_by_id.get(value) or detail_value_by_id.get(value) or value for value in values]
|
|
26549
|
+
return ordered_detail_values
|
|
26550
|
+
|
|
26551
|
+
|
|
26467
26552
|
def _view_filter_groups_signature(groups: Any) -> list[list[dict[str, Any]]]:
|
|
26468
26553
|
signature: list[list[dict[str, Any]]] = []
|
|
26469
26554
|
for group in _normalize_view_filter_groups_for_compare(groups):
|
|
@@ -26545,7 +26630,7 @@ def _public_view_filter_groups_from_match_rules(
|
|
|
26545
26630
|
for rule in group:
|
|
26546
26631
|
que_id = _coerce_positive_int(rule.get("queId")) or 0
|
|
26547
26632
|
field = fields_by_que_id.get(que_id) or {}
|
|
26548
|
-
values =
|
|
26633
|
+
values = _public_view_filter_rule_values(rule, field=field)
|
|
26549
26634
|
public_rule: dict[str, Any] = {
|
|
26550
26635
|
"field_name": str(field.get("name") or rule.get("queTitle") or que_id),
|
|
26551
26636
|
"operator": _public_view_filter_operator_from_judge_type(rule.get("judgeType")),
|