@josephyan/qingflow-cli 1.1.5 → 1.1.7

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 CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-cli@1.1.5
6
+ npm install @josephyan/qingflow-cli@1.1.7
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-cli@1.1.5 qingflow
12
+ npx -y -p @josephyan/qingflow-cli@1.1.7 qingflow
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-cli",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Human-friendly Qingflow command line interface for auth, record operations, import, tasks, and stable builder flows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "1.1.5"
7
+ version = "1.1.7"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5967,6 +5967,26 @@ class AiBuilderFacade:
5967
5967
  result["message"] = "read app view config"
5968
5968
  return result
5969
5969
 
5970
+ def _load_view_summaries_for_builder(self, *, profile: str, app_key: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
5971
+ views, views_unavailable, views_read_error = self._load_views_result(
5972
+ profile=profile,
5973
+ app_key=app_key,
5974
+ tolerate_404=True,
5975
+ tolerate_permission_restricted=True,
5976
+ include_error=True,
5977
+ )
5978
+ summaries, config_read_errors = _summarize_views_with_config(self.views, profile=profile, views=views)
5979
+ if views_unavailable and views_read_error is not None:
5980
+ config_read_errors = [
5981
+ {
5982
+ "resource": "views",
5983
+ "phase": "view_list",
5984
+ "transport_error": _transport_error_payload(views_read_error),
5985
+ },
5986
+ *config_read_errors,
5987
+ ]
5988
+ return summaries, config_read_errors
5989
+
5970
5990
  def app_get_flow(self, *, profile: str, app_key: str) -> JSONObject:
5971
5991
  result = self.app_read_flow_summary(profile=profile, app_key=app_key)
5972
5992
  if result.get("status") == "success":
@@ -23244,6 +23264,15 @@ def _merge_view_summary_with_config(
23244
23264
  question_entries_by_id=query_question_entries_by_id,
23245
23265
  )
23246
23266
  config_enriched = True
23267
+ if "viewgraphLimit" in config:
23268
+ field_lookup = _view_field_lookup_from_question_entries(
23269
+ [*question_entries, *canonical_question_entries]
23270
+ )
23271
+ summary["filters"] = _public_view_filter_groups_from_match_rules(
23272
+ config.get("viewgraphLimit"),
23273
+ current_fields_by_name=field_lookup,
23274
+ )
23275
+ config_enriched = True
23247
23276
  if any(key in config for key in ("asosChartVisible", "asosChartConfig", "asosChartIdList", "limitType")):
23248
23277
  summary["associated_resources_config"] = _extract_view_associated_resources_config(config)
23249
23278
  config_enriched = True
@@ -23310,6 +23339,36 @@ def _extract_view_question_entries(questions: Any) -> list[dict[str, Any]]:
23310
23339
  return entries
23311
23340
 
23312
23341
 
23342
+ def _view_field_lookup_from_question_entries(entries: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
23343
+ fields_by_name: dict[str, dict[str, Any]] = {}
23344
+ for entry in entries:
23345
+ if not isinstance(entry, dict):
23346
+ continue
23347
+ name = str(entry.get("name") or entry.get("title") or "").strip()
23348
+ que_id = _coerce_positive_int(entry.get("field_id") or entry.get("que_id") or entry.get("queId"))
23349
+ if not name or que_id is None:
23350
+ continue
23351
+ fields_by_name.setdefault(name, {"name": name, "que_id": que_id})
23352
+ return fields_by_name
23353
+
23354
+
23355
+ def _view_field_lookup_from_summary(view: dict[str, Any]) -> dict[str, dict[str, Any]]:
23356
+ entries = view.get("column_details")
23357
+ if isinstance(entries, list):
23358
+ return _view_field_lookup_from_question_entries([entry for entry in entries if isinstance(entry, dict)])
23359
+ fields_by_name: dict[str, dict[str, Any]] = {}
23360
+ names = view.get("columns")
23361
+ ids = view.get("display_column_ids") or view.get("configured_column_ids") or []
23362
+ if isinstance(names, list):
23363
+ for index, raw_name in enumerate(names):
23364
+ name = str(raw_name or "").strip()
23365
+ if not name:
23366
+ continue
23367
+ que_id = _coerce_positive_int(ids[index] if isinstance(ids, list) and index < len(ids) else None)
23368
+ fields_by_name.setdefault(name, {"name": name, "que_id": que_id})
23369
+ return fields_by_name
23370
+
23371
+
23313
23372
  def _filter_public_view_display_entries(
23314
23373
  entries: list[dict[str, Any]],
23315
23374
  *,
@@ -24126,6 +24185,7 @@ def _custom_button_view_configs_from_view_summaries(views: list[dict[str, Any]])
24126
24185
  raw_buttons = view.get("buttons")
24127
24186
  if not isinstance(raw_buttons, list):
24128
24187
  continue
24188
+ field_lookup = _view_field_lookup_from_summary(view)
24129
24189
  buttons: list[dict[str, Any]] = []
24130
24190
  for entry in raw_buttons:
24131
24191
  if not isinstance(entry, dict):
@@ -24133,6 +24193,12 @@ def _custom_button_view_configs_from_view_summaries(views: list[dict[str, Any]])
24133
24193
  if _normalize_view_button_type(entry.get("button_type")) != PublicViewButtonType.custom.value:
24134
24194
  continue
24135
24195
  placement = _public_view_button_placement(entry.get("config_type")) or entry.get("placement")
24196
+ raw_button_limit = deepcopy(entry.get("button_limit") or [])
24197
+ public_button_limit = (
24198
+ _public_view_filter_groups_from_match_rules(raw_button_limit, current_fields_by_name=field_lookup)
24199
+ if raw_button_limit
24200
+ else []
24201
+ )
24136
24202
  button = _compact_dict(
24137
24203
  {
24138
24204
  "button_ref": _coerce_positive_int(entry.get("button_id")),
@@ -24140,7 +24206,7 @@ def _custom_button_view_configs_from_view_summaries(views: list[dict[str, Any]])
24140
24206
  "button_text": entry.get("button_text"),
24141
24207
  "placement": placement,
24142
24208
  "primary": bool(entry.get("being_main", False)),
24143
- "button_limit": deepcopy(entry.get("button_limit") or []),
24209
+ "button_limit": public_button_limit,
24144
24210
  "button_formula": entry.get("button_formula"),
24145
24211
  "button_formula_type": _coerce_positive_int(entry.get("button_formula_type")),
24146
24212
  "print_tpls": deepcopy(entry.get("print_tpls") or []),