@josephyan/qingflow-cli 1.1.8 → 1.1.9
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 +77 -8
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.9
|
|
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.9 qingflow
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -5999,6 +5999,20 @@ class AiBuilderFacade:
|
|
|
5999
5999
|
result["message"] = "read app chart config"
|
|
6000
6000
|
return result
|
|
6001
6001
|
|
|
6002
|
+
def _chart_filter_field_names_by_id(
|
|
6003
|
+
self,
|
|
6004
|
+
*,
|
|
6005
|
+
profile: str,
|
|
6006
|
+
app_key: str,
|
|
6007
|
+
) -> tuple[dict[str, str], dict[str, Any] | None]:
|
|
6008
|
+
try:
|
|
6009
|
+
state = self._load_base_schema_state(profile=profile, app_key=app_key)
|
|
6010
|
+
except (QingflowApiError, RuntimeError) as error:
|
|
6011
|
+
api_error = _coerce_api_error(error)
|
|
6012
|
+
return {}, _transport_error_payload(api_error)
|
|
6013
|
+
fields = cast(list[dict[str, Any]], state["parsed"]["fields"])
|
|
6014
|
+
return _chart_field_names_by_id_from_public_fields(app_key=app_key, fields=fields), None
|
|
6015
|
+
|
|
6002
6016
|
def app_get_buttons(self, *, profile: str, app_key: str) -> JSONObject:
|
|
6003
6017
|
self.apps._require_app_key(app_key)
|
|
6004
6018
|
warnings: list[dict[str, Any]] = []
|
|
@@ -6525,6 +6539,7 @@ class AiBuilderFacade:
|
|
|
6525
6539
|
charts = _summarize_charts(items)
|
|
6526
6540
|
chart_visibility_read_errors: list[dict[str, Any]] = []
|
|
6527
6541
|
chart_config_read_errors: list[dict[str, Any]] = []
|
|
6542
|
+
field_name_by_id, field_name_read_error = self._chart_filter_field_names_by_id(profile=profile, app_key=resolved_app_key)
|
|
6528
6543
|
for chart in charts:
|
|
6529
6544
|
chart_id = str(chart.get("chart_id") or "").strip()
|
|
6530
6545
|
if not chart_id:
|
|
@@ -6564,7 +6579,7 @@ class AiBuilderFacade:
|
|
|
6564
6579
|
if isinstance(config, dict):
|
|
6565
6580
|
chart["group_by"] = _public_chart_group_by_from_qingbi_config(config)
|
|
6566
6581
|
chart["metrics"] = _public_chart_metrics_from_qingbi_config(config)
|
|
6567
|
-
chart["filters"] = _public_chart_filter_groups_from_qingbi_config(config)
|
|
6582
|
+
chart["filters"] = _public_chart_filter_groups_from_qingbi_config(config, field_name_by_id=field_name_by_id)
|
|
6568
6583
|
response = AppChartsReadResponse(
|
|
6569
6584
|
app_key=resolved_app_key,
|
|
6570
6585
|
charts=charts,
|
|
@@ -6581,6 +6596,7 @@ class AiBuilderFacade:
|
|
|
6581
6596
|
"details": {
|
|
6582
6597
|
**({"chart_visibility_read_errors": chart_visibility_read_errors} if chart_visibility_read_errors else {}),
|
|
6583
6598
|
**({"chart_config_read_errors": chart_config_read_errors} if chart_config_read_errors else {}),
|
|
6599
|
+
**({"chart_filter_field_name_read_error": field_name_read_error} if field_name_read_error else {}),
|
|
6584
6600
|
},
|
|
6585
6601
|
"request_id": None,
|
|
6586
6602
|
"suggested_next_call": None,
|
|
@@ -6597,6 +6613,11 @@ class AiBuilderFacade:
|
|
|
6597
6613
|
if chart_config_read_errors
|
|
6598
6614
|
else []
|
|
6599
6615
|
)
|
|
6616
|
+
+ (
|
|
6617
|
+
[_warning("CHART_FILTER_FIELD_NAMES_UNRESOLVED", "chart configs were read, but form fields could not be loaded to resolve filter field names")]
|
|
6618
|
+
if field_name_read_error
|
|
6619
|
+
else []
|
|
6620
|
+
)
|
|
6600
6621
|
),
|
|
6601
6622
|
"verification": {
|
|
6602
6623
|
"app_exists": True,
|
|
@@ -6604,8 +6625,9 @@ class AiBuilderFacade:
|
|
|
6604
6625
|
"chart_list_source": list_source,
|
|
6605
6626
|
"chart_visibility_readback_complete": not chart_visibility_read_errors,
|
|
6606
6627
|
"chart_config_readback_complete": not chart_config_read_errors,
|
|
6628
|
+
"chart_filter_field_names_resolved": not field_name_read_error,
|
|
6607
6629
|
},
|
|
6608
|
-
"verified": not chart_config_read_errors,
|
|
6630
|
+
"verified": not chart_config_read_errors and not field_name_read_error,
|
|
6609
6631
|
**response.model_dump(mode="json"),
|
|
6610
6632
|
}
|
|
6611
6633
|
|
|
@@ -7803,11 +7825,24 @@ class AiBuilderFacade:
|
|
|
7803
7825
|
suggested_next_call={"tool_name": "chart_get", "arguments": {"profile": profile, "chart_id": chart_id}},
|
|
7804
7826
|
)
|
|
7805
7827
|
|
|
7828
|
+
field_name_by_id: dict[str, str] = {}
|
|
7829
|
+
data_source = config.get("dataSource") if isinstance(config.get("dataSource"), dict) else {}
|
|
7830
|
+
data_source_app_key = str(data_source.get("dataSourceId") or config.get("dataSourceId") or "").strip()
|
|
7831
|
+
if data_source_app_key:
|
|
7832
|
+
field_name_by_id, field_name_error = self._chart_filter_field_names_by_id(profile=profile, app_key=data_source_app_key)
|
|
7833
|
+
if field_name_error:
|
|
7834
|
+
warnings.append(
|
|
7835
|
+
_warning(
|
|
7836
|
+
"CHART_FILTER_FIELD_NAMES_UNRESOLVED",
|
|
7837
|
+
"chart config was read, but form fields could not be loaded to resolve filter field names",
|
|
7838
|
+
**field_name_error,
|
|
7839
|
+
)
|
|
7840
|
+
)
|
|
7806
7841
|
response = ChartGetResponse(
|
|
7807
7842
|
chart_id=chart_id,
|
|
7808
7843
|
base=deepcopy(base) if isinstance(base, dict) else {},
|
|
7809
7844
|
visibility=_public_visibility_from_chart_visible_auth(base.get("visibleAuth")),
|
|
7810
|
-
filters=_public_chart_filter_groups_from_qingbi_config(config) if isinstance(config, dict) else [],
|
|
7845
|
+
filters=_public_chart_filter_groups_from_qingbi_config(config, field_name_by_id=field_name_by_id) if isinstance(config, dict) else [],
|
|
7811
7846
|
group_by=_public_chart_group_by_from_qingbi_config(config) if isinstance(config, dict) else [],
|
|
7812
7847
|
metrics=_public_chart_metrics_from_qingbi_config(config) if isinstance(config, dict) else [],
|
|
7813
7848
|
config=deepcopy(config) if isinstance(config, dict) else {},
|
|
@@ -16316,11 +16351,38 @@ def _qingbi_chart_filter_value_to_text(*, value: Any, form_field: dict[str, Any]
|
|
|
16316
16351
|
reject(value)
|
|
16317
16352
|
|
|
16318
16353
|
|
|
16319
|
-
def
|
|
16354
|
+
def _chart_field_names_by_id_from_public_fields(*, app_key: str, fields: list[dict[str, Any]]) -> dict[str, str]:
|
|
16355
|
+
field_name_by_id: dict[str, str] = {}
|
|
16356
|
+
for field in fields:
|
|
16357
|
+
if not isinstance(field, dict):
|
|
16358
|
+
continue
|
|
16359
|
+
name = str(field.get("name") or "").strip()
|
|
16360
|
+
if not name:
|
|
16361
|
+
continue
|
|
16362
|
+
que_id = field.get("que_id")
|
|
16363
|
+
field_id = str(field.get("field_id") or "").strip()
|
|
16364
|
+
for raw_key in (
|
|
16365
|
+
que_id,
|
|
16366
|
+
field_id,
|
|
16367
|
+
f"{app_key}:{que_id}" if que_id is not None else None,
|
|
16368
|
+
f"{app_key}:{field_id}" if field_id else None,
|
|
16369
|
+
):
|
|
16370
|
+
key = str(raw_key or "").strip()
|
|
16371
|
+
if key:
|
|
16372
|
+
field_name_by_id.setdefault(key, name)
|
|
16373
|
+
return field_name_by_id
|
|
16374
|
+
|
|
16375
|
+
|
|
16376
|
+
def _public_chart_filter_groups_from_qingbi_config(
|
|
16377
|
+
config: dict[str, Any],
|
|
16378
|
+
*,
|
|
16379
|
+
field_name_by_id: dict[str, str] | None = None,
|
|
16380
|
+
) -> list[list[dict[str, Any]]]:
|
|
16320
16381
|
groups: list[list[dict[str, Any]]] = []
|
|
16321
16382
|
raw_groups = config.get("beforeAggregationFilterMatrix")
|
|
16322
16383
|
if not isinstance(raw_groups, list):
|
|
16323
16384
|
return groups
|
|
16385
|
+
resolved_field_name_by_id = field_name_by_id or {}
|
|
16324
16386
|
for raw_group in raw_groups:
|
|
16325
16387
|
if not isinstance(raw_group, list):
|
|
16326
16388
|
continue
|
|
@@ -16330,19 +16392,26 @@ def _public_chart_filter_groups_from_qingbi_config(config: dict[str, Any]) -> li
|
|
|
16330
16392
|
continue
|
|
16331
16393
|
operator = _public_chart_filter_operator_from_judge_type(raw_rule.get("judgeType"))
|
|
16332
16394
|
field_id = raw_rule.get("fieldId") or raw_rule.get("field_id")
|
|
16333
|
-
|
|
16395
|
+
field_id_text = _stringify_condition_value(field_id).strip() if field_id is not None else ""
|
|
16396
|
+
raw_field_name = (
|
|
16334
16397
|
raw_rule.get("fieldName")
|
|
16335
16398
|
or raw_rule.get("field_name")
|
|
16336
16399
|
or raw_rule.get("queTitle")
|
|
16337
16400
|
or raw_rule.get("title")
|
|
16338
|
-
|
|
16401
|
+
)
|
|
16402
|
+
raw_field_name_text = _stringify_condition_value(raw_field_name).strip()
|
|
16403
|
+
field_name = (
|
|
16404
|
+
resolved_field_name_by_id.get(raw_field_name_text)
|
|
16405
|
+
or resolved_field_name_by_id.get(field_id_text)
|
|
16406
|
+
or raw_field_name_text
|
|
16407
|
+
or field_id_text
|
|
16339
16408
|
)
|
|
16340
16409
|
public_rule: dict[str, Any] = {
|
|
16341
|
-
"field_name":
|
|
16410
|
+
"field_name": field_name,
|
|
16342
16411
|
"operator": operator,
|
|
16343
16412
|
}
|
|
16344
16413
|
if field_id is not None:
|
|
16345
|
-
public_rule["field_id"] =
|
|
16414
|
+
public_rule["field_id"] = field_id_text
|
|
16346
16415
|
values = _public_chart_filter_values_from_rule(raw_rule, operator=operator)
|
|
16347
16416
|
if values:
|
|
16348
16417
|
public_rule["values"] = values
|