@josephyan/qingflow-cli 1.1.15 → 1.1.17
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/skills/qingflow-cli/SKILL.md +2 -2
- package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +10 -2
- package/skills/qingflow-cli/reference/builder/30-schema-fields.md +22 -1
- package/skills/qingflow-cli/reference/builder/50-views.md +83 -12
- package/skills/qingflow-cli/reference/builder/70-portal.md +16 -4
- package/skills/qingflow-cli/reference/builder/80-buttons-associated-resources.md +57 -4
- package/skills/qingflow-cli/reference/builder/90-workflow.md +1 -0
- package/skills/qingflow-cli/reference/builder/99-publish-verify.md +3 -0
- package/skills/qingflow-cli/reference/builder/workflow/README.md +1 -1
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_FIELD_DATA_TYPES.md +1 -1
- package/skills/qingflow-cli/reference/examples/portal/portal_sections_all_types.example.json +2 -2
- package/skills/qingflow-cli/reference/examples/portal/portal_sections_five_types.example.json +2 -2
- package/skills/qingflow-cli/reference/record/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md +1 -1
- package/skills/qingflow-cli/reference/record/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +4 -0
- package/skills/qingflow-cli/reference/record/insert/README.md +3 -0
- package/skills/qingflow-cli/reference/task/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md +2 -0
- package/src/qingflow_mcp/builder_facade/models.py +167 -0
- package/src/qingflow_mcp/builder_facade/service.py +556 -16
- package/src/qingflow_mcp/tools/ai_builder_tools.py +157 -6
|
@@ -1105,6 +1105,91 @@ class ViewAssociatedResourcesPatch(StrictModel):
|
|
|
1105
1105
|
)
|
|
1106
1106
|
|
|
1107
1107
|
|
|
1108
|
+
class ViewActionButtonPatch(StrictModel):
|
|
1109
|
+
button_id: int | None = Field(default=None, validation_alias=AliasChoices("button_id", "buttonId", "id"))
|
|
1110
|
+
client_key: str | None = Field(default=None, validation_alias=AliasChoices("client_key", "clientKey"))
|
|
1111
|
+
text: str = Field(validation_alias=AliasChoices("text", "button_text", "buttonText", "name"))
|
|
1112
|
+
action: PublicButtonTriggerAction = Field(validation_alias=AliasChoices("action", "trigger_action", "triggerAction"))
|
|
1113
|
+
url: str | None = Field(default=None, validation_alias=AliasChoices("url", "link_url", "linkUrl", "trigger_link_url", "triggerLinkUrl"))
|
|
1114
|
+
target_app_key: str | None = Field(default=None, validation_alias=AliasChoices("target_app_key", "targetAppKey", "related_app_key", "relatedAppKey"))
|
|
1115
|
+
target_app_name: str | None = Field(default=None, validation_alias=AliasChoices("target_app_name", "targetAppName", "related_app_name", "relatedAppName"))
|
|
1116
|
+
field_mappings: list[dict[str, Any]] = Field(default_factory=list, validation_alias=AliasChoices("field_mappings", "fieldMappings", "mappings"))
|
|
1117
|
+
default_values: dict[str, Any] = Field(default_factory=dict, validation_alias=AliasChoices("default_values", "defaultValues", "defaults"))
|
|
1118
|
+
placement: PublicButtonPlacement = Field(default=PublicButtonPlacement.detail, validation_alias=AliasChoices("placement", "position"))
|
|
1119
|
+
primary: bool = Field(default=False, validation_alias=AliasChoices("primary", "being_main", "beingMain"))
|
|
1120
|
+
visible_when: list[list[ViewFilterRulePatch]] = Field(
|
|
1121
|
+
default_factory=list,
|
|
1122
|
+
validation_alias=AliasChoices("visible_when", "visibleWhen", "button_limit", "buttonLimit"),
|
|
1123
|
+
)
|
|
1124
|
+
button_formula: str | None = Field(default=None, validation_alias=AliasChoices("button_formula", "buttonFormula"))
|
|
1125
|
+
button_formula_type: int = Field(default=1, validation_alias=AliasChoices("button_formula_type", "buttonFormulaType"))
|
|
1126
|
+
print_tpls: list[Any] = Field(default_factory=list, validation_alias=AliasChoices("print_tpls", "printTpls"))
|
|
1127
|
+
style_preset: str | None = Field(default=None, validation_alias=AliasChoices("style_preset", "stylePreset"))
|
|
1128
|
+
background_color: str | None = Field(default=None, validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
1129
|
+
text_color: str | None = Field(default=None, validation_alias=AliasChoices("text_color", "textColor"))
|
|
1130
|
+
button_icon: str | None = Field(default=None, validation_alias=AliasChoices("button_icon", "buttonIcon"))
|
|
1131
|
+
external_qrobot_config: dict[str, Any] | None = Field(
|
|
1132
|
+
default=None,
|
|
1133
|
+
validation_alias=AliasChoices(
|
|
1134
|
+
"external_qrobot_config",
|
|
1135
|
+
"externalQrobotConfig",
|
|
1136
|
+
"externalQRobotConfig",
|
|
1137
|
+
"custom_button_external_qrobot_relation_vo",
|
|
1138
|
+
"customButtonExternalQRobotRelationVO",
|
|
1139
|
+
),
|
|
1140
|
+
)
|
|
1141
|
+
trigger_wings_config: dict[str, Any] | None = Field(default=None, validation_alias=AliasChoices("trigger_wings_config", "triggerWingsConfig"))
|
|
1142
|
+
|
|
1143
|
+
@model_validator(mode="before")
|
|
1144
|
+
@classmethod
|
|
1145
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
1146
|
+
if not isinstance(value, dict):
|
|
1147
|
+
return value
|
|
1148
|
+
payload = dict(value)
|
|
1149
|
+
raw_action = payload.get("action", payload.get("trigger_action", payload.get("triggerAction")))
|
|
1150
|
+
if isinstance(raw_action, str):
|
|
1151
|
+
normalized = raw_action.strip()
|
|
1152
|
+
aliases = {
|
|
1153
|
+
"add_data": PublicButtonTriggerAction.add_data.value,
|
|
1154
|
+
"add-data": PublicButtonTriggerAction.add_data.value,
|
|
1155
|
+
"adddata": PublicButtonTriggerAction.add_data.value,
|
|
1156
|
+
"addData": PublicButtonTriggerAction.add_data.value,
|
|
1157
|
+
"link": PublicButtonTriggerAction.link.value,
|
|
1158
|
+
"url": PublicButtonTriggerAction.link.value,
|
|
1159
|
+
"qrobot": PublicButtonTriggerAction.qrobot.value,
|
|
1160
|
+
"qRobot": PublicButtonTriggerAction.qrobot.value,
|
|
1161
|
+
"wings": PublicButtonTriggerAction.wings.value,
|
|
1162
|
+
}
|
|
1163
|
+
payload["action"] = aliases.get(normalized, aliases.get(normalized.lower(), normalized))
|
|
1164
|
+
raw_placement = payload.get("placement", payload.get("position", payload.get("config_type", payload.get("configType"))))
|
|
1165
|
+
if isinstance(raw_placement, str):
|
|
1166
|
+
normalized = raw_placement.strip().lower()
|
|
1167
|
+
if normalized in {"top", "header"}:
|
|
1168
|
+
payload["placement"] = PublicButtonPlacement.header.value
|
|
1169
|
+
elif normalized in {"detail", "data_detail"}:
|
|
1170
|
+
payload["placement"] = PublicButtonPlacement.detail.value
|
|
1171
|
+
elif normalized in {"list", "row", "row_action", "inside"}:
|
|
1172
|
+
payload["placement"] = PublicButtonPlacement.list.value
|
|
1173
|
+
raw_limits = payload.get("visible_when", payload.get("visibleWhen", payload.get("button_limit", payload.get("buttonLimit"))))
|
|
1174
|
+
if isinstance(raw_limits, list) and raw_limits and all(isinstance(item, dict) for item in raw_limits):
|
|
1175
|
+
payload["visible_when"] = [raw_limits]
|
|
1176
|
+
return payload
|
|
1177
|
+
|
|
1178
|
+
@model_validator(mode="after")
|
|
1179
|
+
def validate_shape(self) -> "ViewActionButtonPatch":
|
|
1180
|
+
if not str(self.text or "").strip():
|
|
1181
|
+
raise ValueError("action_buttons[].text is required")
|
|
1182
|
+
if self.action == PublicButtonTriggerAction.link and not str(self.url or "").strip():
|
|
1183
|
+
raise ValueError("link action_buttons require url")
|
|
1184
|
+
if self.action == PublicButtonTriggerAction.add_data and not str(self.target_app_key or "").strip():
|
|
1185
|
+
raise ValueError("add_data action_buttons require target_app_key")
|
|
1186
|
+
if self.action == PublicButtonTriggerAction.qrobot and self.external_qrobot_config is None:
|
|
1187
|
+
raise ValueError("qRobot action_buttons require external_qrobot_config")
|
|
1188
|
+
if self.action == PublicButtonTriggerAction.wings and self.trigger_wings_config is None:
|
|
1189
|
+
raise ValueError("wings action_buttons require trigger_wings_config")
|
|
1190
|
+
return self
|
|
1191
|
+
|
|
1192
|
+
|
|
1108
1193
|
class ViewUpsertPatch(StrictModel):
|
|
1109
1194
|
name: str
|
|
1110
1195
|
view_key: str | None = Field(default=None, validation_alias=AliasChoices("view_key", "viewKey"))
|
|
@@ -1116,6 +1201,8 @@ class ViewUpsertPatch(StrictModel):
|
|
|
1116
1201
|
end_field: str | None = Field(default=None, validation_alias=AliasChoices("end_field", "endField"))
|
|
1117
1202
|
title_field: str | None = Field(default=None, validation_alias=AliasChoices("title_field", "titleField"))
|
|
1118
1203
|
buttons: list["ViewButtonBindingPatch"] | None = None
|
|
1204
|
+
action_buttons: list[ViewActionButtonPatch] | None = Field(default=None, validation_alias=AliasChoices("action_buttons", "actionButtons"))
|
|
1205
|
+
action_buttons_mode: str = Field(default="merge", validation_alias=AliasChoices("action_buttons_mode", "actionButtonsMode", "button_mode", "buttonMode"))
|
|
1119
1206
|
visibility: VisibilityPatch | None = None
|
|
1120
1207
|
query_conditions: ViewQueryConditionsPatch | None = Field(default=None, validation_alias=AliasChoices("query_conditions", "queryConditions", "query_condition", "queryCondition"))
|
|
1121
1208
|
associated_resources: ViewAssociatedResourcesPatch | None = Field(
|
|
@@ -1165,6 +1252,12 @@ class ViewUpsertPatch(StrictModel):
|
|
|
1165
1252
|
payload["associated_resources"] = payload.pop("associatedReports")
|
|
1166
1253
|
if "asosChartConfig" in payload and "associated_resources" not in payload:
|
|
1167
1254
|
payload["associated_resources"] = payload.pop("asosChartConfig")
|
|
1255
|
+
if "actionButtons" in payload and "action_buttons" not in payload:
|
|
1256
|
+
payload["action_buttons"] = payload.pop("actionButtons")
|
|
1257
|
+
if "actionButtonsMode" in payload and "action_buttons_mode" not in payload:
|
|
1258
|
+
payload["action_buttons_mode"] = payload.pop("actionButtonsMode")
|
|
1259
|
+
if "buttonMode" in payload and "action_buttons_mode" not in payload:
|
|
1260
|
+
payload["action_buttons_mode"] = payload.pop("buttonMode")
|
|
1168
1261
|
raw_type = payload.get("type")
|
|
1169
1262
|
if isinstance(raw_type, str):
|
|
1170
1263
|
normalized = raw_type.strip().lower()
|
|
@@ -1186,6 +1279,10 @@ class ViewUpsertPatch(StrictModel):
|
|
|
1186
1279
|
raise ValueError("board view requires group_by")
|
|
1187
1280
|
if self.type == PublicViewType.gantt and not (self.start_field and self.end_field):
|
|
1188
1281
|
raise ValueError("gantt view requires start_field and end_field")
|
|
1282
|
+
normalized_mode = str(self.action_buttons_mode or "merge").strip().lower()
|
|
1283
|
+
if normalized_mode not in {"merge", "replace"}:
|
|
1284
|
+
raise ValueError("action_buttons_mode must be merge or replace")
|
|
1285
|
+
self.action_buttons_mode = normalized_mode
|
|
1189
1286
|
return self
|
|
1190
1287
|
|
|
1191
1288
|
|
|
@@ -1211,6 +1308,76 @@ class ViewPartialPatch(StrictModel):
|
|
|
1211
1308
|
return self
|
|
1212
1309
|
|
|
1213
1310
|
|
|
1311
|
+
def public_button_trigger_action_value(value: Any) -> str:
|
|
1312
|
+
raw = value.value if isinstance(value, PublicButtonTriggerAction) else str(value or "").strip()
|
|
1313
|
+
normalized = raw.lower()
|
|
1314
|
+
if raw == PublicButtonTriggerAction.add_data.value or normalized in {"add_data", "add-data", "adddata"}:
|
|
1315
|
+
return "add_data"
|
|
1316
|
+
if normalized in {PublicButtonTriggerAction.link.value, "url"}:
|
|
1317
|
+
return "link"
|
|
1318
|
+
if raw == PublicButtonTriggerAction.qrobot.value or normalized == "qrobot":
|
|
1319
|
+
return "qRobot"
|
|
1320
|
+
if normalized == PublicButtonTriggerAction.wings.value:
|
|
1321
|
+
return "wings"
|
|
1322
|
+
return raw
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
def _drop_empty_public_payload_values(payload: dict[str, Any]) -> dict[str, Any]:
|
|
1326
|
+
compact: dict[str, Any] = {}
|
|
1327
|
+
for key, item in payload.items():
|
|
1328
|
+
if item is None or item == "" or item == [] or item == {}:
|
|
1329
|
+
continue
|
|
1330
|
+
if key == "primary" and item is False:
|
|
1331
|
+
continue
|
|
1332
|
+
compact[key] = item
|
|
1333
|
+
return compact
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
def public_view_action_button_payload(button: Any, *, compact: bool = False) -> dict[str, Any]:
|
|
1337
|
+
if isinstance(button, ViewActionButtonPatch):
|
|
1338
|
+
payload = button.model_dump(mode="json")
|
|
1339
|
+
elif isinstance(button, dict):
|
|
1340
|
+
payload = dict(button)
|
|
1341
|
+
else:
|
|
1342
|
+
return {}
|
|
1343
|
+
raw_action = payload.get("action", payload.get("trigger_action", payload.get("triggerAction")))
|
|
1344
|
+
if raw_action is not None:
|
|
1345
|
+
payload["action"] = public_button_trigger_action_value(raw_action)
|
|
1346
|
+
payload.pop("trigger_action", None)
|
|
1347
|
+
payload.pop("triggerAction", None)
|
|
1348
|
+
if compact:
|
|
1349
|
+
return _drop_empty_public_payload_values(payload)
|
|
1350
|
+
return payload
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
def public_view_upsert_payload(view: ViewUpsertPatch) -> dict[str, Any]:
|
|
1354
|
+
payload = view.model_dump(mode="json")
|
|
1355
|
+
if view.action_buttons is not None:
|
|
1356
|
+
payload["action_buttons"] = [
|
|
1357
|
+
public_view_action_button_payload(button, compact=True)
|
|
1358
|
+
for button in view.action_buttons
|
|
1359
|
+
]
|
|
1360
|
+
return payload
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
def public_view_partial_payload(patch: ViewPartialPatch) -> dict[str, Any]:
|
|
1364
|
+
payload = patch.model_dump(mode="json")
|
|
1365
|
+
patch_set = payload.get("set")
|
|
1366
|
+
if isinstance(patch_set, dict):
|
|
1367
|
+
raw_buttons = patch_set.get("action_buttons")
|
|
1368
|
+
if raw_buttons is None:
|
|
1369
|
+
raw_buttons = patch_set.get("actionButtons")
|
|
1370
|
+
if isinstance(raw_buttons, list):
|
|
1371
|
+
patch_set = dict(patch_set)
|
|
1372
|
+
patch_set.pop("actionButtons", None)
|
|
1373
|
+
patch_set["action_buttons"] = [
|
|
1374
|
+
public_view_action_button_payload(button, compact=True)
|
|
1375
|
+
for button in raw_buttons
|
|
1376
|
+
]
|
|
1377
|
+
payload["set"] = patch_set
|
|
1378
|
+
return payload
|
|
1379
|
+
|
|
1380
|
+
|
|
1214
1381
|
class CustomButtonJudgeValuePatch(StrictModel):
|
|
1215
1382
|
id: int | str | None = None
|
|
1216
1383
|
value: Any | None = None
|