@josephyan/qingflow-cli 0.2.0-beta.55 → 0.2.0-beta.57
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/cli/commands/app.py +16 -16
- package/src/qingflow_mcp/cli/commands/auth.py +16 -19
- package/src/qingflow_mcp/cli/commands/builder.py +162 -124
- package/src/qingflow_mcp/cli/commands/common.py +95 -21
- package/src/qingflow_mcp/cli/commands/imports.py +34 -42
- package/src/qingflow_mcp/cli/commands/record.py +133 -131
- package/src/qingflow_mcp/cli/commands/task.py +44 -43
- package/src/qingflow_mcp/cli/commands/workspace.py +10 -10
- package/src/qingflow_mcp/cli/context.py +32 -35
- package/src/qingflow_mcp/cli/formatters.py +121 -124
- package/src/qingflow_mcp/cli/main.py +17 -52
- package/src/qingflow_mcp/ops/__init__.py +3 -0
- package/src/qingflow_mcp/ops/apps.py +64 -0
- package/src/qingflow_mcp/ops/auth.py +121 -0
- package/src/qingflow_mcp/ops/base.py +290 -0
- package/src/qingflow_mcp/ops/builder.py +323 -0
- package/src/qingflow_mcp/ops/context.py +120 -0
- package/src/qingflow_mcp/ops/directory.py +171 -0
- package/src/qingflow_mcp/ops/feedback.py +49 -0
- package/src/qingflow_mcp/ops/files.py +78 -0
- package/src/qingflow_mcp/ops/imports.py +140 -0
- package/src/qingflow_mcp/ops/records.py +415 -0
- package/src/qingflow_mcp/ops/tasks.py +171 -0
- package/src/qingflow_mcp/ops/workspace.py +76 -0
- package/src/qingflow_mcp/server_app_builder.py +190 -122
- package/src/qingflow_mcp/server_app_user.py +662 -63
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import json
|
|
4
5
|
import sys
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
8
|
from ...errors import QingflowApiError
|
|
8
|
-
from ..json_io import load_json_list, load_json_object
|
|
9
|
+
from ..json_io import load_json_list, load_json_object
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def parse_bool_text(value: str) -> bool:
|
|
@@ -17,26 +18,6 @@ def parse_bool_text(value: str) -> bool:
|
|
|
17
18
|
raise argparse.ArgumentTypeError("expected one of: true, false, 1, 0, yes, no")
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
def load_list_arg(path: str | None, *, option_name: str) -> list[Any]:
|
|
21
|
-
return load_optional_json_list(path, option_name=option_name)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def load_object_arg(path: str | None, *, option_name: str) -> dict[str, Any] | None:
|
|
25
|
-
return load_optional_json_object(path, option_name=option_name)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def require_list_arg(path: str | None, *, option_name: str) -> list[Any]:
|
|
29
|
-
if not path:
|
|
30
|
-
raise QingflowApiError.config_error(f"{option_name} is required")
|
|
31
|
-
return load_json_list(path, option_name=option_name)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def require_object_arg(path: str | None, *, option_name: str) -> dict[str, Any]:
|
|
35
|
-
if not path:
|
|
36
|
-
raise QingflowApiError.config_error(f"{option_name} is required")
|
|
37
|
-
return load_json_object(path, option_name=option_name)
|
|
38
|
-
|
|
39
|
-
|
|
40
21
|
def read_secret_arg(value: str | None, *, stdin_enabled: bool, label: str) -> str:
|
|
41
22
|
if stdin_enabled:
|
|
42
23
|
secret = sys.stdin.read().strip()
|
|
@@ -45,3 +26,96 @@ def read_secret_arg(value: str | None, *, stdin_enabled: bool, label: str) -> st
|
|
|
45
26
|
if value:
|
|
46
27
|
return value
|
|
47
28
|
raise QingflowApiError.config_error(f"{label} is required")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def add_stdin_json_flag(parser: argparse.ArgumentParser) -> None:
|
|
32
|
+
parser.add_argument("--stdin-json", action="store_true", help="从标准输入读取 JSON")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def add_file_arg(parser: argparse.ArgumentParser, *, required: bool = False, help_text: str = "从文件读取 JSON") -> None:
|
|
36
|
+
parser.add_argument("--file", required=required, help=help_text)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def add_field_args(parser: argparse.ArgumentParser) -> None:
|
|
40
|
+
parser.add_argument("--field", dest="fields", action="append", default=[], help="字段赋值,格式:字段名=值")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def load_object_input(args: argparse.Namespace, *, required: bool = False) -> dict[str, Any]:
|
|
44
|
+
if getattr(args, "stdin_json", False):
|
|
45
|
+
payload = _read_stdin_json()
|
|
46
|
+
if not isinstance(payload, dict):
|
|
47
|
+
raise QingflowApiError.config_error("stdin JSON must be an object")
|
|
48
|
+
return payload
|
|
49
|
+
file_path = getattr(args, "file", None)
|
|
50
|
+
if file_path:
|
|
51
|
+
return load_json_object(file_path, option_name="--file")
|
|
52
|
+
if required:
|
|
53
|
+
raise QingflowApiError.config_error("either --stdin-json or --file is required")
|
|
54
|
+
return {}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def load_list_input(args: argparse.Namespace, *, required: bool = False) -> list[Any]:
|
|
58
|
+
if getattr(args, "stdin_json", False):
|
|
59
|
+
payload = _read_stdin_json()
|
|
60
|
+
if not isinstance(payload, list):
|
|
61
|
+
raise QingflowApiError.config_error("stdin JSON must be a list")
|
|
62
|
+
return payload
|
|
63
|
+
file_path = getattr(args, "file", None)
|
|
64
|
+
if file_path:
|
|
65
|
+
return load_json_list(file_path, option_name="--file")
|
|
66
|
+
if required:
|
|
67
|
+
raise QingflowApiError.config_error("either --stdin-json or --file is required")
|
|
68
|
+
return []
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def parse_field_assignments(items: list[str]) -> dict[str, Any]:
|
|
72
|
+
payload: dict[str, Any] = {}
|
|
73
|
+
for item in items:
|
|
74
|
+
if "=" not in item:
|
|
75
|
+
raise QingflowApiError.config_error("field assignments must use name=value format")
|
|
76
|
+
key, raw_value = item.split("=", 1)
|
|
77
|
+
name = key.strip()
|
|
78
|
+
if not name:
|
|
79
|
+
raise QingflowApiError.config_error("field name cannot be empty")
|
|
80
|
+
payload[name] = _coerce_value(raw_value)
|
|
81
|
+
return payload
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def merge_object_inputs(args: argparse.Namespace, *, allow_empty: bool = False) -> dict[str, Any]:
|
|
85
|
+
payload = parse_field_assignments(list(getattr(args, "fields", []) or []))
|
|
86
|
+
if getattr(args, "stdin_json", False) or getattr(args, "file", None):
|
|
87
|
+
loaded = load_object_input(args, required=False)
|
|
88
|
+
payload.update(loaded)
|
|
89
|
+
if not payload and not allow_empty:
|
|
90
|
+
raise QingflowApiError.config_error("provide at least one --field or pass --stdin-json/--file")
|
|
91
|
+
return payload
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _read_stdin_json() -> Any:
|
|
95
|
+
raw = sys.stdin.read()
|
|
96
|
+
if not raw.strip():
|
|
97
|
+
raise QingflowApiError.config_error("stdin JSON is empty")
|
|
98
|
+
try:
|
|
99
|
+
return json.loads(raw)
|
|
100
|
+
except json.JSONDecodeError as error:
|
|
101
|
+
raise QingflowApiError.config_error(f"stdin JSON is invalid: {error.msg}") from error
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _coerce_value(raw: str) -> Any:
|
|
105
|
+
text = raw.strip()
|
|
106
|
+
if not text:
|
|
107
|
+
return ""
|
|
108
|
+
if text.startswith("{") or text.startswith("[") or text.startswith('"'):
|
|
109
|
+
try:
|
|
110
|
+
return json.loads(text)
|
|
111
|
+
except json.JSONDecodeError:
|
|
112
|
+
return raw
|
|
113
|
+
normalized = text.lower()
|
|
114
|
+
if normalized in {"true", "false", "null"}:
|
|
115
|
+
return json.loads(normalized)
|
|
116
|
+
try:
|
|
117
|
+
if "." in text:
|
|
118
|
+
return float(text)
|
|
119
|
+
return int(text)
|
|
120
|
+
except ValueError:
|
|
121
|
+
return raw
|
|
@@ -10,77 +10,69 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
10
10
|
parser = subparsers.add_parser("import", help="导入")
|
|
11
11
|
import_subparsers = parser.add_subparsers(dest="import_command", required=True)
|
|
12
12
|
|
|
13
|
-
template = import_subparsers.add_parser("template", help="
|
|
14
|
-
template.add_argument("--app
|
|
15
|
-
template.add_argument("--
|
|
16
|
-
template.set_defaults(handler=_handle_template, format_hint="")
|
|
13
|
+
template = import_subparsers.add_parser("template", help="获取导入模板")
|
|
14
|
+
template.add_argument("--app", required=True)
|
|
15
|
+
template.add_argument("--to")
|
|
16
|
+
template.set_defaults(handler=_handle_template, format_hint="import_template")
|
|
17
17
|
|
|
18
18
|
verify = import_subparsers.add_parser("verify", help="校验导入文件")
|
|
19
|
-
verify.add_argument("--app
|
|
20
|
-
verify.add_argument("--file
|
|
19
|
+
verify.add_argument("--app", required=True)
|
|
20
|
+
verify.add_argument("--file", required=True)
|
|
21
21
|
verify.set_defaults(handler=_handle_verify, format_hint="import_verify")
|
|
22
22
|
|
|
23
|
-
repair = import_subparsers.add_parser("repair", help="
|
|
24
|
-
repair.add_argument("--verification
|
|
25
|
-
repair.add_argument("--
|
|
26
|
-
repair.add_argument("--
|
|
23
|
+
repair = import_subparsers.add_parser("repair", help="在授权后修复导入文件")
|
|
24
|
+
repair.add_argument("--verification", required=True)
|
|
25
|
+
repair.add_argument("--authorize", action="store_true")
|
|
26
|
+
repair.add_argument("--to")
|
|
27
27
|
repair.add_argument("--repair", dest="selected_repairs", action="append", default=[])
|
|
28
|
-
repair.set_defaults(handler=_handle_repair, format_hint="")
|
|
28
|
+
repair.set_defaults(handler=_handle_repair, format_hint="import_repair")
|
|
29
29
|
|
|
30
30
|
start = import_subparsers.add_parser("start", help="启动导入")
|
|
31
|
-
start.add_argument("--app
|
|
32
|
-
start.add_argument("--verification
|
|
33
|
-
start.add_argument("--
|
|
34
|
-
start.add_argument("--view
|
|
35
|
-
start.set_defaults(handler=_handle_start, format_hint="")
|
|
36
|
-
|
|
37
|
-
status = import_subparsers.add_parser("status", help="
|
|
38
|
-
status.add_argument("--app
|
|
31
|
+
start.add_argument("--app", required=True)
|
|
32
|
+
start.add_argument("--verification", required=True)
|
|
33
|
+
start.add_argument("--enter-auditing", type=parse_bool_text, required=True)
|
|
34
|
+
start.add_argument("--view")
|
|
35
|
+
start.set_defaults(handler=_handle_start, format_hint="import_start")
|
|
36
|
+
|
|
37
|
+
status = import_subparsers.add_parser("status", help="查看导入状态")
|
|
38
|
+
status.add_argument("--app", required=True)
|
|
39
39
|
status.add_argument("--import-id")
|
|
40
|
-
status.add_argument("--process-id
|
|
40
|
+
status.add_argument("--process-id")
|
|
41
41
|
status.set_defaults(handler=_handle_status, format_hint="import_status")
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def _handle_template(args: argparse.Namespace, context: CliContext) -> dict:
|
|
45
|
-
return context.imports.
|
|
46
|
-
profile=args.profile,
|
|
47
|
-
app_key=args.app_key,
|
|
48
|
-
download_to_path=args.download_to_path,
|
|
49
|
-
)
|
|
45
|
+
return context.imports.template(profile=args.profile, app_key=args.app, download_to_path=args.to)
|
|
50
46
|
|
|
51
47
|
|
|
52
48
|
def _handle_verify(args: argparse.Namespace, context: CliContext) -> dict:
|
|
53
|
-
return context.imports.
|
|
54
|
-
profile=args.profile,
|
|
55
|
-
app_key=args.app_key,
|
|
56
|
-
file_path=args.file_path,
|
|
57
|
-
)
|
|
49
|
+
return context.imports.verify(profile=args.profile, app_key=args.app, file_path=args.file)
|
|
58
50
|
|
|
59
51
|
|
|
60
52
|
def _handle_repair(args: argparse.Namespace, context: CliContext) -> dict:
|
|
61
|
-
return context.imports.
|
|
53
|
+
return context.imports.repair(
|
|
62
54
|
profile=args.profile,
|
|
63
|
-
verification_id=args.
|
|
64
|
-
authorized_file_modification=bool(args.
|
|
65
|
-
output_path=args.
|
|
55
|
+
verification_id=args.verification,
|
|
56
|
+
authorized_file_modification=bool(args.authorize),
|
|
57
|
+
output_path=args.to,
|
|
66
58
|
selected_repairs=list(args.selected_repairs or []),
|
|
67
59
|
)
|
|
68
60
|
|
|
69
61
|
|
|
70
62
|
def _handle_start(args: argparse.Namespace, context: CliContext) -> dict:
|
|
71
|
-
return context.imports.
|
|
63
|
+
return context.imports.start(
|
|
72
64
|
profile=args.profile,
|
|
73
|
-
app_key=args.
|
|
74
|
-
verification_id=args.
|
|
75
|
-
being_enter_auditing=bool(args.
|
|
76
|
-
view_key=args.
|
|
65
|
+
app_key=args.app,
|
|
66
|
+
verification_id=args.verification,
|
|
67
|
+
being_enter_auditing=bool(args.enter_auditing),
|
|
68
|
+
view_key=args.view,
|
|
77
69
|
)
|
|
78
70
|
|
|
79
71
|
|
|
80
72
|
def _handle_status(args: argparse.Namespace, context: CliContext) -> dict:
|
|
81
|
-
return context.imports.
|
|
73
|
+
return context.imports.status(
|
|
82
74
|
profile=args.profile,
|
|
83
|
-
app_key=args.
|
|
75
|
+
app_key=args.app,
|
|
84
76
|
import_id=args.import_id,
|
|
85
|
-
process_id_str=args.
|
|
77
|
+
process_id_str=args.process_id,
|
|
86
78
|
)
|
|
@@ -5,198 +5,200 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from ...errors import QingflowApiError
|
|
7
7
|
from ..context import CliContext
|
|
8
|
-
from .common import
|
|
8
|
+
from .common import add_field_args, add_file_arg, add_stdin_json_flag, load_list_input, load_object_input, merge_object_inputs
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
12
|
-
parser = subparsers.add_parser("
|
|
13
|
-
record_subparsers = parser.add_subparsers(dest="
|
|
12
|
+
parser = subparsers.add_parser("records", help="记录与表结构")
|
|
13
|
+
record_subparsers = parser.add_subparsers(dest="records_command", required=True)
|
|
14
14
|
|
|
15
|
-
schema = record_subparsers.add_parser("schema", help="
|
|
16
|
-
schema.add_argument("--app
|
|
15
|
+
schema = record_subparsers.add_parser("schema", help="读取记录表结构")
|
|
16
|
+
schema.add_argument("--app", required=True)
|
|
17
17
|
schema.add_argument("--mode", choices=["applicant", "browse", "insert", "update", "import", "code-block"], default="applicant")
|
|
18
|
-
schema.add_argument("--view
|
|
19
|
-
schema.add_argument("--record
|
|
20
|
-
schema.set_defaults(handler=_handle_schema, format_hint="")
|
|
18
|
+
schema.add_argument("--view")
|
|
19
|
+
schema.add_argument("--record", type=int)
|
|
20
|
+
schema.set_defaults(handler=_handle_schema, format_hint="record_schema")
|
|
21
21
|
|
|
22
22
|
list_parser = record_subparsers.add_parser("list", help="列出记录")
|
|
23
|
-
list_parser.add_argument("--app
|
|
23
|
+
list_parser.add_argument("--app", required=True)
|
|
24
|
+
list_parser.add_argument("--view")
|
|
24
25
|
list_parser.add_argument("--column", dest="columns", action="append", type=int, default=[])
|
|
25
|
-
list_parser.add_argument("--columns-file")
|
|
26
|
-
list_parser.add_argument("--where-file")
|
|
27
|
-
list_parser.add_argument("--order-by-file")
|
|
28
26
|
list_parser.add_argument("--limit", type=int, default=20)
|
|
29
27
|
list_parser.add_argument("--page", type=int, default=1)
|
|
30
|
-
list_parser
|
|
31
|
-
list_parser
|
|
28
|
+
add_file_arg(list_parser)
|
|
29
|
+
add_stdin_json_flag(list_parser)
|
|
30
|
+
list_parser.set_defaults(handler=_handle_list, format_hint="records_list")
|
|
32
31
|
|
|
33
32
|
get = record_subparsers.add_parser("get", help="读取单条记录")
|
|
34
|
-
get.add_argument("--app
|
|
35
|
-
get.add_argument("--record
|
|
33
|
+
get.add_argument("--app", required=True)
|
|
34
|
+
get.add_argument("--record", required=True, type=int)
|
|
35
|
+
get.add_argument("--view")
|
|
36
36
|
get.add_argument("--column", dest="columns", action="append", type=int, default=[])
|
|
37
|
-
get.
|
|
38
|
-
get.add_argument("--view-id")
|
|
39
|
-
get.set_defaults(handler=_handle_get, format_hint="")
|
|
37
|
+
get.set_defaults(handler=_handle_get, format_hint="record_show")
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
create = record_subparsers.add_parser("create", help="新增记录")
|
|
40
|
+
create.add_argument("--app", required=True)
|
|
41
|
+
add_field_args(create)
|
|
42
|
+
add_file_arg(create)
|
|
43
|
+
add_stdin_json_flag(create)
|
|
44
|
+
create.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
|
|
45
|
+
create.set_defaults(handler=_handle_create, format_hint="record_write")
|
|
46
46
|
|
|
47
47
|
update = record_subparsers.add_parser("update", help="更新记录")
|
|
48
|
-
update.add_argument("--app
|
|
49
|
-
update.add_argument("--record
|
|
50
|
-
update
|
|
48
|
+
update.add_argument("--app", required=True)
|
|
49
|
+
update.add_argument("--record", required=True, type=int)
|
|
50
|
+
add_field_args(update)
|
|
51
|
+
add_file_arg(update)
|
|
52
|
+
add_stdin_json_flag(update)
|
|
51
53
|
update.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
|
|
52
|
-
update.set_defaults(handler=_handle_update, format_hint="")
|
|
54
|
+
update.set_defaults(handler=_handle_update, format_hint="record_write")
|
|
53
55
|
|
|
54
56
|
delete = record_subparsers.add_parser("delete", help="删除记录")
|
|
55
|
-
delete.add_argument("--app
|
|
56
|
-
delete.add_argument("--record
|
|
57
|
-
delete
|
|
58
|
-
delete
|
|
57
|
+
delete.add_argument("--app", required=True)
|
|
58
|
+
delete.add_argument("--record", type=int)
|
|
59
|
+
add_file_arg(delete)
|
|
60
|
+
add_stdin_json_flag(delete)
|
|
61
|
+
delete.set_defaults(handler=_handle_delete, format_hint="record_write")
|
|
59
62
|
|
|
60
63
|
analyze = record_subparsers.add_parser("analyze", help="分析记录数据")
|
|
61
|
-
analyze.add_argument("--app
|
|
62
|
-
analyze.add_argument("--
|
|
63
|
-
analyze.add_argument("--metrics-file")
|
|
64
|
-
analyze.add_argument("--filters-file")
|
|
65
|
-
analyze.add_argument("--sort-file")
|
|
64
|
+
analyze.add_argument("--app", required=True)
|
|
65
|
+
analyze.add_argument("--view")
|
|
66
66
|
analyze.add_argument("--limit", type=int, default=20)
|
|
67
67
|
analyze.add_argument("--strict-full", action=argparse.BooleanOptionalAction, default=False)
|
|
68
|
-
analyze
|
|
69
|
-
analyze
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def _columns(args: argparse.Namespace) -> list[Any]:
|
|
86
|
-
columns: list[Any] = list(args.columns or [])
|
|
87
|
-
if args.columns_file:
|
|
88
|
-
columns.extend(require_list_arg(args.columns_file, option_name="--columns-file"))
|
|
89
|
-
return columns
|
|
68
|
+
add_file_arg(analyze, required=False, help_text="读取分析 JSON,支持 dimensions/metrics/filters/sort")
|
|
69
|
+
add_stdin_json_flag(analyze)
|
|
70
|
+
analyze.set_defaults(handler=_handle_analyze, format_hint="record_analyze")
|
|
71
|
+
|
|
72
|
+
run_code = record_subparsers.add_parser("run-code", help="执行代码块字段")
|
|
73
|
+
run_code.add_argument("--app", required=True)
|
|
74
|
+
run_code.add_argument("--record", required=True, type=int)
|
|
75
|
+
run_code.add_argument("--field-selector", required=True)
|
|
76
|
+
run_code.add_argument("--role", type=int, default=1)
|
|
77
|
+
run_code.add_argument("--node", dest="workflow_node_id", type=int)
|
|
78
|
+
add_file_arg(run_code, required=False, help_text="读取执行 JSON,支持 answers/fields")
|
|
79
|
+
add_stdin_json_flag(run_code)
|
|
80
|
+
run_code.add_argument("--manual", action=argparse.BooleanOptionalAction, default=True)
|
|
81
|
+
run_code.add_argument("--verify-writeback", action=argparse.BooleanOptionalAction, default=True)
|
|
82
|
+
run_code.add_argument("--force-refresh-form", action="store_true")
|
|
83
|
+
run_code.set_defaults(handler=_handle_run_code, format_hint="record_run_code")
|
|
90
84
|
|
|
91
85
|
|
|
92
86
|
def _handle_schema(args: argparse.Namespace, context: CliContext) -> dict:
|
|
93
|
-
mode
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
profile=args.profile,
|
|
105
|
-
app_key=args.app_key,
|
|
106
|
-
view_id=args.view_id,
|
|
107
|
-
)
|
|
108
|
-
if mode == "insert":
|
|
109
|
-
return context.record.record_insert_schema_get_public(profile=args.profile, app_key=args.app_key)
|
|
110
|
-
if mode == "update":
|
|
111
|
-
if not args.record_id:
|
|
112
|
-
raise QingflowApiError.config_error("--record-id is required when --mode update")
|
|
113
|
-
return context.record.record_update_schema_get_public(
|
|
114
|
-
profile=args.profile,
|
|
115
|
-
app_key=args.app_key,
|
|
116
|
-
record_id=args.record_id,
|
|
117
|
-
)
|
|
118
|
-
if mode == "import":
|
|
119
|
-
return context.imports.record_import_schema_get(profile=args.profile, app_key=args.app_key)
|
|
120
|
-
return context.code_block.record_code_block_schema_get_public(profile=args.profile, app_key=args.app_key)
|
|
87
|
+
if args.mode == "browse" and not args.view:
|
|
88
|
+
raise QingflowApiError.config_error("--view is required when --mode browse")
|
|
89
|
+
if args.mode == "update" and not args.record:
|
|
90
|
+
raise QingflowApiError.config_error("--record is required when --mode update")
|
|
91
|
+
return context.records.schema(
|
|
92
|
+
profile=args.profile,
|
|
93
|
+
app_key=args.app,
|
|
94
|
+
mode=args.mode,
|
|
95
|
+
view_id=args.view,
|
|
96
|
+
record_id=args.record,
|
|
97
|
+
)
|
|
121
98
|
|
|
122
99
|
|
|
123
100
|
def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
124
|
-
|
|
101
|
+
query = _load_query_payload(args)
|
|
102
|
+
return context.records.list(
|
|
125
103
|
profile=args.profile,
|
|
126
|
-
app_key=args.
|
|
127
|
-
columns=
|
|
128
|
-
where=
|
|
129
|
-
order_by=
|
|
130
|
-
limit=args.limit,
|
|
131
|
-
page=args.page,
|
|
132
|
-
view_id=args.
|
|
104
|
+
app_key=args.app,
|
|
105
|
+
columns=list(args.columns or []) + _coerce_list(query.get("columns")),
|
|
106
|
+
where=_coerce_list(query.get("where")),
|
|
107
|
+
order_by=_coerce_list(query.get("order_by")),
|
|
108
|
+
limit=int(query.get("limit") or args.limit),
|
|
109
|
+
page=int(query.get("page") or args.page),
|
|
110
|
+
view_id=str(query.get("view_id") or args.view or "") or None,
|
|
111
|
+
list_type=None,
|
|
112
|
+
view_key=None,
|
|
113
|
+
view_name=None,
|
|
133
114
|
)
|
|
134
115
|
|
|
135
116
|
|
|
136
117
|
def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
137
|
-
return context.
|
|
118
|
+
return context.records.get(
|
|
138
119
|
profile=args.profile,
|
|
139
|
-
app_key=args.
|
|
140
|
-
record_id=args.
|
|
141
|
-
columns=
|
|
142
|
-
view_id=args.
|
|
120
|
+
app_key=args.app,
|
|
121
|
+
record_id=args.record,
|
|
122
|
+
columns=list(args.columns or []),
|
|
123
|
+
view_id=args.view,
|
|
124
|
+
workflow_node_id=None,
|
|
143
125
|
)
|
|
144
126
|
|
|
145
127
|
|
|
146
|
-
def
|
|
147
|
-
return context.
|
|
128
|
+
def _handle_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
129
|
+
return context.records.create(
|
|
148
130
|
profile=args.profile,
|
|
149
|
-
app_key=args.
|
|
150
|
-
fields=
|
|
131
|
+
app_key=args.app,
|
|
132
|
+
fields=merge_object_inputs(args),
|
|
151
133
|
verify_write=bool(args.verify_write),
|
|
152
134
|
)
|
|
153
135
|
|
|
154
136
|
|
|
155
137
|
def _handle_update(args: argparse.Namespace, context: CliContext) -> dict:
|
|
156
|
-
return context.
|
|
138
|
+
return context.records.update(
|
|
157
139
|
profile=args.profile,
|
|
158
|
-
app_key=args.
|
|
159
|
-
record_id=args.
|
|
160
|
-
fields=
|
|
140
|
+
app_key=args.app,
|
|
141
|
+
record_id=args.record,
|
|
142
|
+
fields=merge_object_inputs(args),
|
|
161
143
|
verify_write=bool(args.verify_write),
|
|
162
144
|
)
|
|
163
145
|
|
|
164
146
|
|
|
165
147
|
def _handle_delete(args: argparse.Namespace, context: CliContext) -> dict:
|
|
166
|
-
record_ids =
|
|
167
|
-
|
|
148
|
+
record_ids = []
|
|
149
|
+
if args.stdin_json or args.file:
|
|
150
|
+
payload = load_list_input(args, required=False)
|
|
151
|
+
record_ids = [item for item in payload if isinstance(item, int)]
|
|
152
|
+
return context.records.delete(
|
|
168
153
|
profile=args.profile,
|
|
169
|
-
app_key=args.
|
|
170
|
-
record_id=args.
|
|
154
|
+
app_key=args.app,
|
|
155
|
+
record_id=args.record,
|
|
171
156
|
record_ids=record_ids,
|
|
172
157
|
)
|
|
173
158
|
|
|
174
159
|
|
|
175
160
|
def _handle_analyze(args: argparse.Namespace, context: CliContext) -> dict:
|
|
176
|
-
|
|
161
|
+
payload = load_object_input(args, required=False)
|
|
162
|
+
return context.records.analyze(
|
|
177
163
|
profile=args.profile,
|
|
178
|
-
app_key=args.
|
|
179
|
-
dimensions=
|
|
180
|
-
metrics=
|
|
181
|
-
filters=
|
|
182
|
-
sort=
|
|
183
|
-
limit=args.limit,
|
|
184
|
-
strict_full=bool(args.strict_full),
|
|
185
|
-
view_id=args.
|
|
164
|
+
app_key=args.app,
|
|
165
|
+
dimensions=_coerce_list(payload.get("dimensions")),
|
|
166
|
+
metrics=_coerce_list(payload.get("metrics")),
|
|
167
|
+
filters=_coerce_list(payload.get("filters")),
|
|
168
|
+
sort=_coerce_list(payload.get("sort")),
|
|
169
|
+
limit=int(payload.get("limit") or args.limit),
|
|
170
|
+
strict_full=bool(payload.get("strict_full", args.strict_full)),
|
|
171
|
+
view_id=str(payload.get("view_id") or args.view or "") or None,
|
|
172
|
+
list_type=None,
|
|
173
|
+
view_key=None,
|
|
174
|
+
view_name=None,
|
|
186
175
|
)
|
|
187
176
|
|
|
188
177
|
|
|
189
|
-
def
|
|
190
|
-
|
|
178
|
+
def _handle_run_code(args: argparse.Namespace, context: CliContext) -> dict:
|
|
179
|
+
payload = load_object_input(args, required=False)
|
|
180
|
+
return context.records.run_code(
|
|
191
181
|
profile=args.profile,
|
|
192
|
-
app_key=args.
|
|
193
|
-
record_id=args.
|
|
194
|
-
code_block_field=args.
|
|
182
|
+
app_key=args.app,
|
|
183
|
+
record_id=args.record,
|
|
184
|
+
code_block_field=args.field_selector,
|
|
195
185
|
role=args.role,
|
|
196
186
|
workflow_node_id=args.workflow_node_id,
|
|
197
|
-
answers=
|
|
198
|
-
fields=
|
|
199
|
-
manual=bool(args.manual),
|
|
200
|
-
verify_writeback=bool(args.verify_writeback),
|
|
201
|
-
force_refresh_form=bool(args.force_refresh_form),
|
|
187
|
+
answers=_coerce_list(payload.get("answers")),
|
|
188
|
+
fields=payload.get("fields") if isinstance(payload.get("fields"), dict) else {},
|
|
189
|
+
manual=bool(payload.get("manual", args.manual)),
|
|
190
|
+
verify_writeback=bool(payload.get("verify_writeback", args.verify_writeback)),
|
|
191
|
+
force_refresh_form=bool(payload.get("force_refresh_form", args.force_refresh_form)),
|
|
202
192
|
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _load_query_payload(args: argparse.Namespace) -> dict[str, Any]:
|
|
196
|
+
if args.stdin_json or args.file:
|
|
197
|
+
payload = load_object_input(args, required=False)
|
|
198
|
+
if payload:
|
|
199
|
+
return payload
|
|
200
|
+
return {}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _coerce_list(value: Any) -> list[Any]:
|
|
204
|
+
return value if isinstance(value, list) else []
|