@josephyan/qingflow-cli 0.2.0-beta.88 → 0.2.0-beta.90
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@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-cli@0.2.0-beta.90
|
|
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.90 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.90",
|
|
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",
|
|
@@ -4789,12 +4789,22 @@ class AiBuilderFacade:
|
|
|
4789
4789
|
response = _apply_permission_outcomes(response, relation_permission_outcome)
|
|
4790
4790
|
return finalize(self._append_publish_result(profile=profile, app_key=target.app_key, publish=publish, response=response))
|
|
4791
4791
|
|
|
4792
|
-
payload =
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4792
|
+
payload = (
|
|
4793
|
+
_build_form_payload_from_fields(
|
|
4794
|
+
title=effective_app_name,
|
|
4795
|
+
current_schema=schema_result,
|
|
4796
|
+
fields=current_fields,
|
|
4797
|
+
layout=layout,
|
|
4798
|
+
question_relations=compiled_question_relations,
|
|
4799
|
+
)
|
|
4800
|
+
if bool(resolved.get("created"))
|
|
4801
|
+
else _build_form_payload_for_edit_fields(
|
|
4802
|
+
title=effective_app_name,
|
|
4803
|
+
current_schema=schema_result,
|
|
4804
|
+
fields=current_fields,
|
|
4805
|
+
layout=layout,
|
|
4806
|
+
question_relations=compiled_question_relations,
|
|
4807
|
+
)
|
|
4798
4808
|
)
|
|
4799
4809
|
payload["editVersionNo"] = self._resolve_form_edit_version(
|
|
4800
4810
|
profile=profile,
|
|
@@ -4897,12 +4907,22 @@ class AiBuilderFacade:
|
|
|
4897
4907
|
},
|
|
4898
4908
|
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
4899
4909
|
)
|
|
4900
|
-
rebound_payload =
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4910
|
+
rebound_payload = (
|
|
4911
|
+
_build_form_payload_from_fields(
|
|
4912
|
+
title=effective_app_name,
|
|
4913
|
+
current_schema=rebound_schema,
|
|
4914
|
+
fields=rebound_fields,
|
|
4915
|
+
layout=rebound_layout,
|
|
4916
|
+
question_relations=compiled_question_relations,
|
|
4917
|
+
)
|
|
4918
|
+
if bool(resolved.get("created"))
|
|
4919
|
+
else _build_form_payload_for_edit_fields(
|
|
4920
|
+
title=effective_app_name,
|
|
4921
|
+
current_schema=rebound_schema,
|
|
4922
|
+
fields=rebound_fields,
|
|
4923
|
+
layout=rebound_layout,
|
|
4924
|
+
question_relations=compiled_question_relations,
|
|
4925
|
+
)
|
|
4906
4926
|
)
|
|
4907
4927
|
rebound_payload["editVersionNo"] = self._resolve_form_edit_version(
|
|
4908
4928
|
profile=profile,
|
|
@@ -9844,8 +9864,8 @@ def _parse_field(question: dict[str, Any], *, field_id_hint: str | None = None)
|
|
|
9844
9864
|
"subfields": [],
|
|
9845
9865
|
"que_id": que_id,
|
|
9846
9866
|
"que_type": que_type,
|
|
9847
|
-
"default_type": _coerce_positive_int(question.get("queDefaultType"))
|
|
9848
|
-
"default_value": question.get("queDefaultValue"),
|
|
9867
|
+
"default_type": _coerce_positive_int(question.get("queDefaultType")) if "queDefaultType" in question else None,
|
|
9868
|
+
"default_value": question.get("queDefaultValue") if "queDefaultValue" in question else None,
|
|
9849
9869
|
}
|
|
9850
9870
|
if field_type in {FieldType.single_select.value, FieldType.multi_select.value, FieldType.boolean.value}:
|
|
9851
9871
|
options = question.get("options")
|
|
@@ -9893,7 +9913,6 @@ def _parse_field(question: dict[str, Any], *, field_id_hint: str | None = None)
|
|
|
9893
9913
|
field["visible_fields"] = visible_fields
|
|
9894
9914
|
field["field_name_show"] = bool(reference.get("fieldNameShow", True))
|
|
9895
9915
|
field["_reference_config_template"] = deepcopy(reference)
|
|
9896
|
-
field["_question_template"] = deepcopy(question)
|
|
9897
9916
|
field["_relation_config_explicit"] = False
|
|
9898
9917
|
if field_type == FieldType.department:
|
|
9899
9918
|
department_scope = _normalize_department_scope_from_question(question)
|
|
@@ -9961,6 +9980,7 @@ def _parse_field(question: dict[str, Any], *, field_id_hint: str | None = None)
|
|
|
9961
9980
|
continue
|
|
9962
9981
|
subfields.append(_parse_field(sub_question))
|
|
9963
9982
|
field["subfields"] = subfields
|
|
9983
|
+
field["_question_template"] = deepcopy(question)
|
|
9964
9984
|
return field
|
|
9965
9985
|
|
|
9966
9986
|
|
|
@@ -10847,53 +10867,82 @@ def _apply_field_mutation(field: dict[str, Any], mutation: Any) -> None:
|
|
|
10847
10867
|
payload.get("type") == FieldType.relation.value
|
|
10848
10868
|
or any(key in payload for key in ("target_app_key", "display_field", "visible_fields", "relation_mode"))
|
|
10849
10869
|
)
|
|
10870
|
+
question_overlay_keys = set(cast(list[str], field.get("_question_overlay_keys") or []))
|
|
10871
|
+
question_rebuild_required = bool(field.get("_question_rebuild_required"))
|
|
10850
10872
|
if "name" in payload:
|
|
10851
10873
|
field["name"] = payload["name"]
|
|
10874
|
+
question_overlay_keys.add("name")
|
|
10852
10875
|
if "type" in payload:
|
|
10853
10876
|
field["type"] = payload["type"]
|
|
10877
|
+
question_rebuild_required = True
|
|
10854
10878
|
if "required" in payload:
|
|
10855
10879
|
field["required"] = payload["required"]
|
|
10880
|
+
question_overlay_keys.add("required")
|
|
10856
10881
|
if "description" in payload:
|
|
10857
10882
|
field["description"] = payload["description"]
|
|
10883
|
+
question_overlay_keys.add("description")
|
|
10858
10884
|
if "options" in payload:
|
|
10859
10885
|
field["options"] = list(payload["options"])
|
|
10886
|
+
question_rebuild_required = True
|
|
10860
10887
|
if "target_app_key" in payload:
|
|
10861
10888
|
field["target_app_key"] = payload["target_app_key"]
|
|
10889
|
+
question_rebuild_required = True
|
|
10862
10890
|
if "display_field" in payload:
|
|
10863
10891
|
field["display_field"] = payload["display_field"]
|
|
10892
|
+
question_rebuild_required = True
|
|
10864
10893
|
if "visible_fields" in payload:
|
|
10865
10894
|
field["visible_fields"] = list(payload["visible_fields"])
|
|
10895
|
+
question_rebuild_required = True
|
|
10866
10896
|
if "relation_mode" in payload:
|
|
10867
10897
|
field["relation_mode"] = payload["relation_mode"]
|
|
10898
|
+
question_rebuild_required = True
|
|
10868
10899
|
if "department_scope" in payload:
|
|
10869
10900
|
field["department_scope"] = payload["department_scope"]
|
|
10901
|
+
question_rebuild_required = True
|
|
10870
10902
|
if "remote_lookup_config" in payload:
|
|
10871
10903
|
field["remote_lookup_config"] = payload["remote_lookup_config"]
|
|
10872
10904
|
field["config"] = deepcopy(payload["remote_lookup_config"])
|
|
10873
10905
|
field["_explicit_remote_lookup_config"] = True
|
|
10906
|
+
question_rebuild_required = True
|
|
10874
10907
|
if "q_linker_binding" in payload:
|
|
10875
10908
|
field["q_linker_binding"] = payload["q_linker_binding"]
|
|
10876
10909
|
if "remote_lookup_config" not in payload:
|
|
10877
10910
|
field["_explicit_remote_lookup_config"] = False
|
|
10911
|
+
question_rebuild_required = True
|
|
10878
10912
|
if "code_block_config" in payload:
|
|
10879
10913
|
field["code_block_config"] = payload["code_block_config"]
|
|
10880
10914
|
field["config"] = deepcopy(payload["code_block_config"])
|
|
10915
|
+
question_rebuild_required = True
|
|
10881
10916
|
if "code_block_binding" in payload:
|
|
10882
10917
|
field["code_block_binding"] = payload["code_block_binding"]
|
|
10883
10918
|
field["_explicit_code_block_binding"] = True
|
|
10919
|
+
question_rebuild_required = True
|
|
10884
10920
|
if "auto_trigger" in payload:
|
|
10885
10921
|
field["auto_trigger"] = payload["auto_trigger"]
|
|
10922
|
+
question_rebuild_required = True
|
|
10886
10923
|
if "custom_button_text_enabled" in payload:
|
|
10887
10924
|
field["custom_button_text_enabled"] = payload["custom_button_text_enabled"]
|
|
10925
|
+
question_rebuild_required = True
|
|
10888
10926
|
if "custom_button_text" in payload:
|
|
10889
10927
|
field["custom_button_text"] = payload["custom_button_text"]
|
|
10928
|
+
question_rebuild_required = True
|
|
10890
10929
|
if "subfields" in payload:
|
|
10891
10930
|
field["subfields"] = [_field_patch_to_internal(item) for item in payload["subfields"]]
|
|
10931
|
+
question_rebuild_required = True
|
|
10892
10932
|
if relation_config_explicit:
|
|
10893
10933
|
field["_relation_config_explicit"] = True
|
|
10934
|
+
question_rebuild_required = True
|
|
10894
10935
|
elif payload.get("type") and payload.get("type") != FieldType.relation.value:
|
|
10895
10936
|
field.pop("_relation_config_explicit", None)
|
|
10896
10937
|
field.pop("_reference_config_template", None)
|
|
10938
|
+
if question_overlay_keys:
|
|
10939
|
+
field["_question_overlay_keys"] = sorted(question_overlay_keys)
|
|
10940
|
+
else:
|
|
10941
|
+
field.pop("_question_overlay_keys", None)
|
|
10942
|
+
if question_rebuild_required:
|
|
10943
|
+
field["_question_rebuild_required"] = True
|
|
10944
|
+
else:
|
|
10945
|
+
field.pop("_question_rebuild_required", None)
|
|
10897
10946
|
|
|
10898
10947
|
|
|
10899
10948
|
def _resolve_field_selector_with_uniqueness(
|
|
@@ -12691,6 +12740,42 @@ def _verify_package_attachment(packages: PackageTools, *, profile: str, tag_id:
|
|
|
12691
12740
|
return last_result
|
|
12692
12741
|
|
|
12693
12742
|
|
|
12743
|
+
def _field_question_overlay_keys(field: dict[str, Any]) -> set[str]:
|
|
12744
|
+
raw_value = field.get("_question_overlay_keys")
|
|
12745
|
+
if isinstance(raw_value, set):
|
|
12746
|
+
return {str(item) for item in raw_value if isinstance(item, str) and item}
|
|
12747
|
+
if isinstance(raw_value, list):
|
|
12748
|
+
return {str(item) for item in raw_value if isinstance(item, str) and item}
|
|
12749
|
+
return set()
|
|
12750
|
+
|
|
12751
|
+
|
|
12752
|
+
def _field_needs_question_rebuild(field: dict[str, Any]) -> bool:
|
|
12753
|
+
return not isinstance(field.get("_question_template"), dict) or bool(field.get("_question_rebuild_required"))
|
|
12754
|
+
|
|
12755
|
+
|
|
12756
|
+
def _materialize_preserved_question(field: dict[str, Any]) -> dict[str, Any] | None:
|
|
12757
|
+
template = deepcopy(field.get("_question_template"))
|
|
12758
|
+
if not isinstance(template, dict):
|
|
12759
|
+
return None
|
|
12760
|
+
overlay_keys = _field_question_overlay_keys(field)
|
|
12761
|
+
if "name" in overlay_keys:
|
|
12762
|
+
template["queTitle"] = str(field.get("name") or "")
|
|
12763
|
+
if "required" in overlay_keys:
|
|
12764
|
+
template["required"] = bool(field.get("required", False))
|
|
12765
|
+
if "description" in overlay_keys:
|
|
12766
|
+
description = field.get("description")
|
|
12767
|
+
template["queHint"] = "" if description is None else str(description)
|
|
12768
|
+
return template
|
|
12769
|
+
|
|
12770
|
+
|
|
12771
|
+
def _materialize_edit_question(field: dict[str, Any], *, temp_id: int) -> tuple[dict[str, Any], bool]:
|
|
12772
|
+
if not _field_needs_question_rebuild(field):
|
|
12773
|
+
preserved = _materialize_preserved_question(field)
|
|
12774
|
+
if preserved is not None:
|
|
12775
|
+
return preserved, True
|
|
12776
|
+
return _field_to_question(field, temp_id=temp_id), False
|
|
12777
|
+
|
|
12778
|
+
|
|
12694
12779
|
def _field_to_question(field: dict[str, Any], *, temp_id: int) -> dict[str, Any]:
|
|
12695
12780
|
built_question, _next_temp_id = build_question(
|
|
12696
12781
|
{
|
|
@@ -12746,7 +12831,6 @@ def _field_to_question(field: dict[str, Any], *, temp_id: int) -> dict[str, Any]
|
|
|
12746
12831
|
)
|
|
12747
12832
|
if preserved_reference is not None:
|
|
12748
12833
|
preserved_reference["referAppKey"] = field.get("target_app_key")
|
|
12749
|
-
preserved_reference["_targetEntityId"] = field.get("target_app_key")
|
|
12750
12834
|
question["referenceConfig"] = preserved_reference
|
|
12751
12835
|
else:
|
|
12752
12836
|
reference = deepcopy(question.get("referenceConfig")) if isinstance(question.get("referenceConfig"), dict) else {}
|
|
@@ -12914,6 +12998,96 @@ def _build_form_payload_from_fields(
|
|
|
12914
12998
|
return payload
|
|
12915
12999
|
|
|
12916
13000
|
|
|
13001
|
+
def _build_form_payload_for_edit_fields(
|
|
13002
|
+
*,
|
|
13003
|
+
title: str,
|
|
13004
|
+
current_schema: dict[str, Any],
|
|
13005
|
+
fields: list[dict[str, Any]],
|
|
13006
|
+
layout: dict[str, Any],
|
|
13007
|
+
question_relations: list[dict[str, Any]] | None = None,
|
|
13008
|
+
) -> dict[str, Any]:
|
|
13009
|
+
_, section_templates = _extract_question_templates(current_schema)
|
|
13010
|
+
fields_by_name = {
|
|
13011
|
+
str(field.get("name") or ""): field
|
|
13012
|
+
for field in fields
|
|
13013
|
+
if isinstance(field, dict) and str(field.get("name") or "").strip()
|
|
13014
|
+
}
|
|
13015
|
+
form_rows: list[list[dict[str, Any]]] = []
|
|
13016
|
+
temp_id = -10000
|
|
13017
|
+
|
|
13018
|
+
for row in layout.get("root_rows", []) or []:
|
|
13019
|
+
questions: list[dict[str, Any]] = []
|
|
13020
|
+
row_preserved = True
|
|
13021
|
+
for name in row:
|
|
13022
|
+
field = fields_by_name.get(str(name))
|
|
13023
|
+
if field is None:
|
|
13024
|
+
continue
|
|
13025
|
+
question, preserved = _materialize_edit_question(field, temp_id=temp_id)
|
|
13026
|
+
questions.append(question)
|
|
13027
|
+
row_preserved = row_preserved and preserved
|
|
13028
|
+
temp_id -= 100
|
|
13029
|
+
if not questions:
|
|
13030
|
+
continue
|
|
13031
|
+
if not row_preserved:
|
|
13032
|
+
_apply_row_widths(questions)
|
|
13033
|
+
form_rows.append(questions)
|
|
13034
|
+
|
|
13035
|
+
for section in layout.get("sections", []) or []:
|
|
13036
|
+
inner_rows: list[list[dict[str, Any]]] = []
|
|
13037
|
+
for row in section.get("rows", []) or []:
|
|
13038
|
+
questions: list[dict[str, Any]] = []
|
|
13039
|
+
row_preserved = True
|
|
13040
|
+
for name in row:
|
|
13041
|
+
field = fields_by_name.get(str(name))
|
|
13042
|
+
if field is None:
|
|
13043
|
+
continue
|
|
13044
|
+
question, preserved = _materialize_edit_question(field, temp_id=temp_id)
|
|
13045
|
+
questions.append(question)
|
|
13046
|
+
row_preserved = row_preserved and preserved
|
|
13047
|
+
temp_id -= 100
|
|
13048
|
+
if not questions:
|
|
13049
|
+
continue
|
|
13050
|
+
if not row_preserved:
|
|
13051
|
+
_apply_row_widths(questions)
|
|
13052
|
+
inner_rows.append(questions)
|
|
13053
|
+
if not inner_rows:
|
|
13054
|
+
continue
|
|
13055
|
+
template = _select_section_template(section_templates, section)
|
|
13056
|
+
wrapper = deepcopy(template) if isinstance(template, dict) else {
|
|
13057
|
+
"queId": 0,
|
|
13058
|
+
"queTempId": -(20000 + sum(ord(ch) for ch in str(section.get("section_id") or section.get("title") or "section"))),
|
|
13059
|
+
"queType": 24,
|
|
13060
|
+
"queWidth": 100,
|
|
13061
|
+
"scanType": 1,
|
|
13062
|
+
"status": 1,
|
|
13063
|
+
"required": False,
|
|
13064
|
+
"queHint": "",
|
|
13065
|
+
"linkedQuestions": {},
|
|
13066
|
+
"logicalShow": True,
|
|
13067
|
+
"queDefaultValue": None,
|
|
13068
|
+
"queDefaultType": 1,
|
|
13069
|
+
"subQueWidth": 2,
|
|
13070
|
+
"beingHide": False,
|
|
13071
|
+
"beingDesensitized": False,
|
|
13072
|
+
}
|
|
13073
|
+
if section.get("title") is not None:
|
|
13074
|
+
wrapper["queTitle"] = section.get("title") or wrapper.get("queTitle") or "未命名分组"
|
|
13075
|
+
parsed_section_id = _coerce_positive_int(section.get("section_id"))
|
|
13076
|
+
if parsed_section_id is not None:
|
|
13077
|
+
wrapper["sectionId"] = parsed_section_id
|
|
13078
|
+
elif template is None and section.get("section_id") is not None:
|
|
13079
|
+
wrapper["sectionId"] = section.get("section_id")
|
|
13080
|
+
wrapper["innerQuestions"] = inner_rows
|
|
13081
|
+
form_rows.append([wrapper])
|
|
13082
|
+
|
|
13083
|
+
payload = deepcopy(current_schema)
|
|
13084
|
+
payload["formTitle"] = title
|
|
13085
|
+
payload["formQues"] = form_rows
|
|
13086
|
+
payload["questionRelations"] = deepcopy(question_relations if question_relations is not None else (current_schema.get("questionRelations") or []))
|
|
13087
|
+
payload["editVersionNo"] = int(current_schema.get("editVersionNo") or 1)
|
|
13088
|
+
return payload
|
|
13089
|
+
|
|
13090
|
+
|
|
12917
13091
|
def _apply_row_widths(row: list[dict[str, Any]]) -> None:
|
|
12918
13092
|
if not row:
|
|
12919
13093
|
return
|
|
@@ -180,6 +180,16 @@ class AccessibleViewRoute:
|
|
|
180
180
|
view_type: str | None = None
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
@dataclass(slots=True)
|
|
184
|
+
class RecordContextRouteProbe:
|
|
185
|
+
route: AccessibleViewRoute
|
|
186
|
+
answer_list: list[JSONObject] | None
|
|
187
|
+
used_list_type: int | None
|
|
188
|
+
readable: bool
|
|
189
|
+
transport_error: bool
|
|
190
|
+
error_payload: JSONObject | None
|
|
191
|
+
|
|
192
|
+
|
|
183
193
|
@dataclass(slots=True)
|
|
184
194
|
class WorkflowNodeRef:
|
|
185
195
|
workflow_node_id: int
|
|
@@ -782,55 +792,29 @@ class RecordTools(ToolBase):
|
|
|
782
792
|
index=app_index,
|
|
783
793
|
question_relations=question_relations,
|
|
784
794
|
)
|
|
785
|
-
try:
|
|
786
|
-
current_answers = self._load_record_answers_for_preflight(context, app_key=app_key, apply_id=record_id)
|
|
787
|
-
except QingflowApiError:
|
|
788
|
-
return self._record_update_schema_blocked_response(
|
|
789
|
-
profile=profile,
|
|
790
|
-
ws_id=session_profile.selected_ws_id,
|
|
791
|
-
request_route=request_route,
|
|
792
|
-
app_key=app_key,
|
|
793
|
-
record_id=record_id,
|
|
794
|
-
blockers=["CURRENT_RECORD_CONTEXT_UNAVAILABLE"],
|
|
795
|
-
warnings=[
|
|
796
|
-
"update schema could not load the current record; context-sensitive lookup requirements cannot be derived safely."
|
|
797
|
-
],
|
|
798
|
-
recommended_next_actions=[
|
|
799
|
-
"Retry after the record becomes readable in the current workspace/profile context.",
|
|
800
|
-
"If the issue persists, verify that the current profile still has read access to this record.",
|
|
801
|
-
],
|
|
802
|
-
output_profile=normalized_output_profile,
|
|
803
|
-
view_probe_summary=[],
|
|
804
|
-
ambiguous_fields=[],
|
|
805
|
-
)
|
|
806
|
-
|
|
807
795
|
candidate_routes = self._candidate_update_views(profile, context, app_key)
|
|
796
|
+
probes = self._probe_candidate_record_contexts(
|
|
797
|
+
context,
|
|
798
|
+
app_key=app_key,
|
|
799
|
+
apply_id=record_id,
|
|
800
|
+
candidate_routes=candidate_routes,
|
|
801
|
+
)
|
|
808
802
|
probe_summary: list[JSONObject] = []
|
|
809
|
-
|
|
803
|
+
matched_probes: list[RecordContextRouteProbe] = []
|
|
810
804
|
ordered_field_ids: list[int] = []
|
|
811
805
|
field_payloads_by_id: dict[int, JSONObject] = {}
|
|
812
806
|
title_to_field_ids: dict[str, list[int]] = {}
|
|
813
807
|
ws_id = session_profile.selected_ws_id
|
|
814
808
|
|
|
815
|
-
for
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
)
|
|
821
|
-
candidate_summary: JSONObject = {
|
|
822
|
-
"view_id": candidate.view_id,
|
|
823
|
-
"name": candidate.name,
|
|
824
|
-
"kind": candidate.kind,
|
|
825
|
-
"matched_record": matched_record,
|
|
826
|
-
"context_complete": True,
|
|
827
|
-
"writable_field_titles": [],
|
|
828
|
-
}
|
|
829
|
-
if not matched_record:
|
|
809
|
+
for probe in probes:
|
|
810
|
+
candidate = probe.route
|
|
811
|
+
candidate_summary = self._record_context_probe_summary_payload(probe)
|
|
812
|
+
candidate_summary["writable_field_titles"] = []
|
|
813
|
+
if not probe.readable:
|
|
830
814
|
probe_summary.append(candidate_summary)
|
|
831
815
|
continue
|
|
832
816
|
|
|
833
|
-
|
|
817
|
+
matched_probes.append(probe)
|
|
834
818
|
browse_scope = self._build_browse_write_scope(
|
|
835
819
|
profile,
|
|
836
820
|
context,
|
|
@@ -874,19 +858,39 @@ class RecordTools(ToolBase):
|
|
|
874
858
|
candidate_summary["writable_field_titles"] = candidate_titles
|
|
875
859
|
probe_summary.append(candidate_summary)
|
|
876
860
|
|
|
877
|
-
if not
|
|
861
|
+
if not matched_probes:
|
|
862
|
+
blockers = (
|
|
863
|
+
["CURRENT_RECORD_CONTEXT_UNAVAILABLE"]
|
|
864
|
+
if probes and all(probe.transport_error for probe in probes)
|
|
865
|
+
else ["NO_MATCHING_ACCESSIBLE_VIEW_FOR_RECORD"]
|
|
866
|
+
)
|
|
867
|
+
warnings = (
|
|
868
|
+
[
|
|
869
|
+
"update schema could not load the current record from any candidate route; context-sensitive lookup requirements cannot be derived safely."
|
|
870
|
+
]
|
|
871
|
+
if blockers == ["CURRENT_RECORD_CONTEXT_UNAVAILABLE"]
|
|
872
|
+
else []
|
|
873
|
+
)
|
|
874
|
+
recommended_next_actions = (
|
|
875
|
+
[
|
|
876
|
+
"Retry after the record becomes readable in the current workspace/profile context.",
|
|
877
|
+
"If the issue persists, verify that the current profile still has read access to this record.",
|
|
878
|
+
]
|
|
879
|
+
if blockers == ["CURRENT_RECORD_CONTEXT_UNAVAILABLE"]
|
|
880
|
+
else [
|
|
881
|
+
"Check whether this record is still visible in any accessible view for the current profile.",
|
|
882
|
+
"Use record_get or record_list to confirm the record still exists in the current workspace.",
|
|
883
|
+
]
|
|
884
|
+
)
|
|
878
885
|
return self._record_update_schema_blocked_response(
|
|
879
886
|
profile=profile,
|
|
880
887
|
ws_id=ws_id,
|
|
881
888
|
request_route=request_route,
|
|
882
889
|
app_key=app_key,
|
|
883
890
|
record_id=record_id,
|
|
884
|
-
blockers=
|
|
885
|
-
warnings=
|
|
886
|
-
recommended_next_actions=
|
|
887
|
-
"Check whether this record is still visible in any accessible view for the current profile.",
|
|
888
|
-
"Use record_get or record_list to confirm the record still exists in the current workspace.",
|
|
889
|
-
],
|
|
891
|
+
blockers=blockers,
|
|
892
|
+
warnings=warnings,
|
|
893
|
+
recommended_next_actions=recommended_next_actions,
|
|
890
894
|
output_profile=normalized_output_profile,
|
|
891
895
|
view_probe_summary=probe_summary,
|
|
892
896
|
ambiguous_fields=[],
|
|
@@ -894,7 +898,10 @@ class RecordTools(ToolBase):
|
|
|
894
898
|
|
|
895
899
|
ambiguous_field_ids: set[int] = set()
|
|
896
900
|
ambiguous_fields: list[JSONObject] = []
|
|
897
|
-
warnings: list[JSONObject] = [
|
|
901
|
+
warnings: list[JSONObject] = [
|
|
902
|
+
{"code": "RECORD_CONTEXT_ROUTE_FALLBACK", "message": message}
|
|
903
|
+
for message in self._record_context_probe_fallback_warnings(probes)
|
|
904
|
+
]
|
|
898
905
|
for title, field_ids in title_to_field_ids.items():
|
|
899
906
|
unique_ids = list(dict.fromkeys(field_ids))
|
|
900
907
|
if len(unique_ids) <= 1:
|
|
@@ -953,6 +960,7 @@ class RecordTools(ToolBase):
|
|
|
953
960
|
}
|
|
954
961
|
if normalized_output_profile == "verbose":
|
|
955
962
|
response["view_probe_summary"] = probe_summary
|
|
963
|
+
response["record_context_probe"] = probe_summary
|
|
956
964
|
response["ambiguous_fields"] = ambiguous_fields
|
|
957
965
|
return response
|
|
958
966
|
|
|
@@ -2286,9 +2294,15 @@ class RecordTools(ToolBase):
|
|
|
2286
2294
|
def runner(session_profile, context):
|
|
2287
2295
|
request_route = self._request_route_payload(context)
|
|
2288
2296
|
def build_once(*, effective_force_refresh: bool) -> JSONObject:
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2297
|
+
candidate_routes = self._candidate_update_views(profile, context, app_key)
|
|
2298
|
+
probes = self._probe_candidate_record_contexts(
|
|
2299
|
+
context,
|
|
2300
|
+
app_key=app_key,
|
|
2301
|
+
apply_id=record_id,
|
|
2302
|
+
candidate_routes=candidate_routes,
|
|
2303
|
+
)
|
|
2304
|
+
matched_probes = [probe for probe in probes if probe.readable]
|
|
2305
|
+
if not matched_probes and probes and all(probe.transport_error for probe in probes):
|
|
2292
2306
|
return {
|
|
2293
2307
|
"profile": profile,
|
|
2294
2308
|
"ws_id": session_profile.selected_ws_id,
|
|
@@ -2299,46 +2313,40 @@ class RecordTools(ToolBase):
|
|
|
2299
2313
|
record_id=record_id,
|
|
2300
2314
|
blockers=["CURRENT_RECORD_CONTEXT_UNAVAILABLE"],
|
|
2301
2315
|
warnings=[
|
|
2302
|
-
"update preflight could not load the current record; automatic view selection was blocked to avoid resolving lookup fields against a partial patch."
|
|
2316
|
+
"update preflight could not load the current record from any candidate route; automatic view selection was blocked to avoid resolving lookup fields against a partial patch."
|
|
2303
2317
|
],
|
|
2304
2318
|
recommended_next_actions=[
|
|
2305
2319
|
"Retry after the record becomes readable in the current workspace/profile context.",
|
|
2306
2320
|
"Call record_update_schema_get to inspect the overall writable field set for this record after context access is restored.",
|
|
2307
2321
|
],
|
|
2308
|
-
view_probe_summary=[
|
|
2322
|
+
view_probe_summary=[
|
|
2323
|
+
self._record_context_probe_summary_payload(probe)
|
|
2324
|
+
for probe in probes
|
|
2325
|
+
],
|
|
2309
2326
|
),
|
|
2310
2327
|
}
|
|
2311
2328
|
|
|
2312
|
-
candidate_routes = self._candidate_update_views(profile, context, app_key)
|
|
2313
2329
|
probe_summary: list[JSONObject] = []
|
|
2314
|
-
matched_any = False
|
|
2315
2330
|
matched_routes: list[AccessibleViewRoute] = []
|
|
2331
|
+
matched_answers_for_union: list[JSONObject] | None = None
|
|
2316
2332
|
first_blocked_plan: JSONObject | None = None
|
|
2317
2333
|
first_confirmation_plan: JSONObject | None = None
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
"view_id": candidate.view_id,
|
|
2329
|
-
"name": candidate.name,
|
|
2330
|
-
"kind": candidate.kind,
|
|
2331
|
-
"matched_record": False,
|
|
2332
|
-
"writable_field_titles": [],
|
|
2333
|
-
"missing_field_titles": [],
|
|
2334
|
-
"context_complete": True,
|
|
2335
|
-
"selected": False,
|
|
2336
|
-
}
|
|
2337
|
-
)
|
|
2334
|
+
fallback_warning_messages = self._record_context_probe_fallback_warnings(probes)
|
|
2335
|
+
|
|
2336
|
+
for probe in probes:
|
|
2337
|
+
candidate = probe.route
|
|
2338
|
+
candidate_summary = self._record_context_probe_summary_payload(probe)
|
|
2339
|
+
candidate_summary["writable_field_titles"] = []
|
|
2340
|
+
candidate_summary["missing_field_titles"] = []
|
|
2341
|
+
candidate_summary["selected"] = False
|
|
2342
|
+
if not probe.readable:
|
|
2343
|
+
probe_summary.append(candidate_summary)
|
|
2338
2344
|
continue
|
|
2339
2345
|
|
|
2340
|
-
|
|
2346
|
+
current_answers = probe.answer_list or []
|
|
2341
2347
|
matched_routes.append(candidate)
|
|
2348
|
+
if matched_answers_for_union is None:
|
|
2349
|
+
matched_answers_for_union = current_answers
|
|
2342
2350
|
browse_scope = self._build_browse_write_scope(
|
|
2343
2351
|
profile,
|
|
2344
2352
|
context,
|
|
@@ -2394,16 +2402,8 @@ class RecordTools(ToolBase):
|
|
|
2394
2402
|
title = _normalize_optional_text(field_payload.get("que_title"))
|
|
2395
2403
|
if title and title not in missing_field_titles:
|
|
2396
2404
|
missing_field_titles.append(title)
|
|
2397
|
-
candidate_summary
|
|
2398
|
-
|
|
2399
|
-
"name": candidate.name,
|
|
2400
|
-
"kind": candidate.kind,
|
|
2401
|
-
"matched_record": True,
|
|
2402
|
-
"writable_field_titles": candidate_titles,
|
|
2403
|
-
"missing_field_titles": missing_field_titles,
|
|
2404
|
-
"context_complete": True,
|
|
2405
|
-
"selected": False,
|
|
2406
|
-
}
|
|
2405
|
+
candidate_summary["writable_field_titles"] = candidate_titles
|
|
2406
|
+
candidate_summary["missing_field_titles"] = missing_field_titles
|
|
2407
2407
|
if plan_data.get("blockers"):
|
|
2408
2408
|
confirmation_requests = plan_data.get("confirmation_requests")
|
|
2409
2409
|
if (
|
|
@@ -2422,8 +2422,26 @@ class RecordTools(ToolBase):
|
|
|
2422
2422
|
view_payload["auto_selected"] = True
|
|
2423
2423
|
view_payload["selection_source"] = "first_satisfying_accessible_view"
|
|
2424
2424
|
candidate_summary["selected"] = True
|
|
2425
|
+
validation = plan_data.get("validation")
|
|
2426
|
+
if isinstance(validation, dict):
|
|
2427
|
+
warnings = validation.get("warnings")
|
|
2428
|
+
if not isinstance(warnings, list):
|
|
2429
|
+
warnings = []
|
|
2430
|
+
validation["warnings"] = warnings
|
|
2431
|
+
for message in fallback_warning_messages:
|
|
2432
|
+
if message not in warnings:
|
|
2433
|
+
warnings.append(message)
|
|
2425
2434
|
first_confirmation_plan = plan_data
|
|
2426
2435
|
elif first_blocked_plan is None:
|
|
2436
|
+
validation = plan_data.get("validation")
|
|
2437
|
+
if isinstance(validation, dict):
|
|
2438
|
+
warnings = validation.get("warnings")
|
|
2439
|
+
if not isinstance(warnings, list):
|
|
2440
|
+
warnings = []
|
|
2441
|
+
validation["warnings"] = warnings
|
|
2442
|
+
for message in fallback_warning_messages:
|
|
2443
|
+
if message not in warnings:
|
|
2444
|
+
warnings.append(message)
|
|
2427
2445
|
first_blocked_plan = plan_data
|
|
2428
2446
|
probe_summary.append(candidate_summary)
|
|
2429
2447
|
continue
|
|
@@ -2439,8 +2457,18 @@ class RecordTools(ToolBase):
|
|
|
2439
2457
|
view_payload["auto_selected"] = True
|
|
2440
2458
|
view_payload["selection_source"] = "first_satisfying_accessible_view"
|
|
2441
2459
|
candidate_summary["selected"] = True
|
|
2460
|
+
validation = plan_data.get("validation")
|
|
2461
|
+
if isinstance(validation, dict):
|
|
2462
|
+
warnings = validation.get("warnings")
|
|
2463
|
+
if not isinstance(warnings, list):
|
|
2464
|
+
warnings = []
|
|
2465
|
+
validation["warnings"] = warnings
|
|
2466
|
+
for message in fallback_warning_messages:
|
|
2467
|
+
if message not in warnings:
|
|
2468
|
+
warnings.append(message)
|
|
2442
2469
|
probe_summary.append(candidate_summary)
|
|
2443
2470
|
plan_data["view_probe_summary"] = probe_summary
|
|
2471
|
+
plan_data["record_context_probe"] = probe_summary
|
|
2444
2472
|
return {
|
|
2445
2473
|
"profile": profile,
|
|
2446
2474
|
"ws_id": session_profile.selected_ws_id,
|
|
@@ -2449,7 +2477,7 @@ class RecordTools(ToolBase):
|
|
|
2449
2477
|
"data": plan_data,
|
|
2450
2478
|
}
|
|
2451
2479
|
|
|
2452
|
-
if not
|
|
2480
|
+
if not matched_probes:
|
|
2453
2481
|
blocked_data = self._build_auto_view_blocked_preflight_data(
|
|
2454
2482
|
app_key=app_key,
|
|
2455
2483
|
record_id=record_id,
|
|
@@ -2471,6 +2499,7 @@ class RecordTools(ToolBase):
|
|
|
2471
2499
|
|
|
2472
2500
|
if first_confirmation_plan is not None:
|
|
2473
2501
|
first_confirmation_plan["view_probe_summary"] = probe_summary
|
|
2502
|
+
first_confirmation_plan["record_context_probe"] = probe_summary
|
|
2474
2503
|
return {
|
|
2475
2504
|
"profile": profile,
|
|
2476
2505
|
"ws_id": session_profile.selected_ws_id,
|
|
@@ -2485,12 +2514,22 @@ class RecordTools(ToolBase):
|
|
|
2485
2514
|
app_key=app_key,
|
|
2486
2515
|
record_id=record_id,
|
|
2487
2516
|
fields=fields,
|
|
2488
|
-
current_answers=
|
|
2517
|
+
current_answers=matched_answers_for_union or [],
|
|
2489
2518
|
matched_routes=matched_routes,
|
|
2490
2519
|
force_refresh_form=effective_force_refresh,
|
|
2491
2520
|
)
|
|
2492
2521
|
if union_plan is not None:
|
|
2522
|
+
validation = union_plan.get("validation")
|
|
2523
|
+
if isinstance(validation, dict):
|
|
2524
|
+
warnings = validation.get("warnings")
|
|
2525
|
+
if not isinstance(warnings, list):
|
|
2526
|
+
warnings = []
|
|
2527
|
+
validation["warnings"] = warnings
|
|
2528
|
+
for message in fallback_warning_messages:
|
|
2529
|
+
if message not in warnings:
|
|
2530
|
+
warnings.append(message)
|
|
2493
2531
|
union_plan["view_probe_summary"] = probe_summary
|
|
2532
|
+
union_plan["record_context_probe"] = probe_summary
|
|
2494
2533
|
return {
|
|
2495
2534
|
"profile": profile,
|
|
2496
2535
|
"ws_id": session_profile.selected_ws_id,
|
|
@@ -2785,6 +2824,161 @@ class RecordTools(ToolBase):
|
|
|
2785
2824
|
)
|
|
2786
2825
|
return candidates
|
|
2787
2826
|
|
|
2827
|
+
def _route_view_key(self, resolved_view: AccessibleViewRoute) -> str | None:
|
|
2828
|
+
if resolved_view.view_selection is not None:
|
|
2829
|
+
view_key = _normalize_optional_text(resolved_view.view_selection.view_key)
|
|
2830
|
+
if view_key:
|
|
2831
|
+
return view_key
|
|
2832
|
+
if resolved_view.kind == "custom" and resolved_view.view_id.startswith("custom:"):
|
|
2833
|
+
view_key = resolved_view.view_id.split(":", 1)[1].strip()
|
|
2834
|
+
return view_key or None
|
|
2835
|
+
return None
|
|
2836
|
+
|
|
2837
|
+
def _record_context_route_error_payload(self, error: QingflowApiError) -> JSONObject:
|
|
2838
|
+
payload: JSONObject = {"message": error.message}
|
|
2839
|
+
if error.category:
|
|
2840
|
+
payload["category"] = error.category
|
|
2841
|
+
if error.backend_code is not None:
|
|
2842
|
+
payload["backend_code"] = error.backend_code
|
|
2843
|
+
if error.http_status is not None:
|
|
2844
|
+
payload["http_status"] = error.http_status
|
|
2845
|
+
return payload
|
|
2846
|
+
|
|
2847
|
+
def _is_record_context_route_miss(self, error: QingflowApiError) -> bool:
|
|
2848
|
+
if error.backend_code in {40002, 40027, 40038, 404}:
|
|
2849
|
+
return True
|
|
2850
|
+
if error.http_status == 404:
|
|
2851
|
+
return True
|
|
2852
|
+
return False
|
|
2853
|
+
|
|
2854
|
+
def _load_record_answers_for_accessible_route(
|
|
2855
|
+
self,
|
|
2856
|
+
context, # type: ignore[no-untyped-def]
|
|
2857
|
+
*,
|
|
2858
|
+
app_key: str,
|
|
2859
|
+
apply_id: int,
|
|
2860
|
+
resolved_view: AccessibleViewRoute,
|
|
2861
|
+
) -> tuple[list[JSONObject], int | None]:
|
|
2862
|
+
if resolved_view.kind == "custom":
|
|
2863
|
+
view_key = self._route_view_key(resolved_view)
|
|
2864
|
+
if not view_key:
|
|
2865
|
+
raise_tool_error(
|
|
2866
|
+
QingflowApiError.config_error(
|
|
2867
|
+
f"cannot resolve custom view route for '{resolved_view.view_id}'"
|
|
2868
|
+
)
|
|
2869
|
+
)
|
|
2870
|
+
record = self.backend.request(
|
|
2871
|
+
"GET",
|
|
2872
|
+
context,
|
|
2873
|
+
f"/view/{view_key}/apply/{apply_id}",
|
|
2874
|
+
)
|
|
2875
|
+
used_list_type = None
|
|
2876
|
+
else:
|
|
2877
|
+
used_list_type = resolved_view.list_type if resolved_view.list_type is not None else DEFAULT_RECORD_LIST_TYPE
|
|
2878
|
+
record = self.backend.request(
|
|
2879
|
+
"GET",
|
|
2880
|
+
context,
|
|
2881
|
+
f"/app/{app_key}/apply/{apply_id}",
|
|
2882
|
+
params={"role": 1, "listType": used_list_type},
|
|
2883
|
+
)
|
|
2884
|
+
answers = record.get("answers") if isinstance(record, dict) else None
|
|
2885
|
+
normalized_answers = [item for item in answers if isinstance(item, dict)] if isinstance(answers, list) else []
|
|
2886
|
+
return normalized_answers, used_list_type
|
|
2887
|
+
|
|
2888
|
+
def _probe_record_context_route(
|
|
2889
|
+
self,
|
|
2890
|
+
context, # type: ignore[no-untyped-def]
|
|
2891
|
+
*,
|
|
2892
|
+
app_key: str,
|
|
2893
|
+
apply_id: int,
|
|
2894
|
+
resolved_view: AccessibleViewRoute,
|
|
2895
|
+
) -> RecordContextRouteProbe:
|
|
2896
|
+
try:
|
|
2897
|
+
answer_list, used_list_type = self._load_record_answers_for_accessible_route(
|
|
2898
|
+
context,
|
|
2899
|
+
app_key=app_key,
|
|
2900
|
+
apply_id=apply_id,
|
|
2901
|
+
resolved_view=resolved_view,
|
|
2902
|
+
)
|
|
2903
|
+
return RecordContextRouteProbe(
|
|
2904
|
+
route=resolved_view,
|
|
2905
|
+
answer_list=answer_list,
|
|
2906
|
+
used_list_type=used_list_type,
|
|
2907
|
+
readable=True,
|
|
2908
|
+
transport_error=False,
|
|
2909
|
+
error_payload=None,
|
|
2910
|
+
)
|
|
2911
|
+
except QingflowApiError as exc:
|
|
2912
|
+
return RecordContextRouteProbe(
|
|
2913
|
+
route=resolved_view,
|
|
2914
|
+
answer_list=None,
|
|
2915
|
+
used_list_type=resolved_view.list_type if resolved_view.kind == "system" else None,
|
|
2916
|
+
readable=False,
|
|
2917
|
+
transport_error=not self._is_record_context_route_miss(exc),
|
|
2918
|
+
error_payload=self._record_context_route_error_payload(exc),
|
|
2919
|
+
)
|
|
2920
|
+
|
|
2921
|
+
def _probe_candidate_record_contexts(
|
|
2922
|
+
self,
|
|
2923
|
+
context, # type: ignore[no-untyped-def]
|
|
2924
|
+
*,
|
|
2925
|
+
app_key: str,
|
|
2926
|
+
apply_id: int,
|
|
2927
|
+
candidate_routes: list[AccessibleViewRoute],
|
|
2928
|
+
) -> list[RecordContextRouteProbe]:
|
|
2929
|
+
return [
|
|
2930
|
+
self._probe_record_context_route(
|
|
2931
|
+
context,
|
|
2932
|
+
app_key=app_key,
|
|
2933
|
+
apply_id=apply_id,
|
|
2934
|
+
resolved_view=candidate,
|
|
2935
|
+
)
|
|
2936
|
+
for candidate in candidate_routes
|
|
2937
|
+
]
|
|
2938
|
+
|
|
2939
|
+
def _record_context_probe_summary_payload(self, probe: RecordContextRouteProbe) -> JSONObject:
|
|
2940
|
+
payload: JSONObject = {
|
|
2941
|
+
"view_id": probe.route.view_id,
|
|
2942
|
+
"name": probe.route.name,
|
|
2943
|
+
"kind": probe.route.kind,
|
|
2944
|
+
"matched_record": probe.readable,
|
|
2945
|
+
"readable": probe.readable,
|
|
2946
|
+
"context_complete": probe.readable,
|
|
2947
|
+
"used_list_type": probe.used_list_type,
|
|
2948
|
+
}
|
|
2949
|
+
if probe.error_payload is not None:
|
|
2950
|
+
payload["error"] = probe.error_payload
|
|
2951
|
+
payload["transport_error"] = probe.transport_error
|
|
2952
|
+
return payload
|
|
2953
|
+
|
|
2954
|
+
def _record_context_probe_fallback_warnings(
|
|
2955
|
+
self,
|
|
2956
|
+
probes: list[RecordContextRouteProbe],
|
|
2957
|
+
) -> list[str]:
|
|
2958
|
+
matched_probes = [probe for probe in probes if probe.readable]
|
|
2959
|
+
if not matched_probes:
|
|
2960
|
+
return []
|
|
2961
|
+
if any(
|
|
2962
|
+
probe.route.kind == "system" and probe.used_list_type == DEFAULT_RECORD_LIST_TYPE
|
|
2963
|
+
for probe in matched_probes
|
|
2964
|
+
):
|
|
2965
|
+
return []
|
|
2966
|
+
first_probe = matched_probes[0]
|
|
2967
|
+
if first_probe.route.kind == "custom":
|
|
2968
|
+
return [
|
|
2969
|
+
"current record context was not accessible via listType="
|
|
2970
|
+
f"{DEFAULT_RECORD_LIST_TYPE}; preflight resolved it via custom view "
|
|
2971
|
+
f"'{first_probe.route.name}'."
|
|
2972
|
+
]
|
|
2973
|
+
used_list_type = first_probe.used_list_type
|
|
2974
|
+
if used_list_type is None:
|
|
2975
|
+
return []
|
|
2976
|
+
return [
|
|
2977
|
+
"current record context was not accessible via listType="
|
|
2978
|
+
f"{DEFAULT_RECORD_LIST_TYPE}; preflight resolved it via listType={used_list_type} "
|
|
2979
|
+
f"({get_record_list_type_label(used_list_type)})."
|
|
2980
|
+
]
|
|
2981
|
+
|
|
2788
2982
|
def _record_matches_accessible_view(
|
|
2789
2983
|
self,
|
|
2790
2984
|
context, # type: ignore[no-untyped-def]
|
|
@@ -5276,7 +5470,19 @@ class RecordTools(ToolBase):
|
|
|
5276
5470
|
existing_answers_loaded = True
|
|
5277
5471
|
else:
|
|
5278
5472
|
try:
|
|
5279
|
-
|
|
5473
|
+
if resolved_view is not None:
|
|
5474
|
+
existing_answers_for_update, _used_list_type = self._load_record_answers_for_accessible_route(
|
|
5475
|
+
context,
|
|
5476
|
+
app_key=app_key,
|
|
5477
|
+
apply_id=apply_id,
|
|
5478
|
+
resolved_view=resolved_view,
|
|
5479
|
+
)
|
|
5480
|
+
else:
|
|
5481
|
+
existing_answers_for_update = self._load_record_answers_for_preflight(
|
|
5482
|
+
context,
|
|
5483
|
+
app_key=app_key,
|
|
5484
|
+
apply_id=apply_id,
|
|
5485
|
+
)
|
|
5280
5486
|
existing_answers_loaded = True
|
|
5281
5487
|
except QingflowApiError:
|
|
5282
5488
|
validation_warnings.append(
|