hap-cli 0.9.1__tar.gz → 0.9.3__tar.gz
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.
- {hap_cli-0.9.1 → hap_cli-0.9.3}/PKG-INFO +1 -1
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/smoke.py +292 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/__init__.py +1 -1
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/worksheet_cmd.py +1 -1
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/context.py +5 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/ops.py +119 -3
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/reader.py +137 -1
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/field_spec_adapter.py +6 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/record.py +6 -2
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/record_form_checks.py +30 -4
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/worksheet.py +288 -49
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_core.py +171 -0
- hap_cli-0.9.3/hap_cli/tests/test_create_worksheet_partial.py +231 -0
- hap_cli-0.9.3/hap_cli/tests/test_editor_inline_subtable.py +239 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g6_advanced_fields.py +5 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_form_checks.py +126 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/PKG-INFO +1 -1
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/SOURCES.txt +2 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/MANIFEST.in +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/README.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/config.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/fixtures/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/fixtures/feedback_scenario.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/harness.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/app_live_tests/state.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/README.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/README_CN.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/__main__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/_entry.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/attachment_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/chat_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/guide_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/attachment.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/condition_dsl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/department.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/editspec/component.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/editspec/field.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/filter_v3.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/group.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/guide.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/layout_check.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/page.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/post.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/record_defaults.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/record_lookups.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/record_rules.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/relation_scope.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/role.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/rule_spec_adapter.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/session.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/update.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/worksheet_form.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/worksheet_reference.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/approval.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/chart.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/messages.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/overview.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/post.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/record.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/setup.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/skills.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/workflow.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/en/worksheet.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/index.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/approval.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/chart.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/messages.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/overview.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/post.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/record.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/setup.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/skills.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/workflow.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/guide/zh-Hans/worksheet.md +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/i18n.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_action_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_advanced_setting_guard.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_app_light_color.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_app_section_name.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_approval_wire.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_atomic_write.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_attachment_share.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_batch_add_atomic.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_calendar_date_range.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_calendar_discussion_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chart_filter_merge.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chat_attachment_send.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chat_messages_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chat_recall_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_chat_send_socket.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_coded_responses.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_condition_dsl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_condition_dsl_entries.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_condition_dsl_readback.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_dsl_existing_node_refs.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_dsl_multi_record_guard.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_engine_core_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_arg_consistency.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_bidirectional.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_discussion_mentions.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_entry_module.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_field_record_ref.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_http_error_body.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_json_anywhere.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_json_file_arg.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_layout_check.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_node_get_detail.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_node_summary.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_post_cursor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_publish_reasons.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_replicate_workflow.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_save_fields_shape.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_subgroups.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_subtable_read.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_worksheet_references.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_worksheet_visibility.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fb_worksheet_workflows.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_fields_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g1_chart_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g1_record_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g1_upload_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g1_worksheet_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g2_coverage_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g3_workflow_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g4_approval_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g5_low_frequency_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g6_fields_roundtrip.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g7_misc_gaps.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g7b_permanent_delete.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g8_filter_operator.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g8b_pivot_operators.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g8c_empty_filter_and_help_truth.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_g9_appid_resolve.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_guide.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_guide_sections.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_inner_flow_batch_add.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_instance_envelope.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_jsonschema_mini_copy.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_noninteractive_confirm.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_page_filters_group_read.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_page_filters_group_update.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_page_save_page_id.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_post_scope_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_business_rules.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_defaults.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_doc_id_hidden.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_run_action.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_record_write_fixes.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_relation_scope.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_rmw_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_role_app_scope.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_rule_filters_and_field_warning.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_save_action_silent_drop.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_save_rule_spec.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_select_add_option.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_subtable_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_upload_allow_down.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_upload_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_bool_flags.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_response_format_json.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_view_mdpublic_parity.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_config_keys.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_inner_scope.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_json_file_arg.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_node_delete_missing.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_save_action_dsl_fields.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_structure_listing.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_trigger_outcome.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wf_trigger_preserve.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_wo4_result_handling.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_code_node.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_condition_field_types.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_condition_slots.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_delete_cascade.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_lifecycle_wire.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_node_wire.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_publish_inner.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_worksheet_filter_read.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_worksheet_switch.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/atomic_write.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/confirm.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/__main__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/_wftest.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/charts.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/cleanup.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/compiler.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/config.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/errors.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/executor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/fields.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/hap.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/recording/console.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/recording/report.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/schema.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/seed/template.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/selftest.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/smoke.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/step.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/steps.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/store.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/setup.cfg +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/setup.py +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.9.1 → hap_cli-0.9.3}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -226,6 +226,146 @@ def case_custom_action(app_id: str, section_id: str) -> None:
|
|
|
226
226
|
hap(["worksheet", "delete", ws_id, "-a", app_id, "-y"], check=False)
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
def case_custom_action_update(app_id: str, section_id: str) -> None:
|
|
230
|
+
"""bug #455751: --action-spec with --btn-id edits the action in place."""
|
|
231
|
+
print("scenario: custom-action update by id")
|
|
232
|
+
ws_id = _make_worksheet(app_id, section_id, "LT-action-update")
|
|
233
|
+
try:
|
|
234
|
+
ok, res = _try(["worksheet", "create-custom-action", ws_id, "-a",
|
|
235
|
+
app_id, "--action-spec", json.dumps(
|
|
236
|
+
{"name": "ORIGINAL", "type": "triggerWorkflow",
|
|
237
|
+
"color": "#2196F3"})])
|
|
238
|
+
check("update: workflow action created", ok, str(res)[:160])
|
|
239
|
+
btn_id = res.get("actionId") if ok else ""
|
|
240
|
+
proc_id = res.get("processId") if ok else ""
|
|
241
|
+
ok, res = _try(["worksheet", "create-custom-action", ws_id, "-a",
|
|
242
|
+
app_id, "--btn-id", btn_id, "--action-spec",
|
|
243
|
+
json.dumps({"name": "UPDATED"})])
|
|
244
|
+
check("update: edit succeeds", ok, str(res)[:160])
|
|
245
|
+
check("update: the id is unchanged",
|
|
246
|
+
ok and res.get("actionId") == btn_id, str(res)[:160])
|
|
247
|
+
check("update: the same workflow is reported",
|
|
248
|
+
ok and res.get("processId") == proc_id, str(res)[:160])
|
|
249
|
+
acts = _actions(ws_id)
|
|
250
|
+
check("update: still one action", len(acts) == 1,
|
|
251
|
+
str([(a.get("btnId"), a.get("name")) for a in acts]))
|
|
252
|
+
got = acts[0] if acts else {}
|
|
253
|
+
check("update: renamed in place",
|
|
254
|
+
got.get("btnId") == btn_id and got.get("name") == "UPDATED",
|
|
255
|
+
str((got.get("btnId"), got.get("name"))))
|
|
256
|
+
check("update: unnamed settings kept",
|
|
257
|
+
got.get("color") == "#2196F3" and got.get("clickType") == 1,
|
|
258
|
+
str((got.get("color"), got.get("clickType"))))
|
|
259
|
+
wf = [r for r in _workflow_rows(app_id)
|
|
260
|
+
if r.get("id") == proc_id or r.get("processId") == proc_id]
|
|
261
|
+
check("update: the action's workflow survives", bool(wf),
|
|
262
|
+
proc_id)
|
|
263
|
+
|
|
264
|
+
# A fill action edited by id stays a fill action and keeps its fields.
|
|
265
|
+
title = next((c["controlId"] for c in _fields(ws_id)
|
|
266
|
+
if c.get("attribute") == 1), "")
|
|
267
|
+
ok, res = _try(["worksheet", "create-custom-action", ws_id, "-a",
|
|
268
|
+
app_id, "--action-spec", json.dumps(
|
|
269
|
+
{"name": "FILL", "type": "updateCurrentRecord",
|
|
270
|
+
"updateFields": [title]})])
|
|
271
|
+
fill_id = res.get("actionId") if ok else ""
|
|
272
|
+
ok, res = _try(["worksheet", "create-custom-action", ws_id, "-a",
|
|
273
|
+
app_id, "--btn-id", fill_id, "--action-spec",
|
|
274
|
+
json.dumps({"name": "FILL2"})])
|
|
275
|
+
check("update: fill action edit succeeds", ok, str(res)[:160])
|
|
276
|
+
acts = _actions(ws_id)
|
|
277
|
+
fill = next((a for a in acts if a.get("btnId") == fill_id), {})
|
|
278
|
+
check("update: two actions after editing the second", len(acts) == 2,
|
|
279
|
+
str([(a.get("btnId"), a.get("name")) for a in acts]))
|
|
280
|
+
check("update: fill action keeps its kind and field",
|
|
281
|
+
fill.get("name") == "FILL2" and fill.get("clickType") == 3
|
|
282
|
+
and [w.get("controlId") for w in fill.get("writeControls")
|
|
283
|
+
or []] == [title],
|
|
284
|
+
str((fill.get("name"), fill.get("clickType"),
|
|
285
|
+
fill.get("writeControls"))))
|
|
286
|
+
|
|
287
|
+
ok, res = _try(["worksheet", "create-custom-action", ws_id, "-a",
|
|
288
|
+
app_id, "--btn-id", "000000000000000000000000",
|
|
289
|
+
"--action-spec", json.dumps({"name": "GHOST"})])
|
|
290
|
+
check("update: unknown id is refused", not ok, str(res)[:160])
|
|
291
|
+
check("update: nothing created for an unknown id",
|
|
292
|
+
len(_actions(ws_id)) == 2, str(len(_actions(ws_id))))
|
|
293
|
+
finally:
|
|
294
|
+
hap(["worksheet", "delete", ws_id, "-a", app_id, "-y"], check=False)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def case_hidden_defaults(app_id: str, section_id: str) -> None:
|
|
298
|
+
"""bug #455757: a hidden field's default goes in with a new record.
|
|
299
|
+
|
|
300
|
+
The form submits every non-empty cell on create, hidden ones included,
|
|
301
|
+
so the defaults the CLI fills in must not be judged as the caller
|
|
302
|
+
writing a hidden field. Writing one yourself is still refused.
|
|
303
|
+
"""
|
|
304
|
+
print("scenario: hidden defaults on create")
|
|
305
|
+
ws_id = _make_worksheet(app_id, section_id, "LT-hidden-defaults")
|
|
306
|
+
|
|
307
|
+
def static(value):
|
|
308
|
+
return {"defsource": json.dumps(
|
|
309
|
+
[{"cid": "", "rcid": "", "staticValue": value}])}
|
|
310
|
+
try:
|
|
311
|
+
ok, res = _try(["worksheet", "add-fields", ws_id, "--controls",
|
|
312
|
+
json.dumps([
|
|
313
|
+
{"type": 2, "controlName": "Stage",
|
|
314
|
+
"fieldPermission": "110",
|
|
315
|
+
"advancedSetting": static("Draft")},
|
|
316
|
+
{"type": 2, "controlName": "Status",
|
|
317
|
+
"fieldPermission": "110",
|
|
318
|
+
"advancedSetting": static("Open")}])])
|
|
319
|
+
check("hidden: fields added", ok, str(res)[:160])
|
|
320
|
+
ids = {c.get("controlName"): c.get("controlId")
|
|
321
|
+
for c in _fields(ws_id)}
|
|
322
|
+
name_id = next((c["controlId"] for c in _fields(ws_id)
|
|
323
|
+
if c.get("attribute") == 1), "")
|
|
324
|
+
stage, status = ids.get("Stage"), ids.get("Status")
|
|
325
|
+
|
|
326
|
+
ok, res = _try(["worksheet", "record", "create", ws_id, "-a", app_id,
|
|
327
|
+
"--fields-json", json.dumps(
|
|
328
|
+
[{"id": name_id, "value": "visible-only"}])])
|
|
329
|
+
check("hidden: create with only the visible field succeeds", ok,
|
|
330
|
+
str(res)[:200])
|
|
331
|
+
row_id = ((res.get("data") or {}).get("rowid")
|
|
332
|
+
if ok and isinstance(res, dict) else "")
|
|
333
|
+
got = (hap(["worksheet", "record", "get", ws_id, row_id, "-a",
|
|
334
|
+
app_id]) or {}) if row_id else {}
|
|
335
|
+
got = got.get("data", got) if isinstance(got, dict) else {}
|
|
336
|
+
check("hidden: the hidden defaults were stored",
|
|
337
|
+
got.get(stage) == "Draft" and got.get(status) == "Open",
|
|
338
|
+
str({k: got.get(k) for k in (name_id, stage, status)}))
|
|
339
|
+
|
|
340
|
+
ok, res = _try(["worksheet", "record", "create", ws_id, "-a", app_id,
|
|
341
|
+
"--fields-json", json.dumps(
|
|
342
|
+
[{"id": name_id, "value": "sneaky"},
|
|
343
|
+
{"id": stage, "value": "Won"}])])
|
|
344
|
+
check("hidden: writing a hidden field yourself is refused",
|
|
345
|
+
not ok and "Stage" in str(res) and "Status" not in str(res),
|
|
346
|
+
str(res)[:240])
|
|
347
|
+
|
|
348
|
+
rows = json.dumps([{name_id: "batch-1"}, {name_id: "batch-2"}])
|
|
349
|
+
ok, res = _try(["worksheet", "record", "batch-create", ws_id,
|
|
350
|
+
"-a", app_id, "--rows", rows])
|
|
351
|
+
check("hidden: batch create with only visible fields succeeds", ok,
|
|
352
|
+
str(res)[:200])
|
|
353
|
+
rows = json.dumps([{name_id: "batch-3"},
|
|
354
|
+
{name_id: "batch-4", stage: "Won"}])
|
|
355
|
+
ok, res = _try(["worksheet", "record", "batch-create", ws_id,
|
|
356
|
+
"-a", app_id, "--rows", rows])
|
|
357
|
+
check("hidden: batch writing a hidden field is refused on its row",
|
|
358
|
+
not ok and "row 2" in str(res) and "row 1" not in str(res),
|
|
359
|
+
str(res)[:240])
|
|
360
|
+
listed = (hap(["worksheet", "record", "list", ws_id, "-a", app_id])
|
|
361
|
+
or {}).get("rows") or []
|
|
362
|
+
blob = json.dumps(listed, ensure_ascii=False)
|
|
363
|
+
check("hidden: the refused batch wrote nothing",
|
|
364
|
+
"batch-3" not in blob and "batch-1" in blob, blob[:200])
|
|
365
|
+
finally:
|
|
366
|
+
hap(["worksheet", "delete", ws_id, "-a", app_id, "-y"], check=False)
|
|
367
|
+
|
|
368
|
+
|
|
229
369
|
def _items(app_id: str) -> dict[str, str]:
|
|
230
370
|
"""All sidebar items (worksheets, pages, chatbots) name -> id."""
|
|
231
371
|
detail = hap(["app", "info", "-a", app_id])
|
|
@@ -3397,6 +3537,154 @@ def case_fb_subtable_read(app_id: str, section_id: str) -> None:
|
|
|
3397
3537
|
hap(["worksheet", "delete", parent, "--yes"], check=False)
|
|
3398
3538
|
|
|
3399
3539
|
|
|
3540
|
+
def case_editor_inline_subtable(app_id: str, section_id: str) -> None:
|
|
3541
|
+
"""Bug #455768: edit-spec field ops on an inline sub-table's own sheet."""
|
|
3542
|
+
print("\nscenario: editor field ops on an inline sub-table (#455768)")
|
|
3543
|
+
import json as _json
|
|
3544
|
+
name = "BUG455768-sub-parent"
|
|
3545
|
+
parent = _make_worksheet(app_id, section_id, name)
|
|
3546
|
+
check("inline-subtable: a throwaway parent was created", bool(parent))
|
|
3547
|
+
if not parent:
|
|
3548
|
+
return
|
|
3549
|
+
try:
|
|
3550
|
+
hap(["worksheet", "update-fields", parent, "--title-name", "名称",
|
|
3551
|
+
"--no-verify", "--fields", _json.dumps([
|
|
3552
|
+
{"type": "TEXT", "name": "名称"},
|
|
3553
|
+
{"type": "SUB_LIST", "name": "内嵌明细", "child_fields": [
|
|
3554
|
+
{"type": "TEXT", "name": "行名称"},
|
|
3555
|
+
{"type": "NUMBER", "name": "行数量"}]},
|
|
3556
|
+
], ensure_ascii=False)], check=False)
|
|
3557
|
+
child = next((c.get("dataSource") for c in _fields(parent)
|
|
3558
|
+
if c.get("type") == 34), "")
|
|
3559
|
+
check("inline-subtable: the parent names its child sheet",
|
|
3560
|
+
bool(child), str(child))
|
|
3561
|
+
if not child:
|
|
3562
|
+
return
|
|
3563
|
+
|
|
3564
|
+
def _child_cols() -> list[dict]:
|
|
3565
|
+
got = hap(["worksheet", "fields", child, "--raw",
|
|
3566
|
+
"--parent", parent], check=False)
|
|
3567
|
+
return [c for c in got if len(c.get("controlId") or "") == 24] \
|
|
3568
|
+
if isinstance(got, list) else []
|
|
3569
|
+
|
|
3570
|
+
rc, out, err = editor_apply({"app": app_id, "ops": [
|
|
3571
|
+
{"type": "field.update", "worksheet": child, "field": "行名称",
|
|
3572
|
+
"set": {"hint": "按id改"}}]})
|
|
3573
|
+
check("inline-subtable: field.update by sheet id applies", rc == 0,
|
|
3574
|
+
(err or out)[-300:])
|
|
3575
|
+
cols = {c["controlName"]: c for c in _child_cols()}
|
|
3576
|
+
check("inline-subtable: the hint reads back",
|
|
3577
|
+
(cols.get("行名称") or {}).get("hint") == "按id改",
|
|
3578
|
+
str(cols.get("行名称"))[:200])
|
|
3579
|
+
|
|
3580
|
+
rc, out, err = editor_apply({"app": app_id, "ops": [
|
|
3581
|
+
{"type": "field.update", "worksheet": f"{name}/内嵌明细",
|
|
3582
|
+
"field": "行数量", "rename": "数量", "set": {}},
|
|
3583
|
+
{"type": "field.add", "worksheet": child,
|
|
3584
|
+
"field": {"name": "行备注", "type": "Text"}},
|
|
3585
|
+
{"type": "field.reorder", "worksheet": child,
|
|
3586
|
+
"order": ["行备注", "数量"]},
|
|
3587
|
+
{"type": "field.delete", "worksheet": child, "field": "行名称",
|
|
3588
|
+
"confirm": True}]})
|
|
3589
|
+
check("inline-subtable: add / reorder / delete apply", rc == 0,
|
|
3590
|
+
(err or out)[-300:])
|
|
3591
|
+
names = [c["controlName"] for c in
|
|
3592
|
+
sorted(_child_cols(), key=lambda c: c.get("row", 0))]
|
|
3593
|
+
check("inline-subtable: columns read back renamed, added, "
|
|
3594
|
+
"reordered and deleted", names == ["行备注", "数量"],
|
|
3595
|
+
str(names))
|
|
3596
|
+
sub = next((c for c in _fields(parent) if c.get("type") == 34), {})
|
|
3597
|
+
shown = {c["controlId"]: c["controlName"] for c in _child_cols()}
|
|
3598
|
+
check("inline-subtable: the new column is shown in the sub-table",
|
|
3599
|
+
[shown.get(i) for i in sub.get("showControls") or []]
|
|
3600
|
+
== ["行备注", "数量"], str(sub.get("showControls")))
|
|
3601
|
+
finally:
|
|
3602
|
+
hap(["worksheet", "delete", parent, "-a", app_id, "-y"], check=False)
|
|
3603
|
+
|
|
3604
|
+
|
|
3605
|
+
def case_create_partial(app_id: str, section_id: str) -> None:
|
|
3606
|
+
"""Bug #455775: a failed `worksheet create --fields` leaves nothing."""
|
|
3607
|
+
print("\nscenario: worksheet create --fields failure (#455775)")
|
|
3608
|
+
import json as _json
|
|
3609
|
+
from hap_cli.core import app as app_mod
|
|
3610
|
+
from hap_cli.core.session import Session
|
|
3611
|
+
session = Session.load()
|
|
3612
|
+
project_id = app_mod.app_project_id(session, app_id)
|
|
3613
|
+
prefix = "QA455775"
|
|
3614
|
+
for leftover in [n for n in _worksheets(app_id) if n.startswith(prefix)]:
|
|
3615
|
+
_ensure_absent(app_id, leftover)
|
|
3616
|
+
|
|
3617
|
+
def _ours() -> list[str]:
|
|
3618
|
+
return [n for n in _worksheets(app_id) if n.startswith(prefix)]
|
|
3619
|
+
|
|
3620
|
+
def _purge(ws_id: str) -> None:
|
|
3621
|
+
try:
|
|
3622
|
+
app_mod.purge_app_item(session, app_id=app_id,
|
|
3623
|
+
project_id=project_id,
|
|
3624
|
+
section_id=section_id, item_id=ws_id,
|
|
3625
|
+
item_type=0)
|
|
3626
|
+
except Exception as exc: # noqa: BLE001 — reported, not fatal
|
|
3627
|
+
print(f" note: could not purge {ws_id}: {exc}")
|
|
3628
|
+
|
|
3629
|
+
single = {"source": "static", "value": "DEFAULT-QA"}
|
|
3630
|
+
ok, res = _try(["worksheet", "create", app_id, f"{prefix} Invalid",
|
|
3631
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3632
|
+
{"type": "Text", "name": "名称"},
|
|
3633
|
+
{"type": "Text", "name": "备注",
|
|
3634
|
+
"defaultValue": single}], ensure_ascii=False)])
|
|
3635
|
+
check("create-partial: a single-object default is refused", not ok,
|
|
3636
|
+
str(res)[:200])
|
|
3637
|
+
check("create-partial: the refusal names the field and the shape",
|
|
3638
|
+
"备注" in str(res) and "list of objects" in str(res),
|
|
3639
|
+
str(res)[:300])
|
|
3640
|
+
check("create-partial: nothing was created", _ours() == [], str(_ours()))
|
|
3641
|
+
|
|
3642
|
+
# Passes every offline check, refused by the server at save time:
|
|
3643
|
+
# an alias the worksheet's own record-id column already holds.
|
|
3644
|
+
ok, res = _try(["worksheet", "create", app_id, f"{prefix} PostFail",
|
|
3645
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3646
|
+
{"type": "Text", "name": "名称"},
|
|
3647
|
+
{"type": "Text", "name": "冲突",
|
|
3648
|
+
"extra": {"alias": "rowid"}}],
|
|
3649
|
+
ensure_ascii=False)])
|
|
3650
|
+
check("create-partial: a save rejected after the create fails", not ok,
|
|
3651
|
+
str(res)[:200])
|
|
3652
|
+
check("create-partial: the error says the create was undone",
|
|
3653
|
+
"undone" in str(res), str(res)[:300])
|
|
3654
|
+
check("create-partial: no half-built worksheet is left",
|
|
3655
|
+
_ours() == [], str(_ours()))
|
|
3656
|
+
|
|
3657
|
+
ws_id = ""
|
|
3658
|
+
try:
|
|
3659
|
+
made = hap(["worksheet", "create", app_id, f"{prefix} Array",
|
|
3660
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3661
|
+
{"type": "Text", "name": "名称"},
|
|
3662
|
+
{"type": "Text", "name": "备注",
|
|
3663
|
+
"defaultValue": [single]}], ensure_ascii=False)],
|
|
3664
|
+
check=False)
|
|
3665
|
+
ws_id = made.get("worksheetId", "") if isinstance(made, dict) else ""
|
|
3666
|
+
check("create-partial: the list form still creates", bool(ws_id),
|
|
3667
|
+
str(made)[:200])
|
|
3668
|
+
if not ws_id:
|
|
3669
|
+
return
|
|
3670
|
+
note = next((c for c in _fields(ws_id)
|
|
3671
|
+
if c.get("controlName") == "备注"), {})
|
|
3672
|
+
check("create-partial: its default is stored",
|
|
3673
|
+
"DEFAULT-QA" in str((note.get("advancedSetting") or {})
|
|
3674
|
+
.get("defsource")), str(note)[:200])
|
|
3675
|
+
ok, res = _try(["worksheet", "update-fields", ws_id, "--fields",
|
|
3676
|
+
_json.dumps([{"type": "Text", "name": "名称"},
|
|
3677
|
+
{"type": "Text", "name": "备注",
|
|
3678
|
+
"defaultValue": single}],
|
|
3679
|
+
ensure_ascii=False)])
|
|
3680
|
+
check("create-partial: update-fields refuses it clearly too",
|
|
3681
|
+
not ok and "defaultValue" in str(res)
|
|
3682
|
+
and "AttributeError" not in str(res), str(res)[:300])
|
|
3683
|
+
finally:
|
|
3684
|
+
if ws_id:
|
|
3685
|
+
_purge(ws_id)
|
|
3686
|
+
|
|
3687
|
+
|
|
3400
3688
|
def case_fb_subgroups(app_id: str, section_id: str) -> None:
|
|
3401
3689
|
"""WO-FB 3.1: the editor can see worksheets in second-level groups."""
|
|
3402
3690
|
print("\nscenario: sub-group visibility (WO-FB 3.1)")
|
|
@@ -4546,6 +4834,8 @@ _CASES = {
|
|
|
4546
4834
|
"view": case_view,
|
|
4547
4835
|
"role": case_role,
|
|
4548
4836
|
"custom-action": case_custom_action,
|
|
4837
|
+
"custom-action-update": case_custom_action_update,
|
|
4838
|
+
"hidden-defaults": case_hidden_defaults,
|
|
4549
4839
|
"chatbot": case_chatbot,
|
|
4550
4840
|
"custom-page": case_custom_page,
|
|
4551
4841
|
"component": case_component,
|
|
@@ -4585,6 +4875,8 @@ _CASES = {
|
|
|
4585
4875
|
"fb-layout-check": case_fb_layout_check,
|
|
4586
4876
|
"fb-pair-relation": case_fb_pair_relation,
|
|
4587
4877
|
"fb-subtable-read": case_fb_subtable_read,
|
|
4878
|
+
"create-partial": case_create_partial,
|
|
4879
|
+
"editor-inline-subtable": case_editor_inline_subtable,
|
|
4588
4880
|
"fb-subgroups": case_fb_subgroups,
|
|
4589
4881
|
"fb-button-target": case_fb_button_target,
|
|
4590
4882
|
"g6-advanced-fields": case_g6_advanced_fields,
|
|
@@ -1299,7 +1299,7 @@ def worksheet_save_button(ctx, worksheet_id, btn_config, action_spec,
|
|
|
1299
1299
|
eff_app = app_id or getattr(session, "default_app_id", "") or ""
|
|
1300
1300
|
data = ws_mod.create_custom_action(
|
|
1301
1301
|
session, worksheet_id, json.loads(action_spec),
|
|
1302
|
-
app_id=eff_app,
|
|
1302
|
+
app_id=eff_app, btn_id=btn_id,
|
|
1303
1303
|
)
|
|
1304
1304
|
else:
|
|
1305
1305
|
btn_data = json.loads(btn_config)
|
|
@@ -84,6 +84,11 @@ class Context:
|
|
|
84
84
|
is_auth = isinstance(e, (AuthenticationError, SessionError))
|
|
85
85
|
if self.json_mode:
|
|
86
86
|
payload = {"error": msg, "type": type(e).__name__}
|
|
87
|
+
# An error may carry state the caller needs to act on, e.g.
|
|
88
|
+
# the id of a worksheet a failed create left behind.
|
|
89
|
+
details = getattr(e, "details", None)
|
|
90
|
+
if isinstance(details, dict):
|
|
91
|
+
payload.update(details)
|
|
87
92
|
if is_auth:
|
|
88
93
|
payload["hint"] = NOT_LOGGED_IN_HINT
|
|
89
94
|
payload["not_logged_in"] = True
|
|
@@ -15,6 +15,8 @@ the plain CLI commands — see ``editspec.RETIRED_OPS``.
|
|
|
15
15
|
"""
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import json
|
|
19
|
+
import uuid
|
|
18
20
|
from typing import Any, Callable
|
|
19
21
|
|
|
20
22
|
from hap_cli.core import page as page_mod
|
|
@@ -31,6 +33,61 @@ def _ws_field_save(s, ws_id, controls):
|
|
|
31
33
|
return ws_mod.save_controls(s, ws_id, controls)
|
|
32
34
|
|
|
33
35
|
|
|
36
|
+
# ── inline sub-table sheets: written through the parent (bug #455768) ───
|
|
37
|
+
# Such a sheet cannot be saved on its own; the product edits its columns
|
|
38
|
+
# as the parent's sub-table column ``relationControls`` and saves the
|
|
39
|
+
# parent. See ``AppIndex._subtable_map`` for the evidence.
|
|
40
|
+
def _subtable_columns(idx: AppIndex, ws_ref: str):
|
|
41
|
+
"""``(parent_id, parent controls, host column)`` copies, or None.
|
|
42
|
+
|
|
43
|
+
The host column and its ``relationControls`` are copied so the
|
|
44
|
+
mutation never leaks into the index cache.
|
|
45
|
+
"""
|
|
46
|
+
host = idx.subtable_host(ws_ref)
|
|
47
|
+
if host is None:
|
|
48
|
+
return None
|
|
49
|
+
parent_id, column_id = host
|
|
50
|
+
controls = [dict(c) for c in idx.controls(parent_id)]
|
|
51
|
+
column = next((c for c in controls if c.get("controlId") == column_id),
|
|
52
|
+
None)
|
|
53
|
+
if column is None:
|
|
54
|
+
raise ResolveError(
|
|
55
|
+
f"the sub-table column hosting worksheet {ws_ref!r} is gone")
|
|
56
|
+
column["relationControls"] = [dict(r) for r in
|
|
57
|
+
column.get("relationControls") or []]
|
|
58
|
+
return parent_id, controls, column
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _sorts_of(column: dict) -> tuple[dict, list]:
|
|
62
|
+
adv = column.get("advancedSetting")
|
|
63
|
+
if isinstance(adv, str):
|
|
64
|
+
try:
|
|
65
|
+
adv = json.loads(adv) if adv else {}
|
|
66
|
+
except ValueError:
|
|
67
|
+
adv = {}
|
|
68
|
+
adv = dict(adv or {})
|
|
69
|
+
try:
|
|
70
|
+
sorts = json.loads(adv.get("controlssorts") or "[]")
|
|
71
|
+
except (TypeError, ValueError):
|
|
72
|
+
sorts = []
|
|
73
|
+
return adv, sorts if isinstance(sorts, list) else []
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _set_display(column: dict, show: list, sorts: list) -> None:
|
|
77
|
+
"""Keep ``showControls`` and ``controlssorts`` in step with the
|
|
78
|
+
columns — the product updates both on every add/delete/reorder, or
|
|
79
|
+
the sub-table renders its columns out of order (MDPublic
|
|
80
|
+
ConfigureControls.jsx ``updateControlsWithSorts``)."""
|
|
81
|
+
adv, _ = _sorts_of(column)
|
|
82
|
+
adv["controlssorts"] = json.dumps(sorts)
|
|
83
|
+
column["advancedSetting"] = adv
|
|
84
|
+
column["showControls"] = show
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _sub_label(ws_ref: str) -> str:
|
|
88
|
+
return f"'{ws_ref}' (sub-table, saved through its parent)"
|
|
89
|
+
|
|
90
|
+
|
|
34
91
|
def _far_worksheet_of(controls: list[dict], bridge_id: str) -> str:
|
|
35
92
|
"""The worksheet a bridge column reaches, from its own dataSource."""
|
|
36
93
|
for c in controls:
|
|
@@ -144,6 +201,27 @@ def _field_add(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
|
144
201
|
# place.
|
|
145
202
|
control = lower_field(field)
|
|
146
203
|
|
|
204
|
+
sub = _subtable_columns(idx, op["worksheet"])
|
|
205
|
+
if sub is not None:
|
|
206
|
+
if control.get("type") == 34:
|
|
207
|
+
raise ResolveError(
|
|
208
|
+
f"cannot add sub-table {field.get('name')!r} inside the "
|
|
209
|
+
f"sub-table {op['worksheet']!r}")
|
|
210
|
+
parent_id, controls, column = sub
|
|
211
|
+
control = dict(control)
|
|
212
|
+
# A dashed placeholder: the server mints the real id and rewrites
|
|
213
|
+
# it in showControls too (verified live 2026-10-08).
|
|
214
|
+
control["controlId"] = str(uuid.uuid4())
|
|
215
|
+
column["relationControls"].append(control)
|
|
216
|
+
_, sorts = _sorts_of(column)
|
|
217
|
+
_set_display(column,
|
|
218
|
+
list(column.get("showControls") or [])
|
|
219
|
+
+ [control["controlId"]],
|
|
220
|
+
sorts + [control["controlId"]])
|
|
221
|
+
return [Action(f"add field '{op['field']['name']}' to "
|
|
222
|
+
f"{_sub_label(op['worksheet'])}",
|
|
223
|
+
lambda s: _ws_field_save(s, parent_id, controls))]
|
|
224
|
+
|
|
147
225
|
# Mounting an existing worksheet is a two-step handshake — build the
|
|
148
226
|
# SUB_LIST, then wire the child side's back-relation — and
|
|
149
227
|
# `mount_existing_subtable` is the composite that already does both.
|
|
@@ -179,11 +257,20 @@ def _match_control(controls: list, ref: str) -> dict:
|
|
|
179
257
|
|
|
180
258
|
def _field_update(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
181
259
|
ws_id = idx.worksheet_id(op["worksheet"])
|
|
182
|
-
|
|
183
|
-
|
|
260
|
+
sub = _subtable_columns(idx, op["worksheet"])
|
|
261
|
+
if sub is not None:
|
|
262
|
+
parent_id, controls, column = sub
|
|
263
|
+
target = _match_control(column["relationControls"], op["field"])
|
|
264
|
+
else:
|
|
265
|
+
controls = [dict(c) for c in idx.controls(op["worksheet"])]
|
|
266
|
+
target = _match_control(controls, op["field"])
|
|
184
267
|
if op.get("rename"):
|
|
185
268
|
target["controlName"] = op["rename"]
|
|
186
269
|
target.update(op.get("set", {}))
|
|
270
|
+
if sub is not None:
|
|
271
|
+
return [Action(f"update field '{op['field']}' on "
|
|
272
|
+
f"{_sub_label(op['worksheet'])}",
|
|
273
|
+
lambda s: _ws_field_save(s, parent_id, controls))]
|
|
187
274
|
return [Action(f"update field '{op['field']}' on '{op['worksheet']}' "
|
|
188
275
|
f"(write-back {len(controls)} controls)",
|
|
189
276
|
lambda s: _ws_field_save(s, ws_id, controls))]
|
|
@@ -191,6 +278,21 @@ def _field_update(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
|
191
278
|
|
|
192
279
|
def _field_delete(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
193
280
|
ws_id = idx.worksheet_id(op["worksheet"])
|
|
281
|
+
sub = _subtable_columns(idx, op["worksheet"])
|
|
282
|
+
if sub is not None:
|
|
283
|
+
parent_id, controls, column = sub
|
|
284
|
+
gone = _match_control(column["relationControls"],
|
|
285
|
+
op["field"]).get("controlId")
|
|
286
|
+
column["relationControls"] = [r for r in column["relationControls"]
|
|
287
|
+
if r.get("controlId") != gone]
|
|
288
|
+
_, sorts = _sorts_of(column)
|
|
289
|
+
_set_display(column,
|
|
290
|
+
[i for i in column.get("showControls") or []
|
|
291
|
+
if i != gone],
|
|
292
|
+
[i for i in sorts if i != gone])
|
|
293
|
+
return [Action(f"delete field '{op['field']}' from "
|
|
294
|
+
f"{_sub_label(op['worksheet'])}",
|
|
295
|
+
lambda s: _ws_field_save(s, parent_id, controls))]
|
|
194
296
|
controls = idx.controls(op["worksheet"])
|
|
195
297
|
target = _match_control(controls, op["field"])
|
|
196
298
|
remaining = [c for c in controls
|
|
@@ -202,7 +304,12 @@ def _field_delete(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
|
202
304
|
|
|
203
305
|
def _field_reorder(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
204
306
|
ws_id = idx.worksheet_id(op["worksheet"])
|
|
205
|
-
|
|
307
|
+
sub = _subtable_columns(idx, op["worksheet"])
|
|
308
|
+
if sub is not None:
|
|
309
|
+
parent_id, parent_controls, column = sub
|
|
310
|
+
controls = column["relationControls"]
|
|
311
|
+
else:
|
|
312
|
+
controls = [dict(c) for c in idx.controls(op["worksheet"])]
|
|
206
313
|
by_ref: dict[str, dict] = {}
|
|
207
314
|
for c in controls:
|
|
208
315
|
for k in (c.get("controlId"), c.get("controlName"), c.get("alias")):
|
|
@@ -225,6 +332,15 @@ def _field_reorder(op: dict[str, Any], idx: AppIndex) -> list[Action]:
|
|
|
225
332
|
for i, c in enumerate(ordered):
|
|
226
333
|
c["row"] = i
|
|
227
334
|
c["col"] = 0
|
|
335
|
+
if sub is not None:
|
|
336
|
+
column["relationControls"] = ordered
|
|
337
|
+
ids = [c.get("controlId") for c in ordered]
|
|
338
|
+
shown = set(column.get("showControls") or [])
|
|
339
|
+
_set_display(column, [i for i in ids if i in shown], ids)
|
|
340
|
+
return [Action(f"reorder {len(op['order'])} field(s) on "
|
|
341
|
+
f"{_sub_label(op['worksheet'])}",
|
|
342
|
+
lambda s: _ws_field_save(s, parent_id,
|
|
343
|
+
parent_controls))]
|
|
228
344
|
return [Action(f"reorder {len(op['order'])} field(s) on '{op['worksheet']}'",
|
|
229
345
|
lambda s: _ws_field_save(s, ws_id, ordered))]
|
|
230
346
|
|