hap-cli 0.9.2__tar.gz → 0.9.4__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.2 → hap_cli-0.9.4}/PKG-INFO +1 -1
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/smoke.py +111 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/__init__.py +1 -1
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/context.py +5 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/field_spec_adapter.py +6 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/worksheet.py +147 -14
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_core.py +72 -0
- hap_cli-0.9.4/hap_cli/tests/test_create_worksheet_partial.py +231 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/PKG-INFO +1 -1
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/SOURCES.txt +1 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/MANIFEST.in +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/README.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/config.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/fixtures/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/fixtures/feedback_scenario.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/harness.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/app_live_tests/state.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/README.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/README_CN.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/__main__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/_entry.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/attachment_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/chat_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/guide_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/commands/worksheet_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/attachment.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/condition_dsl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/department.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/editspec/component.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/editspec/field.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/filter_v3.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/group.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/guide.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/layout_check.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/page.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/post.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/record.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/record_defaults.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/record_form_checks.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/record_lookups.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/record_rules.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/relation_scope.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/role.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/rule_spec_adapter.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/session.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/update.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/worksheet_form.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/worksheet_reference.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/approval.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/chart.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/messages.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/overview.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/post.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/record.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/setup.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/skills.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/workflow.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/en/worksheet.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/index.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/approval.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/chart.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/messages.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/overview.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/post.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/record.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/setup.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/skills.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/workflow.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/guide/zh-Hans/worksheet.md +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/i18n.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_action_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_advanced_setting_guard.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_app_light_color.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_app_section_name.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_approval_wire.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_atomic_write.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_attachment_share.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_batch_add_atomic.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_calendar_date_range.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_calendar_discussion_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chart_filter_merge.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chat_attachment_send.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chat_messages_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chat_recall_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_chat_send_socket.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_coded_responses.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_condition_dsl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_condition_dsl_entries.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_condition_dsl_readback.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_dsl_existing_node_refs.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_dsl_multi_record_guard.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_editor_inline_subtable.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_engine_core_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_arg_consistency.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_bidirectional.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_discussion_mentions.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_entry_module.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_field_record_ref.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_http_error_body.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_json_anywhere.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_json_file_arg.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_layout_check.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_node_get_detail.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_node_summary.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_post_cursor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_publish_reasons.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_replicate_workflow.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_save_fields_shape.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_subgroups.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_subtable_read.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_worksheet_references.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_worksheet_visibility.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fb_worksheet_workflows.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_fields_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g1_chart_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g1_record_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g1_upload_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g1_worksheet_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g2_coverage_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g3_workflow_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g4_approval_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g5_low_frequency_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g6_advanced_fields.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g6_fields_roundtrip.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g7_misc_gaps.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g7b_permanent_delete.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g8_filter_operator.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g8b_pivot_operators.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g8c_empty_filter_and_help_truth.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_g9_appid_resolve.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_guide.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_guide_sections.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_inner_flow_batch_add.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_instance_envelope.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_jsonschema_mini_copy.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_noninteractive_confirm.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_page_filters_group_read.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_page_filters_group_update.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_page_save_page_id.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_post_scope_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_business_rules.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_defaults.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_doc_id_hidden.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_form_checks.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_run_action.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_record_write_fixes.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_relation_scope.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_rmw_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_role_app_scope.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_rule_filters_and_field_warning.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_save_action_silent_drop.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_save_rule_spec.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_select_add_option.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_subtable_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_upload_allow_down.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_upload_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_bool_flags.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_response_format_json.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_view_mdpublic_parity.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_config_keys.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_inner_scope.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_json_file_arg.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_node_delete_missing.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_save_action_dsl_fields.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_structure_listing.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_trigger_outcome.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wf_trigger_preserve.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_wo4_result_handling.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_code_node.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_condition_field_types.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_condition_slots.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_delete_cascade.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_lifecycle_wire.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_node_wire.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_publish_inner.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_worksheet_filter_read.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_worksheet_switch.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/atomic_write.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/confirm.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/__main__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/_wftest.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/charts.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/cleanup.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/compiler.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/config.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/errors.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/executor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/fields.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/hap.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/recording/console.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/recording/report.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/schema.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/seed/template.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/selftest.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/smoke.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/step.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/steps.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/store.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/setup.cfg +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/setup.py +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.9.2 → hap_cli-0.9.4}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -155,6 +155,32 @@ def case_view(app_id: str, section_id: str) -> None:
|
|
|
155
155
|
hap(["worksheet", "delete", ws_id, "-a", app_id, "-y"], check=False)
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
def case_view_spec_partial(app_id: str, section_id: str) -> None:
|
|
159
|
+
"""Bug #455744: a --view-spec naming only the card title must leave the
|
|
160
|
+
calendar's name, type and start-date field alone."""
|
|
161
|
+
print("scenario: view update --view-spec keeps unexpressed settings")
|
|
162
|
+
ws_id = _make_worksheet(app_id, section_id, "LT-view-spec-partial")
|
|
163
|
+
title_id = next((c["controlId"] for c in _fields(ws_id)
|
|
164
|
+
if c.get("attribute") == 1), "")
|
|
165
|
+
res = hap(["worksheet", "view", "create", ws_id, "日历",
|
|
166
|
+
"--view-type", "calendar", "--begin-date", "ctime",
|
|
167
|
+
"-a", app_id])
|
|
168
|
+
vid = res.get("viewId") if isinstance(res, dict) else ""
|
|
169
|
+
check("calendar view created", bool(vid), str(res))
|
|
170
|
+
ok, res = _try(["worksheet", "view", "update", ws_id, vid, "-a", app_id,
|
|
171
|
+
"--view-spec",
|
|
172
|
+
json.dumps({"card": {"titleField": title_id}})])
|
|
173
|
+
check("title-only view-spec update succeeds", ok, str(res))
|
|
174
|
+
view = hap(["worksheet", "view", "info", ws_id, vid]) or {}
|
|
175
|
+
adv = view.get("advancedSetting") or {}
|
|
176
|
+
check("name kept", view.get("name") == "日历", str(view.get("name")))
|
|
177
|
+
check("still a calendar", view.get("viewType") == 4,
|
|
178
|
+
str(view.get("viewType")))
|
|
179
|
+
check("start date kept", adv.get("begindate") == "ctime", str(adv))
|
|
180
|
+
check("title field written", adv.get("viewtitle") == title_id, str(adv))
|
|
181
|
+
hap(["worksheet", "delete", ws_id, "-a", app_id, "-y"], check=False)
|
|
182
|
+
|
|
183
|
+
|
|
158
184
|
def _roles(app_id: str) -> dict[str, str]:
|
|
159
185
|
data = hap(["app", "role", "list", "-a", app_id], check=False)
|
|
160
186
|
roles = data.get("roles", []) if isinstance(data, dict) else []
|
|
@@ -3602,6 +3628,89 @@ def case_editor_inline_subtable(app_id: str, section_id: str) -> None:
|
|
|
3602
3628
|
hap(["worksheet", "delete", parent, "-a", app_id, "-y"], check=False)
|
|
3603
3629
|
|
|
3604
3630
|
|
|
3631
|
+
def case_create_partial(app_id: str, section_id: str) -> None:
|
|
3632
|
+
"""Bug #455775: a failed `worksheet create --fields` leaves nothing."""
|
|
3633
|
+
print("\nscenario: worksheet create --fields failure (#455775)")
|
|
3634
|
+
import json as _json
|
|
3635
|
+
from hap_cli.core import app as app_mod
|
|
3636
|
+
from hap_cli.core.session import Session
|
|
3637
|
+
session = Session.load()
|
|
3638
|
+
project_id = app_mod.app_project_id(session, app_id)
|
|
3639
|
+
prefix = "QA455775"
|
|
3640
|
+
for leftover in [n for n in _worksheets(app_id) if n.startswith(prefix)]:
|
|
3641
|
+
_ensure_absent(app_id, leftover)
|
|
3642
|
+
|
|
3643
|
+
def _ours() -> list[str]:
|
|
3644
|
+
return [n for n in _worksheets(app_id) if n.startswith(prefix)]
|
|
3645
|
+
|
|
3646
|
+
def _purge(ws_id: str) -> None:
|
|
3647
|
+
try:
|
|
3648
|
+
app_mod.purge_app_item(session, app_id=app_id,
|
|
3649
|
+
project_id=project_id,
|
|
3650
|
+
section_id=section_id, item_id=ws_id,
|
|
3651
|
+
item_type=0)
|
|
3652
|
+
except Exception as exc: # noqa: BLE001 — reported, not fatal
|
|
3653
|
+
print(f" note: could not purge {ws_id}: {exc}")
|
|
3654
|
+
|
|
3655
|
+
single = {"source": "static", "value": "DEFAULT-QA"}
|
|
3656
|
+
ok, res = _try(["worksheet", "create", app_id, f"{prefix} Invalid",
|
|
3657
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3658
|
+
{"type": "Text", "name": "名称"},
|
|
3659
|
+
{"type": "Text", "name": "备注",
|
|
3660
|
+
"defaultValue": single}], ensure_ascii=False)])
|
|
3661
|
+
check("create-partial: a single-object default is refused", not ok,
|
|
3662
|
+
str(res)[:200])
|
|
3663
|
+
check("create-partial: the refusal names the field and the shape",
|
|
3664
|
+
"备注" in str(res) and "list of objects" in str(res),
|
|
3665
|
+
str(res)[:300])
|
|
3666
|
+
check("create-partial: nothing was created", _ours() == [], str(_ours()))
|
|
3667
|
+
|
|
3668
|
+
# Passes every offline check, refused by the server at save time:
|
|
3669
|
+
# an alias the worksheet's own record-id column already holds.
|
|
3670
|
+
ok, res = _try(["worksheet", "create", app_id, f"{prefix} PostFail",
|
|
3671
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3672
|
+
{"type": "Text", "name": "名称"},
|
|
3673
|
+
{"type": "Text", "name": "冲突",
|
|
3674
|
+
"extra": {"alias": "rowid"}}],
|
|
3675
|
+
ensure_ascii=False)])
|
|
3676
|
+
check("create-partial: a save rejected after the create fails", not ok,
|
|
3677
|
+
str(res)[:200])
|
|
3678
|
+
check("create-partial: the error says the create was undone",
|
|
3679
|
+
"undone" in str(res), str(res)[:300])
|
|
3680
|
+
check("create-partial: no half-built worksheet is left",
|
|
3681
|
+
_ours() == [], str(_ours()))
|
|
3682
|
+
|
|
3683
|
+
ws_id = ""
|
|
3684
|
+
try:
|
|
3685
|
+
made = hap(["worksheet", "create", app_id, f"{prefix} Array",
|
|
3686
|
+
"--section-id", section_id, "--fields", _json.dumps([
|
|
3687
|
+
{"type": "Text", "name": "名称"},
|
|
3688
|
+
{"type": "Text", "name": "备注",
|
|
3689
|
+
"defaultValue": [single]}], ensure_ascii=False)],
|
|
3690
|
+
check=False)
|
|
3691
|
+
ws_id = made.get("worksheetId", "") if isinstance(made, dict) else ""
|
|
3692
|
+
check("create-partial: the list form still creates", bool(ws_id),
|
|
3693
|
+
str(made)[:200])
|
|
3694
|
+
if not ws_id:
|
|
3695
|
+
return
|
|
3696
|
+
note = next((c for c in _fields(ws_id)
|
|
3697
|
+
if c.get("controlName") == "备注"), {})
|
|
3698
|
+
check("create-partial: its default is stored",
|
|
3699
|
+
"DEFAULT-QA" in str((note.get("advancedSetting") or {})
|
|
3700
|
+
.get("defsource")), str(note)[:200])
|
|
3701
|
+
ok, res = _try(["worksheet", "update-fields", ws_id, "--fields",
|
|
3702
|
+
_json.dumps([{"type": "Text", "name": "名称"},
|
|
3703
|
+
{"type": "Text", "name": "备注",
|
|
3704
|
+
"defaultValue": single}],
|
|
3705
|
+
ensure_ascii=False)])
|
|
3706
|
+
check("create-partial: update-fields refuses it clearly too",
|
|
3707
|
+
not ok and "defaultValue" in str(res)
|
|
3708
|
+
and "AttributeError" not in str(res), str(res)[:300])
|
|
3709
|
+
finally:
|
|
3710
|
+
if ws_id:
|
|
3711
|
+
_purge(ws_id)
|
|
3712
|
+
|
|
3713
|
+
|
|
3605
3714
|
def case_fb_subgroups(app_id: str, section_id: str) -> None:
|
|
3606
3715
|
"""WO-FB 3.1: the editor can see worksheets in second-level groups."""
|
|
3607
3716
|
print("\nscenario: sub-group visibility (WO-FB 3.1)")
|
|
@@ -4749,6 +4858,7 @@ _CASES = {
|
|
|
4749
4858
|
"rs-business-rules": case_rs_business_rules,
|
|
4750
4859
|
"field": case_field,
|
|
4751
4860
|
"view": case_view,
|
|
4861
|
+
"view-spec-partial": case_view_spec_partial,
|
|
4752
4862
|
"role": case_role,
|
|
4753
4863
|
"custom-action": case_custom_action,
|
|
4754
4864
|
"custom-action-update": case_custom_action_update,
|
|
@@ -4792,6 +4902,7 @@ _CASES = {
|
|
|
4792
4902
|
"fb-layout-check": case_fb_layout_check,
|
|
4793
4903
|
"fb-pair-relation": case_fb_pair_relation,
|
|
4794
4904
|
"fb-subtable-read": case_fb_subtable_read,
|
|
4905
|
+
"create-partial": case_create_partial,
|
|
4795
4906
|
"editor-inline-subtable": case_editor_inline_subtable,
|
|
4796
4907
|
"fb-subgroups": case_fb_subgroups,
|
|
4797
4908
|
"fb-button-target": case_fb_button_target,
|
|
@@ -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
|
|
@@ -156,6 +156,12 @@ def adapt_relation_config(spec: dict[str, Any]) -> None:
|
|
|
156
156
|
spec["advanced_setting"] = adv
|
|
157
157
|
|
|
158
158
|
|
|
159
|
+
# The ``source`` values build_defsource below can encode. Anything else
|
|
160
|
+
# was skipped there without a word; the field-spec check refuses it
|
|
161
|
+
# up front instead (bug #455775).
|
|
162
|
+
DEFAULT_VALUE_SOURCES = ("system", "static", "field", "relation")
|
|
163
|
+
|
|
164
|
+
|
|
159
165
|
def build_defsource(
|
|
160
166
|
default_value: list[dict[str, Any]],
|
|
161
167
|
*,
|
|
@@ -490,9 +490,24 @@ def create_worksheet_with_fields(
|
|
|
490
490
|
``{"worksheetId": "...", "saveResult": <SaveWorksheetControls
|
|
491
491
|
response>}``
|
|
492
492
|
"""
|
|
493
|
-
#
|
|
494
|
-
#
|
|
495
|
-
|
|
493
|
+
# Shape the whole field payload before the worksheet exists. Every
|
|
494
|
+
# step of it is offline here (no default columns are kept, so nothing
|
|
495
|
+
# is read back), and it is the same shaping update_fields and
|
|
496
|
+
# save_controls run below — so any spec they would refuse is refused
|
|
497
|
+
# now, instead of after AddWorkSheet left a worksheet behind with
|
|
498
|
+
# only its auto-created columns (bug #455775). The host id only
|
|
499
|
+
# feeds a two-way relation's reverse half; a stand-in builds it the
|
|
500
|
+
# same way the real one will.
|
|
501
|
+
preview = build_fields_payload(
|
|
502
|
+
fields, worksheet_id=_PREFLIGHT_WORKSHEET_ID, title_name=title_name,
|
|
503
|
+
keep_default_controls=False)
|
|
504
|
+
_normalize_defsource(_checked_values(preview))
|
|
505
|
+
# Resolved here rather than left to create_worksheet (which would do
|
|
506
|
+
# the same lookup): undoing a failed create needs the group too, and
|
|
507
|
+
# without it the removal does not reach the recycle bin (seen live
|
|
508
|
+
# 2026-10-08).
|
|
509
|
+
if not section_id:
|
|
510
|
+
section_id = _first_app_section_id(session, app_id)
|
|
496
511
|
created = create_worksheet(
|
|
497
512
|
session, app_id, name,
|
|
498
513
|
project_id=project_id, section_id=section_id,
|
|
@@ -505,18 +520,86 @@ def create_worksheet_with_fields(
|
|
|
505
520
|
raise ValueError(
|
|
506
521
|
f"AddWorkSheet did not return a worksheetId; got {created!r}"
|
|
507
522
|
)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
523
|
+
try:
|
|
524
|
+
save_result = update_fields(
|
|
525
|
+
session, worksheet_id, fields,
|
|
526
|
+
title_name=title_name,
|
|
527
|
+
# Match `worksheet update-fields` CLI: drop the auto-created
|
|
528
|
+
# 名称/描述/附件 columns so the caller's `fields[]` is the full
|
|
529
|
+
# layout. Callers wanting to preserve them can issue an extra
|
|
530
|
+
# update-fields call with keep_default_controls=True.
|
|
531
|
+
keep_default_controls=False,
|
|
532
|
+
)
|
|
533
|
+
# The save reports a rejection in its body rather than raising.
|
|
534
|
+
if isinstance(save_result, dict) and "code" in save_result \
|
|
535
|
+
and save_result.get("code") != 1:
|
|
536
|
+
raise APIError(
|
|
537
|
+
f"The fields were not saved: "
|
|
538
|
+
f"{save_result.get('msg') or save_result.get('code')}",
|
|
539
|
+
code=save_result.get("code"))
|
|
540
|
+
except Exception as exc:
|
|
541
|
+
raise _undo_partial_create(
|
|
542
|
+
session, exc, app_id=app_id, project_id=project_id,
|
|
543
|
+
section_id=section_id, worksheet_id=worksheet_id) from exc
|
|
517
544
|
return {"worksheetId": worksheet_id, "saveResult": save_result}
|
|
518
545
|
|
|
519
546
|
|
|
547
|
+
_PREFLIGHT_WORKSHEET_ID = "0" * 24
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class WorksheetCreateError(APIError):
|
|
551
|
+
"""A create that failed after the worksheet already existed.
|
|
552
|
+
|
|
553
|
+
``details`` is added to the CLI's JSON error output, so a caller
|
|
554
|
+
reading it can tell whether the worksheet is gone or still there.
|
|
555
|
+
"""
|
|
556
|
+
|
|
557
|
+
def __init__(self, message: str, *, worksheet_id: str,
|
|
558
|
+
rolled_back: bool, code: Optional[int] = None):
|
|
559
|
+
super().__init__(message, code=code)
|
|
560
|
+
self.worksheet_id = worksheet_id
|
|
561
|
+
self.rolled_back = rolled_back
|
|
562
|
+
self.details = {"worksheetId": worksheet_id,
|
|
563
|
+
"rolledBack": rolled_back}
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def _undo_partial_create(session: Session, exc: Exception, *, app_id: str,
|
|
567
|
+
project_id: str, section_id: str,
|
|
568
|
+
worksheet_id: str) -> WorksheetCreateError:
|
|
569
|
+
"""Remove the worksheet a failed create left behind.
|
|
570
|
+
|
|
571
|
+
It is removed the way the product removes one — to the recycle bin,
|
|
572
|
+
then out of it (``app.purge_app_item``) — since it holds nothing but
|
|
573
|
+
the auto-created columns and keeping it in the bin would only leave
|
|
574
|
+
a stray to clean up. When that fails as well, the error names the
|
|
575
|
+
worksheet so the caller can finish the job. Either way the original
|
|
576
|
+
reason leads the message.
|
|
577
|
+
"""
|
|
578
|
+
from hap_cli.core import app as app_mod
|
|
579
|
+
reason = str(exc).rstrip(".") or type(exc).__name__
|
|
580
|
+
code = getattr(exc, "code", None)
|
|
581
|
+
logger.warning(
|
|
582
|
+
"worksheet create: fields failed on new worksheet %s (%s); "
|
|
583
|
+
"removing it", worksheet_id, reason)
|
|
584
|
+
try:
|
|
585
|
+
app_mod.purge_app_item(
|
|
586
|
+
session, app_id=app_id, project_id=project_id,
|
|
587
|
+
section_id=section_id, item_id=worksheet_id, item_type=0)
|
|
588
|
+
except Exception as undo_exc: # noqa: BLE001 — reported below
|
|
589
|
+
logger.warning("worksheet create: could not remove %s: %s",
|
|
590
|
+
worksheet_id, undo_exc, exc_info=True)
|
|
591
|
+
return WorksheetCreateError(
|
|
592
|
+
f"{reason}. Worksheet {worksheet_id} was created but its "
|
|
593
|
+
f"fields were not written — delete it, or retry with "
|
|
594
|
+
f"'hap worksheet update-fields {worksheet_id}'.",
|
|
595
|
+
worksheet_id=worksheet_id, rolled_back=False, code=code)
|
|
596
|
+
logger.warning("worksheet create: removed %s", worksheet_id)
|
|
597
|
+
return WorksheetCreateError(
|
|
598
|
+
f"{reason}. The worksheet it had just created was undone; "
|
|
599
|
+
f"nothing was left in the app.",
|
|
600
|
+
worksheet_id=worksheet_id, rolled_back=True, code=code)
|
|
601
|
+
|
|
602
|
+
|
|
520
603
|
def copy_worksheet(
|
|
521
604
|
session: Session,
|
|
522
605
|
worksheet_id: str,
|
|
@@ -1026,6 +1109,7 @@ def check_field_specs(fields: Any) -> None:
|
|
|
1026
1109
|
f'"Text" / "Number" / "Date" / "Dropdown".')
|
|
1027
1110
|
name = spec.get("name")
|
|
1028
1111
|
if isinstance(name, str) and name.strip():
|
|
1112
|
+
_check_default_value(spec, f'{where} ("{name}")')
|
|
1029
1113
|
continue
|
|
1030
1114
|
alias = next((k for k in _FIELD_SPEC_NAME_ALIASES if k in spec), "")
|
|
1031
1115
|
if alias:
|
|
@@ -1041,6 +1125,41 @@ def check_field_specs(fields: Any) -> None:
|
|
|
1041
1125
|
f'name it will show under.')
|
|
1042
1126
|
|
|
1043
1127
|
|
|
1128
|
+
_DEFAULT_VALUE_EXAMPLE = '"defaultValue": [{"source": "static", "value": "..."}]'
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
def _check_default_value(spec: dict[str, Any], where: str) -> None:
|
|
1132
|
+
"""Refuse a ``defaultValue`` the field shaping cannot read.
|
|
1133
|
+
|
|
1134
|
+
It is a list of objects, each naming a ``source`` that
|
|
1135
|
+
``field_spec_adapter.build_defsource`` encodes. A single object or a
|
|
1136
|
+
plain string used to pass this check and crash the shaping halfway —
|
|
1137
|
+
on a create, after the worksheet already existed (bug #455775). An
|
|
1138
|
+
unknown ``source`` was dropped there silently.
|
|
1139
|
+
"""
|
|
1140
|
+
from hap_cli.core.field_spec_adapter import DEFAULT_VALUE_SOURCES
|
|
1141
|
+
value = spec.get("defaultValue")
|
|
1142
|
+
if value in (None, []):
|
|
1143
|
+
return
|
|
1144
|
+
sources = ", ".join(DEFAULT_VALUE_SOURCES)
|
|
1145
|
+
rule = (f"Write it as a list of objects, e.g. {_DEFAULT_VALUE_EXAMPLE}; "
|
|
1146
|
+
f'"source" is one of {sources}.')
|
|
1147
|
+
if not isinstance(value, list):
|
|
1148
|
+
kind = "a single object" if isinstance(value, dict) \
|
|
1149
|
+
else type(value).__name__
|
|
1150
|
+
raise ValueError(f'{where} has "defaultValue" as {kind}. {rule}')
|
|
1151
|
+
for n, entry in enumerate(value, start=1):
|
|
1152
|
+
if not isinstance(entry, dict):
|
|
1153
|
+
raise ValueError(
|
|
1154
|
+
f'{where}: "defaultValue" entry {n} is '
|
|
1155
|
+
f"{type(entry).__name__}, not an object. {rule}")
|
|
1156
|
+
if entry.get("source") not in DEFAULT_VALUE_SOURCES:
|
|
1157
|
+
got = entry.get("source")
|
|
1158
|
+
said = f'"source" {got!r}' if got is not None else 'no "source"'
|
|
1159
|
+
raise ValueError(
|
|
1160
|
+
f'{where}: "defaultValue" entry {n} has {said}. {rule}')
|
|
1161
|
+
|
|
1162
|
+
|
|
1044
1163
|
def build_fields_payload(
|
|
1045
1164
|
fields: list[dict[str, Any]],
|
|
1046
1165
|
*,
|
|
@@ -2103,20 +2222,34 @@ def update_view_spec(
|
|
|
2103
2222
|
from hap_cli.core import view_spec_adapter as _vsa
|
|
2104
2223
|
field_resolver, control_types = _view_field_maps(
|
|
2105
2224
|
session, worksheet_id, app_id)
|
|
2225
|
+
current = get_view_detail(
|
|
2226
|
+
session, worksheet_id, view_id, app_id=app_id) or {}
|
|
2227
|
+
# The adapter is built for create, where a missing type means a table
|
|
2228
|
+
# view and a missing name means "". On an update the spec only says
|
|
2229
|
+
# what changes, so an absent type is the view's current type (it also
|
|
2230
|
+
# drives type-specific translation such as card/cover defaults) and an
|
|
2231
|
+
# absent name must not be written at all — otherwise a title-only spec
|
|
2232
|
+
# turns a calendar into a nameless table view (bug #455744).
|
|
2233
|
+
spec = dict(spec)
|
|
2234
|
+
if "viewType" not in spec and "type" not in spec \
|
|
2235
|
+
and current.get("viewType") is not None:
|
|
2236
|
+
spec["viewType"] = current["viewType"]
|
|
2106
2237
|
payload = _vsa.build_view_payload(
|
|
2107
2238
|
spec, worksheet_id=worksheet_id, app_id=app_id, view_id=view_id,
|
|
2108
2239
|
field_resolver=field_resolver or None,
|
|
2109
2240
|
control_types=control_types or None,
|
|
2110
2241
|
)
|
|
2242
|
+
if "name" not in spec:
|
|
2243
|
+
payload.pop("name", None)
|
|
2111
2244
|
# Changing the view TYPE is not a partial edit. The product handles it
|
|
2112
2245
|
# by posting the whole view object — read back, merged, re-defaulted for
|
|
2113
2246
|
# the new type — with no editAttrs (ViewControl.jsx:256-259). Naming
|
|
2114
2247
|
# viewType in editAttrs is a path the product never takes.
|
|
2115
2248
|
new_type = payload.get("viewType")
|
|
2116
2249
|
if new_type is not None:
|
|
2117
|
-
current = get_view_detail(
|
|
2118
|
-
session, worksheet_id, view_id, app_id=app_id) or {}
|
|
2119
2250
|
if current and current.get("viewType") != new_type:
|
|
2251
|
+
logger.info("view spec: view %s type %s -> %s, saving whole view",
|
|
2252
|
+
view_id, current.get("viewType"), new_type)
|
|
2120
2253
|
merged = {**current, **payload}
|
|
2121
2254
|
merged.pop("editAttrs", None)
|
|
2122
2255
|
merged.pop("editAdKeys", None)
|
|
@@ -10566,6 +10566,78 @@ class TestUpdateViewSpec:
|
|
|
10566
10566
|
assert identity not in body["editAttrs"]
|
|
10567
10567
|
assert "navshow" in body["editAdKeys"]
|
|
10568
10568
|
|
|
10569
|
+
@staticmethod
|
|
10570
|
+
def _route_current(mock_post, current):
|
|
10571
|
+
def _route(url, json=None, **kw):
|
|
10572
|
+
if url.endswith("/Worksheet/GetWorksheetControls"):
|
|
10573
|
+
return _mock_response({"controls": [
|
|
10574
|
+
{"controlId": "c1", "controlName": "标题", "type": 2},
|
|
10575
|
+
]})
|
|
10576
|
+
if url.endswith("/Worksheet/GetWorksheetViewById"):
|
|
10577
|
+
return _mock_response(current)
|
|
10578
|
+
return _mock_response({"viewId": "vw1"})
|
|
10579
|
+
mock_post.side_effect = _route
|
|
10580
|
+
|
|
10581
|
+
@staticmethod
|
|
10582
|
+
def _save_body(mock_post):
|
|
10583
|
+
saves = [c for c in mock_post.call_args_list
|
|
10584
|
+
if c.args[0].endswith("/Worksheet/SaveWorksheetView")]
|
|
10585
|
+
assert len(saves) == 1
|
|
10586
|
+
return saves[0].kwargs["json"]
|
|
10587
|
+
|
|
10588
|
+
@patch("hap_cli.core.session.requests.post")
|
|
10589
|
+
def test_title_only_spec_keeps_calendar_type_and_name(
|
|
10590
|
+
self, mock_post, mock_session):
|
|
10591
|
+
"""Bug #455744: a spec naming only card.titleField must not turn a
|
|
10592
|
+
calendar into a table view or blank its name — the spec says
|
|
10593
|
+
nothing about either, so both are left as they are."""
|
|
10594
|
+
self._route_current(mock_post, {
|
|
10595
|
+
"viewId": "vw1", "viewType": 4, "name": "QA Calendar",
|
|
10596
|
+
"advancedSetting": {"begindate": "cd1"},
|
|
10597
|
+
})
|
|
10598
|
+
ws_mod.update_view_spec(
|
|
10599
|
+
mock_session, "ws1", "vw1", {"card": {"titleField": "c1"}},
|
|
10600
|
+
app_id="app1",
|
|
10601
|
+
)
|
|
10602
|
+
body = self._save_body(mock_post)
|
|
10603
|
+
# Still a partial edit — not the whole-object type-change save.
|
|
10604
|
+
assert "editAttrs" in body
|
|
10605
|
+
assert body.get("viewType", 4) == 4
|
|
10606
|
+
assert "name" not in body
|
|
10607
|
+
assert "name" not in body["editAttrs"]
|
|
10608
|
+
assert "viewType" not in body["editAttrs"]
|
|
10609
|
+
assert body["advancedSetting"]["viewtitle"] == "c1"
|
|
10610
|
+
assert "begindate" not in body["editAdKeys"]
|
|
10611
|
+
assert body["editAdKeys"] == list(body["advancedSetting"])
|
|
10612
|
+
|
|
10613
|
+
@patch("hap_cli.core.session.requests.post")
|
|
10614
|
+
def test_spec_without_name_keeps_table_view_name(
|
|
10615
|
+
self, mock_post, mock_session):
|
|
10616
|
+
self._route_current(mock_post, {
|
|
10617
|
+
"viewId": "vw1", "viewType": 0, "name": "全部"})
|
|
10618
|
+
ws_mod.update_view_spec(
|
|
10619
|
+
mock_session, "ws1", "vw1", {"card": {"titleField": "c1"}},
|
|
10620
|
+
app_id="app1",
|
|
10621
|
+
)
|
|
10622
|
+
body = self._save_body(mock_post)
|
|
10623
|
+
assert "name" not in body
|
|
10624
|
+
assert "name" not in body["editAttrs"]
|
|
10625
|
+
|
|
10626
|
+
@patch("hap_cli.core.session.requests.post")
|
|
10627
|
+
def test_explicit_type_change_still_saves_whole_view(
|
|
10628
|
+
self, mock_post, mock_session):
|
|
10629
|
+
self._route_current(mock_post, {
|
|
10630
|
+
"viewId": "vw1", "viewType": 0, "name": "全部"})
|
|
10631
|
+
ws_mod.update_view_spec(
|
|
10632
|
+
mock_session, "ws1", "vw1", {"viewType": "gallery"},
|
|
10633
|
+
app_id="app1",
|
|
10634
|
+
)
|
|
10635
|
+
body = self._save_body(mock_post)
|
|
10636
|
+
assert body["viewType"] == 3
|
|
10637
|
+
assert "editAttrs" not in body
|
|
10638
|
+
# The spec did not rename it, so the current name rides along.
|
|
10639
|
+
assert body["name"] == "全部"
|
|
10640
|
+
|
|
10569
10641
|
|
|
10570
10642
|
class TestFieldNormalizerFixtureCoverage:
|
|
10571
10643
|
"""Loads the user's captured get_worksheet_structure fixtures from
|