@josephyan/qingflow-cli 0.2.0-beta.64 → 0.2.0-beta.66
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/models.py +5 -0
- package/src/qingflow_mcp/builder_facade/service.py +157 -10
- package/src/qingflow_mcp/cli/commands/builder.py +4 -0
- package/src/qingflow_mcp/server_app_builder.py +4 -0
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +119 -45
- package/src/qingflow_mcp/tools/ai_builder_tools.py +36 -2
- package/src/qingflow_mcp/tools/custom_button_tools.py +2 -0
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-cli@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-cli@0.2.0-beta.66
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.66 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": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.66",
|
|
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
|
@@ -639,6 +639,7 @@ class CustomButtonPatch(StrictModel):
|
|
|
639
639
|
background_color: str = Field(validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
640
640
|
text_color: str = Field(validation_alias=AliasChoices("text_color", "textColor"))
|
|
641
641
|
button_icon: str = Field(validation_alias=AliasChoices("button_icon", "buttonIcon"))
|
|
642
|
+
icon_color: str | None = Field(default=None, validation_alias=AliasChoices("icon_color", "iconColor"))
|
|
642
643
|
trigger_action: PublicButtonTriggerAction = Field(validation_alias=AliasChoices("trigger_action", "triggerAction"))
|
|
643
644
|
trigger_link_url: str | None = Field(default=None, validation_alias=AliasChoices("trigger_link_url", "triggerLinkUrl"))
|
|
644
645
|
trigger_add_data_config: CustomButtonAddDataConfigPatch | None = Field(
|
|
@@ -678,6 +679,7 @@ class ViewButtonBindingPatch(StrictModel):
|
|
|
678
679
|
button_id: int = Field(validation_alias=AliasChoices("button_id", "buttonId", "id"))
|
|
679
680
|
button_text: str | None = Field(default=None, validation_alias=AliasChoices("button_text", "buttonText"))
|
|
680
681
|
button_icon: str | None = Field(default=None, validation_alias=AliasChoices("button_icon", "buttonIcon"))
|
|
682
|
+
icon_color: str | None = Field(default=None, validation_alias=AliasChoices("icon_color", "iconColor"))
|
|
681
683
|
background_color: str | None = Field(default=None, validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
682
684
|
text_color: str | None = Field(default=None, validation_alias=AliasChoices("text_color", "textColor"))
|
|
683
685
|
trigger_action: str | None = Field(default=None, validation_alias=AliasChoices("trigger_action", "triggerAction"))
|
|
@@ -994,6 +996,7 @@ FieldPatch.model_rebuild()
|
|
|
994
996
|
class AppReadSummaryResponse(StrictModel):
|
|
995
997
|
app_key: str
|
|
996
998
|
title: str | None = None
|
|
999
|
+
app_icon: str | None = None
|
|
997
1000
|
tag_ids: list[int] = Field(default_factory=list)
|
|
998
1001
|
publish_status: int | None = None
|
|
999
1002
|
field_count: int = 0
|
|
@@ -1051,6 +1054,8 @@ class SchemaPlanRequest(StrictModel):
|
|
|
1051
1054
|
app_key: str = ""
|
|
1052
1055
|
package_tag_id: int | None = None
|
|
1053
1056
|
app_name: str = Field(default="", validation_alias=AliasChoices("app_name", "app_title", "title"))
|
|
1057
|
+
icon: str | None = None
|
|
1058
|
+
color: str | None = None
|
|
1054
1059
|
create_if_missing: bool = False
|
|
1055
1060
|
add_fields: list[FieldPatch] = Field(default_factory=list)
|
|
1056
1061
|
update_fields: list[FieldUpdatePatch] = Field(default_factory=list)
|
|
@@ -16,7 +16,7 @@ from ..list_type_labels import RECORD_LIST_TYPE_LABELS, SYSTEM_VIEW_ID_TO_LIST_T
|
|
|
16
16
|
from ..solution.build_assembly_store import BuildAssemblyStore, default_artifacts, default_manifest
|
|
17
17
|
from ..solution.compiler.chart_compiler import qingbi_workspace_visible_auth
|
|
18
18
|
from ..solution.compiler.form_compiler import build_question, default_form_payload, default_member_auth
|
|
19
|
-
from ..solution.compiler.icon_utils import
|
|
19
|
+
from ..solution.compiler.icon_utils import encode_workspace_icon_with_defaults
|
|
20
20
|
from ..solution.compiler.view_compiler import VIEW_TYPE_MAP
|
|
21
21
|
from ..solution.executor import _build_viewgraph_questions, _compact_dict, extract_field_map
|
|
22
22
|
from ..solution.spec_models import FieldType, FormLayoutRowSpec, FormLayoutSectionSpec, ViewSpec
|
|
@@ -1968,6 +1968,7 @@ class AiBuilderFacade:
|
|
|
1968
1968
|
response = AppReadSummaryResponse(
|
|
1969
1969
|
app_key=app_key,
|
|
1970
1970
|
title=state["base"].get("formTitle"),
|
|
1971
|
+
app_icon=str(state["base"].get("appIcon") or "").strip() or None,
|
|
1971
1972
|
tag_ids=_coerce_int_list(state["base"].get("tagIds")),
|
|
1972
1973
|
publish_status=state["base"].get("appPublishStatus"),
|
|
1973
1974
|
field_count=len(parsed["fields"]),
|
|
@@ -2674,6 +2675,7 @@ class AiBuilderFacade:
|
|
|
2674
2675
|
"app": {
|
|
2675
2676
|
"app_key": app_key,
|
|
2676
2677
|
"title": base_result.get("formTitle"),
|
|
2678
|
+
"app_icon": str(base_result.get("appIcon") or "").strip() or None,
|
|
2677
2679
|
"tag_ids": _coerce_int_list(base_result.get("tagIds")),
|
|
2678
2680
|
"publish_status": base_result.get("appPublishStatus"),
|
|
2679
2681
|
},
|
|
@@ -2706,6 +2708,8 @@ class AiBuilderFacade:
|
|
|
2706
2708
|
app_key: str = "",
|
|
2707
2709
|
package_tag_id: int | None = None,
|
|
2708
2710
|
app_name: str = "",
|
|
2711
|
+
icon: str | None = None,
|
|
2712
|
+
color: str | None = None,
|
|
2709
2713
|
create_if_missing: bool = False,
|
|
2710
2714
|
publish: bool = True,
|
|
2711
2715
|
add_fields: list[FieldPatch],
|
|
@@ -2716,6 +2720,8 @@ class AiBuilderFacade:
|
|
|
2716
2720
|
"app_key": app_key,
|
|
2717
2721
|
"package_tag_id": package_tag_id,
|
|
2718
2722
|
"app_name": app_name,
|
|
2723
|
+
"icon": icon,
|
|
2724
|
+
"color": color,
|
|
2719
2725
|
"create_if_missing": create_if_missing,
|
|
2720
2726
|
"publish": publish,
|
|
2721
2727
|
"add_fields": [patch.model_dump(mode="json") for patch in add_fields],
|
|
@@ -2766,6 +2772,8 @@ class AiBuilderFacade:
|
|
|
2766
2772
|
profile=profile,
|
|
2767
2773
|
app_name=app_name,
|
|
2768
2774
|
package_tag_id=package_tag_id,
|
|
2775
|
+
icon=icon,
|
|
2776
|
+
color=color,
|
|
2769
2777
|
)
|
|
2770
2778
|
if resolved.get("status") == "failed":
|
|
2771
2779
|
if not isinstance(resolved.get("normalized_args"), dict) or not resolved.get("normalized_args"):
|
|
@@ -2789,6 +2797,23 @@ class AiBuilderFacade:
|
|
|
2789
2797
|
if permission_outcome.block is not None:
|
|
2790
2798
|
return permission_outcome.block
|
|
2791
2799
|
permission_outcomes.append(permission_outcome)
|
|
2800
|
+
visual_result = self._ensure_app_base_visuals(
|
|
2801
|
+
profile=profile,
|
|
2802
|
+
app_key=target.app_key,
|
|
2803
|
+
fallback_title=target.app_name,
|
|
2804
|
+
icon=icon,
|
|
2805
|
+
color=color,
|
|
2806
|
+
normalized_args=normalized_args,
|
|
2807
|
+
)
|
|
2808
|
+
if visual_result.get("status") == "failed":
|
|
2809
|
+
return finalize(visual_result)
|
|
2810
|
+
else:
|
|
2811
|
+
visual_result = {
|
|
2812
|
+
"status": "success",
|
|
2813
|
+
"updated": False,
|
|
2814
|
+
"app_icon": str(resolved.get("app_icon") or "").strip() or None,
|
|
2815
|
+
"request_id": None,
|
|
2816
|
+
}
|
|
2792
2817
|
if bool(resolved.get("created")) and not requested_field_changes:
|
|
2793
2818
|
return finalize({
|
|
2794
2819
|
"status": "success",
|
|
@@ -2807,9 +2832,11 @@ class AiBuilderFacade:
|
|
|
2807
2832
|
"fields_verified": True,
|
|
2808
2833
|
"package_attached": None if package_tag_id is None else package_tag_id in target.tag_ids,
|
|
2809
2834
|
"relation_field_limit_verified": True,
|
|
2835
|
+
"app_visuals_verified": True,
|
|
2810
2836
|
"publish_skipped": True,
|
|
2811
2837
|
},
|
|
2812
2838
|
"app_key": target.app_key,
|
|
2839
|
+
"app_icon": str(resolved.get("app_icon") or visual_result.get("app_icon") or "").strip() or None,
|
|
2813
2840
|
"created": True,
|
|
2814
2841
|
"field_diff": {"added": [], "updated": [], "removed": []},
|
|
2815
2842
|
"verified": True,
|
|
@@ -2931,17 +2958,22 @@ class AiBuilderFacade:
|
|
|
2931
2958
|
"status": "success",
|
|
2932
2959
|
"error_code": None,
|
|
2933
2960
|
"recoverable": False,
|
|
2934
|
-
"message": "schema already matches requested state",
|
|
2961
|
+
"message": "updated app visuals; schema already matches requested state" if bool(visual_result.get("updated")) else "schema already matches requested state",
|
|
2935
2962
|
"normalized_args": normalized_args,
|
|
2936
2963
|
"missing_fields": [],
|
|
2937
2964
|
"allowed_values": {"field_types": [item.value for item in PublicFieldType]},
|
|
2938
2965
|
"details": {},
|
|
2939
2966
|
"request_id": None,
|
|
2940
2967
|
"suggested_next_call": None if package_attached is not False else {"tool_name": "package_attach_app", "arguments": {"profile": profile, "tag_id": package_tag_id, "app_key": target.app_key}},
|
|
2941
|
-
"noop":
|
|
2968
|
+
"noop": not bool(visual_result.get("updated")),
|
|
2942
2969
|
"warnings": relation_warnings,
|
|
2943
|
-
"verification": {
|
|
2970
|
+
"verification": {
|
|
2971
|
+
"fields_verified": True,
|
|
2972
|
+
"relation_field_limit_verified": relation_limit_verified,
|
|
2973
|
+
"app_visuals_verified": True,
|
|
2974
|
+
},
|
|
2944
2975
|
"app_key": target.app_key,
|
|
2976
|
+
"app_icon": str(visual_result.get("app_icon") or "").strip() or None,
|
|
2945
2977
|
"created": False,
|
|
2946
2978
|
"field_diff": {"added": [], "updated": [], "removed": []},
|
|
2947
2979
|
"verified": True,
|
|
@@ -3013,9 +3045,11 @@ class AiBuilderFacade:
|
|
|
3013
3045
|
"verification": {
|
|
3014
3046
|
"fields_verified": False,
|
|
3015
3047
|
"package_attached": None,
|
|
3048
|
+
"app_visuals_verified": True,
|
|
3016
3049
|
"relation_field_limit_verified": relation_limit_verified,
|
|
3017
3050
|
},
|
|
3018
3051
|
"app_key": target.app_key,
|
|
3052
|
+
"app_icon": str(visual_result.get("app_icon") or resolved.get("app_icon") or "").strip() or None,
|
|
3019
3053
|
"created": bool(resolved.get("created")),
|
|
3020
3054
|
"field_diff": {
|
|
3021
3055
|
"added": added,
|
|
@@ -5482,9 +5516,17 @@ class AiBuilderFacade:
|
|
|
5482
5516
|
profile: str,
|
|
5483
5517
|
app_name: str,
|
|
5484
5518
|
package_tag_id: int | None,
|
|
5519
|
+
icon: str | None,
|
|
5520
|
+
color: str | None,
|
|
5485
5521
|
) -> JSONObject:
|
|
5486
5522
|
payload: JSONObject = {
|
|
5487
5523
|
"appName": app_name or "未命名应用",
|
|
5524
|
+
"appIcon": encode_workspace_icon_with_defaults(
|
|
5525
|
+
icon=icon,
|
|
5526
|
+
color=color,
|
|
5527
|
+
title=app_name or "未命名应用",
|
|
5528
|
+
fallback_icon_name="template",
|
|
5529
|
+
),
|
|
5488
5530
|
"auth": default_member_auth(),
|
|
5489
5531
|
"tagIds": [package_tag_id] if package_tag_id and package_tag_id > 0 else [],
|
|
5490
5532
|
}
|
|
@@ -5530,6 +5572,7 @@ class AiBuilderFacade:
|
|
|
5530
5572
|
"suggested_next_call": None,
|
|
5531
5573
|
"app_key": new_app_key,
|
|
5532
5574
|
"app_name": app_name or "未命名应用",
|
|
5575
|
+
"app_icon": payload.get("appIcon"),
|
|
5533
5576
|
"tag_ids": [package_tag_id] if package_tag_id and package_tag_id > 0 else [],
|
|
5534
5577
|
"created": True,
|
|
5535
5578
|
}
|
|
@@ -5541,10 +5584,103 @@ class AiBuilderFacade:
|
|
|
5541
5584
|
"suggested_next_call": None,
|
|
5542
5585
|
"app_key": new_app_key,
|
|
5543
5586
|
"app_name": base.get("formTitle") or app_name or "未命名应用",
|
|
5587
|
+
"app_icon": str(base.get("appIcon") or payload.get("appIcon") or "").strip() or None,
|
|
5544
5588
|
"tag_ids": _coerce_int_list(base.get("tagIds")),
|
|
5545
5589
|
"created": True,
|
|
5546
5590
|
}
|
|
5547
5591
|
|
|
5592
|
+
def _build_app_base_update_payload(
|
|
5593
|
+
self,
|
|
5594
|
+
*,
|
|
5595
|
+
raw_base: dict[str, Any],
|
|
5596
|
+
form_title: str,
|
|
5597
|
+
app_icon: str,
|
|
5598
|
+
) -> JSONObject | None:
|
|
5599
|
+
auth = deepcopy(raw_base.get("auth"))
|
|
5600
|
+
if not isinstance(auth, dict):
|
|
5601
|
+
return None
|
|
5602
|
+
payload: JSONObject = {
|
|
5603
|
+
"formTitle": form_title,
|
|
5604
|
+
"auth": auth,
|
|
5605
|
+
"appIcon": app_icon,
|
|
5606
|
+
}
|
|
5607
|
+
tag_ids = _coerce_int_list(raw_base.get("tagIds"))
|
|
5608
|
+
if tag_ids:
|
|
5609
|
+
payload["tagIds"] = tag_ids
|
|
5610
|
+
return payload
|
|
5611
|
+
|
|
5612
|
+
def _ensure_app_base_visuals(
|
|
5613
|
+
self,
|
|
5614
|
+
*,
|
|
5615
|
+
profile: str,
|
|
5616
|
+
app_key: str,
|
|
5617
|
+
fallback_title: str,
|
|
5618
|
+
icon: str | None,
|
|
5619
|
+
color: str | None,
|
|
5620
|
+
normalized_args: dict[str, Any],
|
|
5621
|
+
) -> JSONObject:
|
|
5622
|
+
if not icon and not color:
|
|
5623
|
+
return {
|
|
5624
|
+
"status": "success",
|
|
5625
|
+
"updated": False,
|
|
5626
|
+
"app_icon": None,
|
|
5627
|
+
"request_id": None,
|
|
5628
|
+
}
|
|
5629
|
+
try:
|
|
5630
|
+
base_result = self.apps.app_get_base(profile=profile, app_key=app_key, include_raw=True)
|
|
5631
|
+
except (QingflowApiError, RuntimeError) as error:
|
|
5632
|
+
api_error = _coerce_api_error(error)
|
|
5633
|
+
return _failed_from_api_error(
|
|
5634
|
+
"APP_VISUAL_READ_FAILED",
|
|
5635
|
+
api_error,
|
|
5636
|
+
normalized_args=normalized_args,
|
|
5637
|
+
details={"app_key": app_key},
|
|
5638
|
+
suggested_next_call={"tool_name": "app_read_summary", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5639
|
+
)
|
|
5640
|
+
raw_base = base_result.get("result") if isinstance(base_result.get("result"), dict) else {}
|
|
5641
|
+
effective_title = str(raw_base.get("formTitle") or fallback_title or "未命名应用").strip() or "未命名应用"
|
|
5642
|
+
existing_icon = str(raw_base.get("appIcon") or "").strip() or None
|
|
5643
|
+
desired_icon = encode_workspace_icon_with_defaults(
|
|
5644
|
+
icon=icon,
|
|
5645
|
+
color=color,
|
|
5646
|
+
title=effective_title,
|
|
5647
|
+
fallback_icon_name="template",
|
|
5648
|
+
existing_icon=existing_icon,
|
|
5649
|
+
)
|
|
5650
|
+
if desired_icon == existing_icon:
|
|
5651
|
+
return {
|
|
5652
|
+
"status": "success",
|
|
5653
|
+
"updated": False,
|
|
5654
|
+
"app_icon": desired_icon,
|
|
5655
|
+
"request_id": None,
|
|
5656
|
+
}
|
|
5657
|
+
payload = self._build_app_base_update_payload(raw_base=raw_base, form_title=effective_title, app_icon=desired_icon)
|
|
5658
|
+
if payload is None:
|
|
5659
|
+
return _failed(
|
|
5660
|
+
"APP_VISUAL_UPDATE_UNSUPPORTED",
|
|
5661
|
+
"app base info did not include editable auth payload required for icon update",
|
|
5662
|
+
normalized_args=normalized_args,
|
|
5663
|
+
details={"app_key": app_key},
|
|
5664
|
+
suggested_next_call={"tool_name": "app_read_summary", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5665
|
+
)
|
|
5666
|
+
try:
|
|
5667
|
+
update_result = self.apps.app_update_base(profile=profile, app_key=app_key, payload=payload)
|
|
5668
|
+
except (QingflowApiError, RuntimeError) as error:
|
|
5669
|
+
api_error = _coerce_api_error(error)
|
|
5670
|
+
return _failed_from_api_error(
|
|
5671
|
+
"APP_VISUAL_UPDATE_FAILED",
|
|
5672
|
+
api_error,
|
|
5673
|
+
normalized_args=normalized_args,
|
|
5674
|
+
details={"app_key": app_key, "app_icon": desired_icon},
|
|
5675
|
+
suggested_next_call={"tool_name": "app_read_summary", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5676
|
+
)
|
|
5677
|
+
return {
|
|
5678
|
+
"status": "success",
|
|
5679
|
+
"updated": True,
|
|
5680
|
+
"app_icon": desired_icon,
|
|
5681
|
+
"request_id": update_result.get("request_id") if isinstance(update_result, dict) else None,
|
|
5682
|
+
}
|
|
5683
|
+
|
|
5548
5684
|
def _current_request_route(self, profile: str) -> JSONObject:
|
|
5549
5685
|
session_profile = self.apps.sessions.get_profile(profile)
|
|
5550
5686
|
backend_session = self.apps.sessions.get_backend_session(profile)
|
|
@@ -5727,6 +5863,8 @@ def _serialize_custom_button_payload(payload: CustomButtonPatch) -> dict[str, An
|
|
|
5727
5863
|
"buttonIcon": data["button_icon"],
|
|
5728
5864
|
"triggerAction": data["trigger_action"],
|
|
5729
5865
|
}
|
|
5866
|
+
if str(data.get("icon_color") or "").strip():
|
|
5867
|
+
serialized["iconColor"] = data["icon_color"]
|
|
5730
5868
|
if str(data.get("trigger_link_url") or "").strip():
|
|
5731
5869
|
serialized["triggerLinkUrl"] = data["trigger_link_url"]
|
|
5732
5870
|
trigger_add_data_config = data.get("trigger_add_data_config")
|
|
@@ -5816,6 +5954,7 @@ def _normalize_custom_button_summary(item: dict[str, Any]) -> dict[str, Any]:
|
|
|
5816
5954
|
"button_id": _coerce_positive_int(item.get("button_id") or item.get("buttonId") or item.get("id")),
|
|
5817
5955
|
"button_text": str(item.get("button_text") or item.get("buttonText") or "").strip() or None,
|
|
5818
5956
|
"button_icon": str(item.get("button_icon") or item.get("buttonIcon") or "").strip() or None,
|
|
5957
|
+
"icon_color": str(item.get("icon_color") or item.get("iconColor") or "").strip() or None,
|
|
5819
5958
|
"background_color": str(item.get("background_color") or item.get("backgroundColor") or "").strip() or None,
|
|
5820
5959
|
"text_color": str(item.get("text_color") or item.get("textColor") or "").strip() or None,
|
|
5821
5960
|
"used_in_chart_count": _coerce_nonnegative_int(item.get("used_in_chart_count") or item.get("userInChartCount")),
|
|
@@ -6572,11 +6711,12 @@ def _build_public_portal_base_payload(
|
|
|
6572
6711
|
effective_name = str(dash_name or data.get("dashName") or "").strip() or "未命名门户"
|
|
6573
6712
|
effective_hide_copyright = hide_copyright if hide_copyright is not None else bool(data.get("hideCopyright", False))
|
|
6574
6713
|
if icon or color or not data.get("dashIcon"):
|
|
6575
|
-
data["dashIcon"] =
|
|
6714
|
+
data["dashIcon"] = encode_workspace_icon_with_defaults(
|
|
6576
6715
|
icon=icon,
|
|
6577
6716
|
color=color,
|
|
6578
6717
|
title=effective_name,
|
|
6579
6718
|
fallback_icon_name="view-grid",
|
|
6719
|
+
existing_icon=str(data.get("dashIcon") or "").strip() or None,
|
|
6580
6720
|
)
|
|
6581
6721
|
data["dashName"] = effective_name
|
|
6582
6722
|
data["auth"] = deepcopy(auth if auth is not None else data.get("auth") or default_member_auth())
|
|
@@ -8593,6 +8733,7 @@ def _normalize_view_button_entry(entry: dict[str, Any]) -> dict[str, Any]:
|
|
|
8593
8733
|
for public_key, source_key in (
|
|
8594
8734
|
("default_button_text", "defaultButtonText"),
|
|
8595
8735
|
("button_icon", "buttonIcon"),
|
|
8736
|
+
("icon_color", "iconColor"),
|
|
8596
8737
|
("background_color", "backgroundColor"),
|
|
8597
8738
|
("text_color", "textColor"),
|
|
8598
8739
|
("trigger_link_url", "triggerLinkUrl"),
|
|
@@ -8622,17 +8763,21 @@ def _normalize_view_buttons_for_compare(value: Any) -> list[dict[str, Any]]:
|
|
|
8622
8763
|
normalized_entries: list[dict[str, Any]] = []
|
|
8623
8764
|
for entry in entries:
|
|
8624
8765
|
normalized = _normalize_view_button_entry(entry)
|
|
8766
|
+
is_custom = normalized.get("button_type") == "CUSTOM"
|
|
8625
8767
|
normalized_entries.append(
|
|
8626
8768
|
{
|
|
8627
8769
|
"button_type": normalized.get("button_type"),
|
|
8628
8770
|
"config_type": normalized.get("config_type"),
|
|
8629
|
-
"button_id": normalized.get("button_id") if
|
|
8771
|
+
"button_id": normalized.get("button_id") if is_custom else None,
|
|
8630
8772
|
"button_text": normalized.get("button_text"),
|
|
8631
8773
|
"button_icon": normalized.get("button_icon"),
|
|
8774
|
+
"icon_color": normalized.get("icon_color"),
|
|
8632
8775
|
"background_color": normalized.get("background_color"),
|
|
8633
8776
|
"text_color": normalized.get("text_color"),
|
|
8634
8777
|
"trigger_action": normalized.get("trigger_action"),
|
|
8635
|
-
|
|
8778
|
+
# Custom button trigger details are verified by dedicated button CRUD readback.
|
|
8779
|
+
# View binding verification should focus on binding/display semantics and tolerate resource-owned URLs.
|
|
8780
|
+
"trigger_link_url": None if is_custom else normalized.get("trigger_link_url"),
|
|
8636
8781
|
"being_main": bool(normalized.get("being_main", False)),
|
|
8637
8782
|
"print_tpls": _normalize_print_tpls_for_compare(normalized.get("print_tpls")),
|
|
8638
8783
|
"button_formula": str(normalized.get("button_formula") or ""),
|
|
@@ -8701,13 +8846,13 @@ def _normalize_expected_view_buttons_for_compare(
|
|
|
8701
8846
|
for key in (
|
|
8702
8847
|
"button_text",
|
|
8703
8848
|
"button_icon",
|
|
8849
|
+
"icon_color",
|
|
8704
8850
|
"background_color",
|
|
8705
8851
|
"text_color",
|
|
8706
8852
|
"trigger_action",
|
|
8707
|
-
"trigger_link_url",
|
|
8708
8853
|
):
|
|
8709
8854
|
value = detail.get(key)
|
|
8710
|
-
if value not in {None, ""}:
|
|
8855
|
+
if enriched.get(key) in {None, ""} and value not in {None, ""}:
|
|
8711
8856
|
enriched[key] = deepcopy(value)
|
|
8712
8857
|
enriched_entries.append(enriched)
|
|
8713
8858
|
return enriched_entries
|
|
@@ -8881,9 +9026,11 @@ def _serialize_view_button_binding(
|
|
|
8881
9026
|
"buttonFormulaType": binding.button_formula_type,
|
|
8882
9027
|
"printTpls": _serialize_print_tpl_ids(binding.print_tpls),
|
|
8883
9028
|
}
|
|
8884
|
-
if binding.button_type
|
|
9029
|
+
if binding.button_type in {PublicViewButtonType.system, PublicViewButtonType.custom}:
|
|
8885
9030
|
dto["buttonText"] = binding.button_text
|
|
8886
9031
|
dto["buttonIcon"] = binding.button_icon
|
|
9032
|
+
if str(binding.icon_color or "").strip():
|
|
9033
|
+
dto["iconColor"] = binding.icon_color
|
|
8887
9034
|
dto["backgroundColor"] = binding.background_color
|
|
8888
9035
|
dto["textColor"] = binding.text_color
|
|
8889
9036
|
dto["triggerAction"] = binding.trigger_action
|
|
@@ -93,6 +93,8 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
93
93
|
schema_apply_apply.add_argument("--package-tag-id", type=int)
|
|
94
94
|
schema_apply_apply.add_argument("--app-name", default="")
|
|
95
95
|
schema_apply_apply.add_argument("--app-title", default="")
|
|
96
|
+
schema_apply_apply.add_argument("--icon")
|
|
97
|
+
schema_apply_apply.add_argument("--color")
|
|
96
98
|
schema_apply_apply.add_argument("--create-if-missing", action="store_true")
|
|
97
99
|
schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
98
100
|
schema_apply_apply.add_argument("--add-fields-file")
|
|
@@ -198,6 +200,8 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
198
200
|
package_tag_id=args.package_tag_id,
|
|
199
201
|
app_name=args.app_name,
|
|
200
202
|
app_title=args.app_title,
|
|
203
|
+
icon=args.icon,
|
|
204
|
+
color=args.color,
|
|
201
205
|
create_if_missing=bool(args.create_if_missing),
|
|
202
206
|
publish=bool(args.publish),
|
|
203
207
|
add_fields=load_list_arg(args.add_fields_file, option_name="--add-fields-file"),
|
|
@@ -280,6 +280,8 @@ def build_builder_server() -> FastMCP:
|
|
|
280
280
|
package_tag_id: int | None = None,
|
|
281
281
|
app_name: str = "",
|
|
282
282
|
app_title: str = "",
|
|
283
|
+
icon: str = "",
|
|
284
|
+
color: str = "",
|
|
283
285
|
create_if_missing: bool = False,
|
|
284
286
|
publish: bool = True,
|
|
285
287
|
add_fields: list[dict] | None = None,
|
|
@@ -292,6 +294,8 @@ def build_builder_server() -> FastMCP:
|
|
|
292
294
|
package_tag_id=package_tag_id,
|
|
293
295
|
app_name=app_name,
|
|
294
296
|
app_title=app_title,
|
|
297
|
+
icon=icon,
|
|
298
|
+
color=color,
|
|
295
299
|
create_if_missing=create_if_missing,
|
|
296
300
|
publish=publish,
|
|
297
301
|
add_fields=add_fields or [],
|
|
@@ -1,44 +1,57 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import re
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
DEFAULT_ICON_COLOR = "qing-orange"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
8
|
+
DEFAULT_ICON_STYLE_POOL: tuple[tuple[str, str], ...] = (
|
|
9
|
+
("briefcase", "qing-orange"),
|
|
10
|
+
("calendar", "emerald"),
|
|
11
|
+
("files-folder", "azure"),
|
|
12
|
+
("shield-check", "indigo"),
|
|
13
|
+
("user-group", "qing-purple"),
|
|
14
|
+
("chart-square-bar", "blue"),
|
|
15
|
+
("clock", "pink"),
|
|
16
|
+
("document-text", "green"),
|
|
17
|
+
("home", "orange"),
|
|
18
|
+
("globe", "red"),
|
|
19
|
+
)
|
|
20
|
+
LEGACY_EX_ICON_MAP = {
|
|
21
|
+
"ex-alert-outlined": "exclamation-circle",
|
|
22
|
+
"ex-clock-outlined": "clock",
|
|
23
|
+
"ex-folder-outlined": "folder",
|
|
24
|
+
"ex-form-outlined": "template",
|
|
25
|
+
"ex-home-outlined": "home",
|
|
26
|
+
"ex-user-outlined": "user",
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
ICON_ALIAS_MAP = {
|
|
17
|
-
"archive-box": "
|
|
18
|
-
"beaker": "
|
|
19
|
-
"briefcase": "
|
|
20
|
-
"building-office": "
|
|
21
|
-
"calendar": "
|
|
22
|
-
"chat": "
|
|
23
|
-
"chat-bubble-left-right": "
|
|
24
|
-
"chart-bar": "
|
|
25
|
-
"chart-square-bar": "
|
|
26
|
-
"check-badge": "
|
|
27
|
-
"check-circle": "
|
|
28
|
-
"clipboard-check": "
|
|
29
|
-
"clock": "
|
|
30
|
-
"cube": "
|
|
31
|
-
"document-text": "
|
|
32
|
-
"folder": "
|
|
33
|
-
"home": "
|
|
34
|
-
"office-building": "
|
|
35
|
-
"shield-check": "
|
|
36
|
-
"template": "
|
|
37
|
-
"user": "
|
|
38
|
-
"user-group": "
|
|
39
|
-
"users": "
|
|
40
|
-
"view-grid": "
|
|
41
|
-
"warning": "
|
|
30
|
+
"archive-box": "template",
|
|
31
|
+
"beaker": "beaker",
|
|
32
|
+
"briefcase": "briefcase",
|
|
33
|
+
"building-office": "office-building",
|
|
34
|
+
"calendar": "calendar",
|
|
35
|
+
"chat": "chat",
|
|
36
|
+
"chat-bubble-left-right": "chat",
|
|
37
|
+
"chart-bar": "chart-bar",
|
|
38
|
+
"chart-square-bar": "chart-square-bar",
|
|
39
|
+
"check-badge": "badge-check",
|
|
40
|
+
"check-circle": "check-circle",
|
|
41
|
+
"clipboard-check": "clipboard-check",
|
|
42
|
+
"clock": "clock",
|
|
43
|
+
"cube": "cube-transparent",
|
|
44
|
+
"document-text": "document-text",
|
|
45
|
+
"folder": "files-folder",
|
|
46
|
+
"home": "home",
|
|
47
|
+
"office-building": "office-building",
|
|
48
|
+
"shield-check": "shield-check",
|
|
49
|
+
"template": "template",
|
|
50
|
+
"user": "user",
|
|
51
|
+
"user-group": "user-group",
|
|
52
|
+
"users": "user-group",
|
|
53
|
+
"view-grid": "view-grid",
|
|
54
|
+
"warning": "exclamation-circle",
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
|
|
@@ -52,8 +65,6 @@ def encode_workspace_icon(
|
|
|
52
65
|
if icon and _looks_like_icon_json(icon):
|
|
53
66
|
return icon
|
|
54
67
|
normalized_icon_name = normalize_workspace_icon_name(icon or fallback_icon_name)
|
|
55
|
-
if normalized_icon_name and normalized_icon_name.startswith("ex-") and not color:
|
|
56
|
-
return normalized_icon_name
|
|
57
68
|
icon_name = normalized_icon_name
|
|
58
69
|
icon_color = color or DEFAULT_ICON_COLOR
|
|
59
70
|
if icon_name:
|
|
@@ -78,6 +89,65 @@ def encode_workspace_icon(
|
|
|
78
89
|
)
|
|
79
90
|
|
|
80
91
|
|
|
92
|
+
def choose_default_workspace_icon_style(*, title: str) -> tuple[str, str]:
|
|
93
|
+
seed_text = (title or "未命名").strip() or "未命名"
|
|
94
|
+
digest = 0
|
|
95
|
+
for index, char in enumerate(seed_text):
|
|
96
|
+
digest = (digest * 131 + ord(char) + index) % 1_000_003
|
|
97
|
+
return DEFAULT_ICON_STYLE_POOL[digest % len(DEFAULT_ICON_STYLE_POOL)]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def parse_workspace_icon(value: str | None) -> tuple[str | None, str | None, str | None]:
|
|
101
|
+
if not value:
|
|
102
|
+
return None, None, None
|
|
103
|
+
stripped = str(value).strip()
|
|
104
|
+
if not stripped:
|
|
105
|
+
return None, None, None
|
|
106
|
+
if _looks_like_icon_json(stripped):
|
|
107
|
+
try:
|
|
108
|
+
payload = json.loads(stripped)
|
|
109
|
+
except Exception:
|
|
110
|
+
return normalize_workspace_icon_name(stripped), None, None
|
|
111
|
+
icon_name = normalize_workspace_icon_name(payload.get("iconName"))
|
|
112
|
+
icon_color = str(payload.get("iconColor") or "").strip() or None
|
|
113
|
+
icon_text = str(payload.get("iconText") or "").strip() or None
|
|
114
|
+
return icon_name, icon_color, icon_text
|
|
115
|
+
return normalize_workspace_icon_name(stripped), None, None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def encode_workspace_icon_with_defaults(
|
|
119
|
+
*,
|
|
120
|
+
icon: str | None,
|
|
121
|
+
color: str | None,
|
|
122
|
+
title: str,
|
|
123
|
+
fallback_icon_name: str | None = None,
|
|
124
|
+
existing_icon: str | None = None,
|
|
125
|
+
) -> str:
|
|
126
|
+
if icon and _looks_like_icon_json(icon):
|
|
127
|
+
return icon
|
|
128
|
+
if not icon and not color and existing_icon:
|
|
129
|
+
existing_payload = str(existing_icon).strip()
|
|
130
|
+
if existing_payload:
|
|
131
|
+
return existing_payload
|
|
132
|
+
existing_icon_name, existing_icon_color, _ = parse_workspace_icon(existing_icon)
|
|
133
|
+
default_icon, default_color = choose_default_workspace_icon_style(title=title)
|
|
134
|
+
resolved_icon = icon or existing_icon_name
|
|
135
|
+
resolved_color = color or existing_icon_color
|
|
136
|
+
if not resolved_icon:
|
|
137
|
+
if icon is None and color is None:
|
|
138
|
+
resolved_icon = default_icon
|
|
139
|
+
else:
|
|
140
|
+
resolved_icon = fallback_icon_name or default_icon
|
|
141
|
+
if not resolved_color:
|
|
142
|
+
resolved_color = default_color
|
|
143
|
+
return encode_workspace_icon(
|
|
144
|
+
icon=resolved_icon,
|
|
145
|
+
color=resolved_color,
|
|
146
|
+
title=title,
|
|
147
|
+
fallback_icon_name=fallback_icon_name,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
81
151
|
def normalize_workspace_icon_name(icon: str | None) -> str | None:
|
|
82
152
|
if not icon:
|
|
83
153
|
return None
|
|
@@ -85,27 +155,31 @@ def normalize_workspace_icon_name(icon: str | None) -> str | None:
|
|
|
85
155
|
try:
|
|
86
156
|
payload = json.loads(icon)
|
|
87
157
|
except Exception:
|
|
88
|
-
return "
|
|
89
|
-
return normalize_workspace_icon_name(payload.get("iconName")) or "
|
|
90
|
-
if icon in SUPPORTED_EX_ICONS:
|
|
91
|
-
return icon
|
|
158
|
+
return "template"
|
|
159
|
+
return normalize_workspace_icon_name(payload.get("iconName")) or "template"
|
|
92
160
|
normalized = icon.strip().lower()
|
|
161
|
+
if normalized in LEGACY_EX_ICON_MAP:
|
|
162
|
+
return LEGACY_EX_ICON_MAP[normalized]
|
|
93
163
|
if normalized in ICON_ALIAS_MAP:
|
|
94
164
|
return ICON_ALIAS_MAP[normalized]
|
|
95
165
|
for token in normalized.replace("_", "-").split("-"):
|
|
96
166
|
if token in ICON_ALIAS_MAP:
|
|
97
167
|
return ICON_ALIAS_MAP[token]
|
|
98
168
|
if "folder" in normalized or "package" in normalized:
|
|
99
|
-
return "
|
|
100
|
-
if "home" in normalized
|
|
101
|
-
return "
|
|
169
|
+
return "files-folder"
|
|
170
|
+
if "home" in normalized:
|
|
171
|
+
return "home"
|
|
172
|
+
if "portal" in normalized or "dashboard" in normalized:
|
|
173
|
+
return "view-grid"
|
|
102
174
|
if "user" in normalized or "member" in normalized or "contact" in normalized:
|
|
103
|
-
return "
|
|
175
|
+
return "user"
|
|
104
176
|
if "clock" in normalized or "time" in normalized or "schedule" in normalized or "log" in normalized:
|
|
105
|
-
return "
|
|
177
|
+
return "clock"
|
|
106
178
|
if "risk" in normalized or "alert" in normalized or "warn" in normalized or "safety" in normalized:
|
|
107
|
-
return "
|
|
108
|
-
|
|
179
|
+
return "exclamation-circle"
|
|
180
|
+
if re.fullmatch(r"[a-z0-9-]+", normalized):
|
|
181
|
+
return normalized
|
|
182
|
+
return "template"
|
|
109
183
|
|
|
110
184
|
|
|
111
185
|
def _looks_like_icon_json(value: str) -> bool:
|
|
@@ -228,6 +228,8 @@ class AiBuilderTools(ToolBase):
|
|
|
228
228
|
package_tag_id: int | None = None,
|
|
229
229
|
app_name: str = "",
|
|
230
230
|
app_title: str = "",
|
|
231
|
+
icon: str = "",
|
|
232
|
+
color: str = "",
|
|
231
233
|
create_if_missing: bool = False,
|
|
232
234
|
publish: bool = True,
|
|
233
235
|
add_fields: list[JSONObject] | None = None,
|
|
@@ -240,6 +242,8 @@ class AiBuilderTools(ToolBase):
|
|
|
240
242
|
package_tag_id=package_tag_id,
|
|
241
243
|
app_name=app_name,
|
|
242
244
|
app_title=app_title,
|
|
245
|
+
icon=icon,
|
|
246
|
+
color=color,
|
|
243
247
|
create_if_missing=create_if_missing,
|
|
244
248
|
publish=publish,
|
|
245
249
|
add_fields=add_fields or [],
|
|
@@ -713,6 +717,8 @@ class AiBuilderTools(ToolBase):
|
|
|
713
717
|
app_key: str = "",
|
|
714
718
|
package_tag_id: int | None = None,
|
|
715
719
|
app_name: str = "",
|
|
720
|
+
icon: str = "",
|
|
721
|
+
color: str = "",
|
|
716
722
|
create_if_missing: bool = False,
|
|
717
723
|
add_fields: list[JSONObject],
|
|
718
724
|
update_fields: list[JSONObject],
|
|
@@ -724,6 +730,8 @@ class AiBuilderTools(ToolBase):
|
|
|
724
730
|
"app_key": app_key,
|
|
725
731
|
"package_tag_id": package_tag_id,
|
|
726
732
|
"app_name": app_name,
|
|
733
|
+
"icon": icon,
|
|
734
|
+
"color": color,
|
|
727
735
|
"create_if_missing": create_if_missing,
|
|
728
736
|
"add_fields": add_fields,
|
|
729
737
|
"update_fields": update_fields,
|
|
@@ -742,6 +750,8 @@ class AiBuilderTools(ToolBase):
|
|
|
742
750
|
"app_key": app_key,
|
|
743
751
|
"package_tag_id": package_tag_id,
|
|
744
752
|
"app_name": app_name,
|
|
753
|
+
"icon": icon,
|
|
754
|
+
"color": color,
|
|
745
755
|
"create_if_missing": create_if_missing,
|
|
746
756
|
"add_fields": [{"name": "字段名称", "type": "text"}],
|
|
747
757
|
"update_fields": [],
|
|
@@ -889,6 +899,8 @@ class AiBuilderTools(ToolBase):
|
|
|
889
899
|
package_tag_id: int | None = None,
|
|
890
900
|
app_name: str = "",
|
|
891
901
|
app_title: str = "",
|
|
902
|
+
icon: str = "",
|
|
903
|
+
color: str = "",
|
|
892
904
|
create_if_missing: bool = False,
|
|
893
905
|
publish: bool = True,
|
|
894
906
|
add_fields: list[JSONObject],
|
|
@@ -901,6 +913,8 @@ class AiBuilderTools(ToolBase):
|
|
|
901
913
|
package_tag_id=package_tag_id,
|
|
902
914
|
app_name=app_name,
|
|
903
915
|
app_title=app_title,
|
|
916
|
+
icon=icon,
|
|
917
|
+
color=color,
|
|
904
918
|
create_if_missing=create_if_missing,
|
|
905
919
|
publish=publish,
|
|
906
920
|
add_fields=add_fields,
|
|
@@ -916,6 +930,8 @@ class AiBuilderTools(ToolBase):
|
|
|
916
930
|
package_tag_id=package_tag_id,
|
|
917
931
|
app_name=app_name,
|
|
918
932
|
app_title=app_title,
|
|
933
|
+
icon=icon,
|
|
934
|
+
color=color,
|
|
919
935
|
create_if_missing=create_if_missing,
|
|
920
936
|
publish=publish,
|
|
921
937
|
add_fields=add_fields,
|
|
@@ -932,6 +948,8 @@ class AiBuilderTools(ToolBase):
|
|
|
932
948
|
package_tag_id: int | None = None,
|
|
933
949
|
app_name: str = "",
|
|
934
950
|
app_title: str = "",
|
|
951
|
+
icon: str = "",
|
|
952
|
+
color: str = "",
|
|
935
953
|
create_if_missing: bool = False,
|
|
936
954
|
publish: bool = True,
|
|
937
955
|
add_fields: list[JSONObject],
|
|
@@ -945,6 +963,8 @@ class AiBuilderTools(ToolBase):
|
|
|
945
963
|
app_key=app_key,
|
|
946
964
|
package_tag_id=package_tag_id,
|
|
947
965
|
app_name=effective_app_name,
|
|
966
|
+
icon=icon,
|
|
967
|
+
color=color,
|
|
948
968
|
create_if_missing=create_if_missing,
|
|
949
969
|
add_fields=add_fields,
|
|
950
970
|
update_fields=update_fields,
|
|
@@ -976,6 +996,8 @@ class AiBuilderTools(ToolBase):
|
|
|
976
996
|
"app_key": str(plan_args.get("app_key") or app_key),
|
|
977
997
|
"package_tag_id": plan_args.get("package_tag_id", package_tag_id),
|
|
978
998
|
"app_name": str(plan_args.get("app_name") or effective_app_name),
|
|
999
|
+
"icon": str(plan_args.get("icon") or icon),
|
|
1000
|
+
"color": str(plan_args.get("color") or color),
|
|
979
1001
|
"create_if_missing": bool(plan_args.get("create_if_missing", create_if_missing)),
|
|
980
1002
|
"publish": publish,
|
|
981
1003
|
"add_fields": plan_args.get("add_fields") or [{"name": "字段名称", "type": "text", "required": False}],
|
|
@@ -988,6 +1010,8 @@ class AiBuilderTools(ToolBase):
|
|
|
988
1010
|
"app_key": str(plan_args.get("app_key") or app_key),
|
|
989
1011
|
"package_tag_id": plan_args.get("package_tag_id", package_tag_id),
|
|
990
1012
|
"app_name": str(plan_args.get("app_name") or effective_app_name),
|
|
1013
|
+
"icon": str(plan_args.get("icon") or icon or ""),
|
|
1014
|
+
"color": str(plan_args.get("color") or color or ""),
|
|
991
1015
|
"create_if_missing": bool(plan_args.get("create_if_missing", create_if_missing)),
|
|
992
1016
|
"publish": publish,
|
|
993
1017
|
"add_fields": [patch.model_dump(mode="json") for patch in parsed_add],
|
|
@@ -1000,6 +1024,8 @@ class AiBuilderTools(ToolBase):
|
|
|
1000
1024
|
app_key=str(plan_args.get("app_key") or app_key),
|
|
1001
1025
|
package_tag_id=plan_args.get("package_tag_id", package_tag_id),
|
|
1002
1026
|
app_name=str(plan_args.get("app_name") or effective_app_name),
|
|
1027
|
+
icon=str(plan_args.get("icon") or icon or ""),
|
|
1028
|
+
color=str(plan_args.get("color") or color or ""),
|
|
1003
1029
|
create_if_missing=bool(plan_args.get("create_if_missing", create_if_missing)),
|
|
1004
1030
|
publish=publish,
|
|
1005
1031
|
add_fields=parsed_add,
|
|
@@ -1744,6 +1770,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1744
1770
|
"payload.backgroundColor": "payload.background_color",
|
|
1745
1771
|
"payload.textColor": "payload.text_color",
|
|
1746
1772
|
"payload.buttonIcon": "payload.button_icon",
|
|
1773
|
+
"payload.iconColor": "payload.icon_color",
|
|
1747
1774
|
"payload.triggerAction": "payload.trigger_action",
|
|
1748
1775
|
"payload.triggerLinkUrl": "payload.trigger_link_url",
|
|
1749
1776
|
"payload.triggerAddDataConfig": "payload.trigger_add_data_config",
|
|
@@ -1762,6 +1789,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1762
1789
|
"background_color": "#FFFFFF",
|
|
1763
1790
|
"text_color": "#494F57",
|
|
1764
1791
|
"button_icon": "ex-add-outlined",
|
|
1792
|
+
"icon_color": "#494F57",
|
|
1765
1793
|
"trigger_action": "link",
|
|
1766
1794
|
"trigger_link_url": "https://example.com",
|
|
1767
1795
|
},
|
|
@@ -1775,6 +1803,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1775
1803
|
"payload.backgroundColor": "payload.background_color",
|
|
1776
1804
|
"payload.textColor": "payload.text_color",
|
|
1777
1805
|
"payload.buttonIcon": "payload.button_icon",
|
|
1806
|
+
"payload.iconColor": "payload.icon_color",
|
|
1778
1807
|
"payload.triggerAction": "payload.trigger_action",
|
|
1779
1808
|
"payload.triggerLinkUrl": "payload.trigger_link_url",
|
|
1780
1809
|
"payload.triggerAddDataConfig": "payload.trigger_add_data_config",
|
|
@@ -1794,6 +1823,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1794
1823
|
"background_color": "#FFFFFF",
|
|
1795
1824
|
"text_color": "#494F57",
|
|
1796
1825
|
"button_icon": "ex-link-outlined",
|
|
1826
|
+
"icon_color": "#494F57",
|
|
1797
1827
|
"trigger_action": "link",
|
|
1798
1828
|
"trigger_link_url": "https://example.com/detail",
|
|
1799
1829
|
},
|
|
@@ -1810,7 +1840,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1810
1840
|
},
|
|
1811
1841
|
},
|
|
1812
1842
|
"app_schema_plan": {
|
|
1813
|
-
"allowed_keys": ["app_key", "package_tag_id", "app_name", "create_if_missing", "add_fields", "update_fields", "remove_fields"],
|
|
1843
|
+
"allowed_keys": ["app_key", "package_tag_id", "app_name", "icon", "color", "create_if_missing", "add_fields", "update_fields", "remove_fields"],
|
|
1814
1844
|
"aliases": {
|
|
1815
1845
|
"app_title": "app_name",
|
|
1816
1846
|
"title": "app_name",
|
|
@@ -1835,6 +1865,8 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1835
1865
|
"profile": "default",
|
|
1836
1866
|
"app_name": "研发项目管理",
|
|
1837
1867
|
"package_tag_id": 1001,
|
|
1868
|
+
"icon": "template",
|
|
1869
|
+
"color": "emerald",
|
|
1838
1870
|
"create_if_missing": True,
|
|
1839
1871
|
"add_fields": [{"name": "项目名称", "type": "text"}],
|
|
1840
1872
|
"update_fields": [],
|
|
@@ -1858,7 +1890,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1858
1890
|
},
|
|
1859
1891
|
},
|
|
1860
1892
|
"app_schema_apply": {
|
|
1861
|
-
"allowed_keys": ["app_key", "package_tag_id", "app_name", "create_if_missing", "publish", "add_fields", "update_fields", "remove_fields"],
|
|
1893
|
+
"allowed_keys": ["app_key", "package_tag_id", "app_name", "icon", "color", "create_if_missing", "publish", "add_fields", "update_fields", "remove_fields"],
|
|
1862
1894
|
"aliases": {
|
|
1863
1895
|
"app_title": "app_name",
|
|
1864
1896
|
"title": "app_name",
|
|
@@ -1888,6 +1920,8 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1888
1920
|
"profile": "default",
|
|
1889
1921
|
"app_name": "研发项目管理",
|
|
1890
1922
|
"package_tag_id": 1001,
|
|
1923
|
+
"icon": "template",
|
|
1924
|
+
"color": "emerald",
|
|
1891
1925
|
"create_if_missing": True,
|
|
1892
1926
|
"publish": True,
|
|
1893
1927
|
"add_fields": [{"name": "项目名称", "type": "text"}],
|
|
@@ -147,6 +147,7 @@ class CustomButtonTools(ToolBase):
|
|
|
147
147
|
"button_id": item.get("buttonId"),
|
|
148
148
|
"button_text": item.get("buttonText"),
|
|
149
149
|
"button_icon": item.get("buttonIcon"),
|
|
150
|
+
"icon_color": item.get("iconColor"),
|
|
150
151
|
"background_color": item.get("backgroundColor"),
|
|
151
152
|
"text_color": item.get("textColor"),
|
|
152
153
|
"creator_user_info": {
|
|
@@ -165,6 +166,7 @@ class CustomButtonTools(ToolBase):
|
|
|
165
166
|
"button_id": item.get("buttonId"),
|
|
166
167
|
"button_text": item.get("buttonText"),
|
|
167
168
|
"button_icon": item.get("buttonIcon"),
|
|
169
|
+
"icon_color": item.get("iconColor"),
|
|
168
170
|
"background_color": item.get("backgroundColor"),
|
|
169
171
|
"text_color": item.get("textColor"),
|
|
170
172
|
"trigger_action": item.get("triggerAction"),
|