hap-cli 0.9.3__tar.gz → 0.9.5__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.3 → hap_cli-0.9.5}/PKG-INFO +1 -1
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/smoke.py +27 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/__init__.py +1 -1
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/post_cmd.py +57 -7
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/post.py +58 -10
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/upload.py +21 -10
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/worksheet.py +16 -2
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/post.md +2 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/post.md +2 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/locale/messages.json +14 -6
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_core.py +72 -0
- hap_cli-0.9.5/hap_cli/tests/test_post_attachments.py +182 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/PKG-INFO +1 -1
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/SOURCES.txt +1 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/MANIFEST.in +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/README.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/config.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/fixtures/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/fixtures/feedback_scenario.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/harness.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/app_live_tests/state.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/README.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/README_CN.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/__main__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/_entry.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/attachment_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/chat_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/guide_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/commands/worksheet_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/context.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/attachment.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/condition_dsl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/department.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/editspec/component.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/editspec/field.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/filter_v3.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/group.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/guide.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/layout_check.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/page.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/record.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/record_defaults.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/record_form_checks.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/record_lookups.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/record_rules.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/relation_scope.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/role.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/rule_spec_adapter.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/session.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/update.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/worksheet_form.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/worksheet_reference.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/approval.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/chart.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/messages.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/overview.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/record.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/setup.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/skills.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/workflow.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/en/worksheet.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/index.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/approval.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/chart.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/messages.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/overview.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/record.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/setup.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/skills.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/workflow.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/guide/zh-Hans/worksheet.md +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/i18n.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_action_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_advanced_setting_guard.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_app_light_color.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_app_section_name.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_approval_wire.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_atomic_write.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_attachment_share.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_batch_add_atomic.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_calendar_date_range.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_calendar_discussion_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chart_filter_merge.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chat_attachment_send.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chat_messages_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chat_recall_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_chat_send_socket.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_coded_responses.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_condition_dsl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_condition_dsl_entries.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_condition_dsl_readback.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_create_worksheet_partial.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_dsl_existing_node_refs.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_dsl_multi_record_guard.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_editor_inline_subtable.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_engine_core_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_arg_consistency.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_bidirectional.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_discussion_mentions.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_entry_module.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_field_record_ref.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_http_error_body.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_json_anywhere.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_json_file_arg.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_layout_check.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_node_get_detail.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_node_summary.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_post_cursor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_publish_reasons.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_replicate_workflow.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_save_fields_shape.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_subgroups.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_subtable_read.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_worksheet_references.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_worksheet_visibility.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fb_worksheet_workflows.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_fields_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g1_chart_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g1_record_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g1_upload_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g1_worksheet_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g2_coverage_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g3_workflow_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g4_approval_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g5_low_frequency_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g6_advanced_fields.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g6_fields_roundtrip.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g7_misc_gaps.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g7b_permanent_delete.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g8_filter_operator.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g8b_pivot_operators.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g8c_empty_filter_and_help_truth.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_g9_appid_resolve.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_guide.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_guide_sections.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_inner_flow_batch_add.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_instance_envelope.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_jsonschema_mini_copy.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_noninteractive_confirm.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_page_filters_group_read.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_page_filters_group_update.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_page_save_page_id.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_post_scope_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_business_rules.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_defaults.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_doc_id_hidden.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_form_checks.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_run_action.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_record_write_fixes.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_relation_scope.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_rmw_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_role_app_scope.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_rule_filters_and_field_warning.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_save_action_silent_drop.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_save_rule_spec.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_select_add_option.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_subtable_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_upload_allow_down.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_upload_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_bool_flags.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_response_format_json.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_view_mdpublic_parity.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_config_keys.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_inner_scope.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_json_file_arg.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_node_delete_missing.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_save_action_dsl_fields.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_structure_listing.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_trigger_outcome.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wf_trigger_preserve.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_wo4_result_handling.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_code_node.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_condition_field_types.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_condition_slots.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_delete_cascade.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_lifecycle_wire.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_node_wire.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_publish_inner.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_worksheet_filter_read.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_worksheet_switch.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/atomic_write.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/confirm.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/__main__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/_wftest.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/charts.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/cleanup.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/compiler.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/config.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/errors.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/executor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/fields.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/hap.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/recording/console.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/recording/report.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/schema.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/seed/template.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/selftest.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/smoke.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/step.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/steps.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/store.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/setup.cfg +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/setup.py +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.9.3 → hap_cli-0.9.5}/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 []
|
|
@@ -4832,6 +4858,7 @@ _CASES = {
|
|
|
4832
4858
|
"rs-business-rules": case_rs_business_rules,
|
|
4833
4859
|
"field": case_field,
|
|
4834
4860
|
"view": case_view,
|
|
4861
|
+
"view-spec-partial": case_view_spec_partial,
|
|
4835
4862
|
"role": case_role,
|
|
4836
4863
|
"custom-action": case_custom_action,
|
|
4837
4864
|
"custom-action-update": case_custom_action_update,
|
|
@@ -131,6 +131,19 @@ def _resolve_markers(
|
|
|
131
131
|
return out
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
def _simplify_attachments(items: Any) -> list[dict[str, Any]]:
|
|
135
|
+
out = []
|
|
136
|
+
for a in items or []:
|
|
137
|
+
if not isinstance(a, dict):
|
|
138
|
+
continue
|
|
139
|
+
out.append({
|
|
140
|
+
"id": a.get("fileID"),
|
|
141
|
+
"name": f"{a.get('originalFilename') or ''}{a.get('ext') or ''}",
|
|
142
|
+
"size": a.get("filesize"),
|
|
143
|
+
})
|
|
144
|
+
return out
|
|
145
|
+
|
|
146
|
+
|
|
134
147
|
def _simplify_comment(c: dict[str, Any]) -> dict[str, Any]:
|
|
135
148
|
text = _resolve_markers(
|
|
136
149
|
c.get("message") or "",
|
|
@@ -152,6 +165,9 @@ def _simplify_comment(c: dict[str, Any]) -> dict[str, Any]:
|
|
|
152
165
|
}
|
|
153
166
|
if c.get("withAttachment") and str(c["withAttachment"]) != "0":
|
|
154
167
|
out["has_attachment"] = True
|
|
168
|
+
files = _simplify_attachments(c.get("attachments"))
|
|
169
|
+
if files:
|
|
170
|
+
out["attachments"] = files
|
|
155
171
|
return out
|
|
156
172
|
|
|
157
173
|
|
|
@@ -203,6 +219,9 @@ def _simplify_post(p: dict[str, Any]) -> dict[str, Any]:
|
|
|
203
219
|
m_groups = [_simplify_group_ref(g) for g in (p.get("rGroupList") or [])]
|
|
204
220
|
if m_groups:
|
|
205
221
|
out["mentioned_groups"] = m_groups
|
|
222
|
+
files = _simplify_attachments(p.get("attachments"))
|
|
223
|
+
if files:
|
|
224
|
+
out["attachments"] = files
|
|
206
225
|
return out
|
|
207
226
|
|
|
208
227
|
|
|
@@ -377,6 +396,8 @@ def _render_post_detail(detail: dict[str, Any]) -> None:
|
|
|
377
396
|
click.echo("")
|
|
378
397
|
for line in (detail.get("text") or "").splitlines() or [""]:
|
|
379
398
|
click.echo(f" {line}")
|
|
399
|
+
for f in detail.get("attachments") or []:
|
|
400
|
+
click.echo(f" 📎 {f.get('name')}")
|
|
380
401
|
click.echo("")
|
|
381
402
|
|
|
382
403
|
stats = (
|
|
@@ -414,6 +435,8 @@ def _render_post_detail(detail: dict[str, Any]) -> None:
|
|
|
414
435
|
click.echo(header)
|
|
415
436
|
for line in (c.get("text") or "").splitlines() or [""]:
|
|
416
437
|
click.echo(f" {line}")
|
|
438
|
+
for f in c.get("attachments") or []:
|
|
439
|
+
click.echo(f" 📎 {f.get('name')}")
|
|
417
440
|
click.echo("")
|
|
418
441
|
|
|
419
442
|
|
|
@@ -669,7 +692,13 @@ def post_get(ctx, post_id):
|
|
|
669
692
|
default=0,
|
|
670
693
|
type=int,
|
|
671
694
|
show_default=True,
|
|
672
|
-
help="Post type
|
|
695
|
+
help="Post type. Leave at 0 (text); adding --file makes it an "
|
|
696
|
+
"attachment post on its own.",
|
|
697
|
+
)
|
|
698
|
+
@click.option(
|
|
699
|
+
"--file", "-f", "files", multiple=True,
|
|
700
|
+
help="Attach a file: a local path or an http(s) address. Repeat for "
|
|
701
|
+
"several. Videos, pictures and documents all work.",
|
|
673
702
|
)
|
|
674
703
|
@click.option(
|
|
675
704
|
"--to-group",
|
|
@@ -694,15 +723,20 @@ def post_get(ctx, post_id):
|
|
|
694
723
|
@click.option("--dry-run", is_flag=True,
|
|
695
724
|
help="Show the audience and what would be sent, without publishing.")
|
|
696
725
|
@pass_context
|
|
697
|
-
def post_create(ctx, org_id, message, post_type,
|
|
698
|
-
legacy_group_ids, legacy_org_ids,
|
|
726
|
+
def post_create(ctx, org_id, message, post_type, files, share_group_ids,
|
|
727
|
+
share_org_ids, legacy_group_ids, legacy_org_ids,
|
|
728
|
+
card_group_ids, dry_run):
|
|
699
729
|
"""Create a new post in the given organization.
|
|
700
730
|
|
|
701
731
|
Audience is set with --to-group / --to-org and defaults to everyone in
|
|
702
732
|
--org-id when neither is given. Who can see a post is covered in
|
|
703
733
|
`hap guide post audience`; the group-chat card is `hap guide post card`.
|
|
734
|
+
Files given with --file are uploaded and attached to the post.
|
|
704
735
|
"""
|
|
705
736
|
try:
|
|
737
|
+
if post_type == post_mod.POST_TYPE_ATTACHMENT and not files:
|
|
738
|
+
raise click.UsageError(
|
|
739
|
+
"An attachment post needs at least one --file.")
|
|
706
740
|
share_group_ids = tuple(share_group_ids) + tuple(legacy_group_ids)
|
|
707
741
|
share_org_ids = tuple(share_org_ids) + tuple(legacy_org_ids)
|
|
708
742
|
if dry_run:
|
|
@@ -712,11 +746,14 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
|
|
|
712
746
|
) or [f"org:{org_id or '<current>'} (everyone, default)"]
|
|
713
747
|
ctx.output(
|
|
714
748
|
{"audience": audience, "cardToGroups": list(card_group_ids),
|
|
715
|
-
"message": message, "
|
|
749
|
+
"message": message, "files": list(files),
|
|
750
|
+
"published": False},
|
|
716
751
|
lambda d: click.echo(
|
|
717
752
|
"Would publish to: " + ", ".join(d["audience"])
|
|
718
753
|
+ (f"; card to groups: {', '.join(d['cardToGroups'])}"
|
|
719
|
-
if d["cardToGroups"] else "")
|
|
754
|
+
if d["cardToGroups"] else "")
|
|
755
|
+
+ (f"; files: {', '.join(d['files'])}"
|
|
756
|
+
if d["files"] else "")),
|
|
720
757
|
)
|
|
721
758
|
return
|
|
722
759
|
session = ctx.get_session()
|
|
@@ -741,6 +778,8 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
|
|
|
741
778
|
+ ". Pick a group whose feed is on, or send a card to the "
|
|
742
779
|
"chat instead with --card-to-group.")
|
|
743
780
|
pid = require_api_project_id(session, org_id)
|
|
781
|
+
attachments = (post_mod.upload_post_files(session, list(files))
|
|
782
|
+
if files else None)
|
|
744
783
|
raw = post_mod.add_post(
|
|
745
784
|
session,
|
|
746
785
|
project_id=pid,
|
|
@@ -748,6 +787,7 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
|
|
|
748
787
|
post_type=post_type,
|
|
749
788
|
share_group_ids=list(share_group_ids) or None,
|
|
750
789
|
share_project_ids=list(share_org_ids) or None,
|
|
790
|
+
attachments=attachments,
|
|
751
791
|
)
|
|
752
792
|
post_obj = raw.get("post") if isinstance(raw, dict) else None
|
|
753
793
|
summary = _simplify_post(post_obj) if post_obj else {"raw": raw}
|
|
@@ -821,14 +861,22 @@ def post_delete(ctx, post_id, yes):
|
|
|
821
861
|
default="",
|
|
822
862
|
help="Member id being replied to (optional; pairs with --reply-id)",
|
|
823
863
|
)
|
|
864
|
+
@click.option(
|
|
865
|
+
"--file", "-f", "files", multiple=True,
|
|
866
|
+
help="Attach a file: a local path or an http(s) address. Repeat for "
|
|
867
|
+
"several. Videos, pictures and documents all work.",
|
|
868
|
+
)
|
|
824
869
|
@pass_context
|
|
825
|
-
def post_comment(ctx, post_id, message, reply_id, reply_account_id):
|
|
826
|
-
"""Add a comment to a post."""
|
|
870
|
+
def post_comment(ctx, post_id, message, reply_id, reply_account_id, files):
|
|
871
|
+
"""Add a comment to a post, optionally with files attached."""
|
|
827
872
|
try:
|
|
828
873
|
session = ctx.get_session()
|
|
874
|
+
attachments = (post_mod.upload_post_files(session, list(files))
|
|
875
|
+
if files else None)
|
|
829
876
|
raw = post_mod.add_comment(
|
|
830
877
|
session, post_id, message,
|
|
831
878
|
reply_id=reply_id, reply_account_id=reply_account_id,
|
|
879
|
+
attachments=attachments,
|
|
832
880
|
)
|
|
833
881
|
comment_obj = raw.get("comment") if isinstance(raw, dict) else None
|
|
834
882
|
summary = _simplify_comment(comment_obj) if comment_obj else {"raw": raw}
|
|
@@ -864,6 +912,8 @@ def post_comments(ctx, post_id):
|
|
|
864
912
|
click.echo(header)
|
|
865
913
|
for line in (c.get("text") or "").splitlines() or [""]:
|
|
866
914
|
click.echo(f" {line}")
|
|
915
|
+
for f in c.get("attachments") or []:
|
|
916
|
+
click.echo(f" 📎 {f.get('name')}")
|
|
867
917
|
click.echo(f" id: {c.get('id')}")
|
|
868
918
|
click.echo("")
|
|
869
919
|
ctx.output(comments, _render)
|
|
@@ -24,6 +24,7 @@ Response envelopes (from a live probe on SaaS):
|
|
|
24
24
|
* ``GetPostDetail`` → bare post object (with ``success: "1"``)
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
+
import json
|
|
27
28
|
import logging
|
|
28
29
|
from typing import Any, Optional
|
|
29
30
|
|
|
@@ -219,6 +220,40 @@ def get_post_detail(session: Session, post_id: str) -> dict[str, Any]:
|
|
|
219
220
|
return session.api_call("Post", "GetPostDetail", {"postId": post_id})
|
|
220
221
|
|
|
221
222
|
|
|
223
|
+
# postType of a post carrying uploaded files ("pic and doc"). The feed's
|
|
224
|
+
# own types: 0 text, 1 link, 2 picture, 3 document, 7 vote, 9 attachments
|
|
225
|
+
# (MDPublic src/pages/feed/components/post/postComponent/factory.jsx:18-41,
|
|
226
|
+
# createFeed/index.js:18-22).
|
|
227
|
+
POST_TYPE_ATTACHMENT = 9
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _attachment_fields(attachments: list[dict[str, Any]]) -> dict[str, str]:
|
|
231
|
+
"""The two attachment keys, as JSON strings — the server takes strings
|
|
232
|
+
here, not arrays. Knowledge-center references are not supported, so
|
|
233
|
+
that list is always empty, as the composer sends it when none are
|
|
234
|
+
picked."""
|
|
235
|
+
return {
|
|
236
|
+
"attachments": json.dumps(attachments, ensure_ascii=False),
|
|
237
|
+
"knowledgeAttach": "[]",
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def upload_post_files(session: Session, sources: list[str]) -> list[dict[str, Any]]:
|
|
242
|
+
"""Upload local paths / http(s) addresses and return attachment items
|
|
243
|
+
for :func:`add_post` / :func:`add_comment`.
|
|
244
|
+
|
|
245
|
+
No organization is named for the upload credential: the feed mounts
|
|
246
|
+
its uploader without a projectId (MDPublic createFeed/
|
|
247
|
+
CreateFeedContent.jsx:124-136), same as chat does here.
|
|
248
|
+
"""
|
|
249
|
+
from hap_cli.core import upload as upload_mod
|
|
250
|
+
|
|
251
|
+
descriptors = upload_mod.upload_files(
|
|
252
|
+
session, upload_mod.source_descriptors(list(sources)))
|
|
253
|
+
logger.info("post: uploaded %d attachment(s)", len(descriptors))
|
|
254
|
+
return upload_mod.attachment_items(descriptors)
|
|
255
|
+
|
|
256
|
+
|
|
222
257
|
def add_post(
|
|
223
258
|
session: Session,
|
|
224
259
|
project_id: str,
|
|
@@ -228,9 +263,16 @@ def add_post(
|
|
|
228
263
|
share_group_ids: Optional[list[str]] = None,
|
|
229
264
|
share_project_ids: Optional[list[str]] = None,
|
|
230
265
|
radio_project_ids: str = "",
|
|
266
|
+
attachments: Optional[list[dict[str, Any]]] = None,
|
|
231
267
|
) -> dict[str, Any]:
|
|
232
268
|
"""Create a post via ``Post.AddPost``.
|
|
233
269
|
|
|
270
|
+
``attachments`` are uploaded-file items (see :func:`upload_post_files`).
|
|
271
|
+
Files make it an attachment post — ``postType`` 9 — and travel as JSON
|
|
272
|
+
strings next to an empty knowledge-center list, exactly as the feed's
|
|
273
|
+
composer sends them (MDPublic src/pages/feed/components/createFeed/
|
|
274
|
+
index.js:18-22 and :163-180; pd-openweb identical).
|
|
275
|
+
|
|
234
276
|
``scope`` is a ``PostShareScopeReq`` object — not an int — and it is
|
|
235
277
|
what decides **who can see the post**. The frontend
|
|
236
278
|
(``pd-openweb/src/pages/feed/components/createFeed/index.js``) posts
|
|
@@ -261,15 +303,16 @@ def add_post(
|
|
|
261
303
|
"shareGroupIds": groups,
|
|
262
304
|
"shareProjectIds": orgs,
|
|
263
305
|
}
|
|
264
|
-
|
|
265
|
-
"
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
306
|
+
data: dict[str, Any] = {
|
|
307
|
+
"projectId": project_id,
|
|
308
|
+
"postType": post_type,
|
|
309
|
+
"postMsg": message,
|
|
310
|
+
"scope": scope,
|
|
311
|
+
}
|
|
312
|
+
if attachments:
|
|
313
|
+
data["postType"] = POST_TYPE_ATTACHMENT
|
|
314
|
+
data.update(_attachment_fields(attachments))
|
|
315
|
+
return session.api_call("Post", "AddPost", data)
|
|
273
316
|
|
|
274
317
|
|
|
275
318
|
def edit_post(
|
|
@@ -304,17 +347,22 @@ def add_comment(
|
|
|
304
347
|
message: str,
|
|
305
348
|
reply_id: str = "",
|
|
306
349
|
reply_account_id: str = "",
|
|
350
|
+
attachments: Optional[list[dict[str, Any]]] = None,
|
|
307
351
|
) -> dict[str, Any]:
|
|
308
352
|
"""Add a comment via ``Post.AddPostComment``.
|
|
309
353
|
|
|
310
354
|
Uses ``postID`` / ``replyID`` (capital ID) to match the documented
|
|
311
|
-
spelling in ``src/api/post.js``.
|
|
355
|
+
spelling in ``src/api/post.js``. ``attachments`` go in the same JSON
|
|
356
|
+
string form as on a post (MDPublic src/pages/feed/components/post/
|
|
357
|
+
comment/postCommentInput.jsx:181-192; pd-openweb identical).
|
|
312
358
|
"""
|
|
313
359
|
data: dict[str, Any] = {"postID": post_id, "message": message}
|
|
314
360
|
if reply_id:
|
|
315
361
|
data["replyID"] = reply_id
|
|
316
362
|
if reply_account_id:
|
|
317
363
|
data["replyAccountId"] = reply_account_id
|
|
364
|
+
if attachments:
|
|
365
|
+
data.update(_attachment_fields(attachments))
|
|
318
366
|
return _require_post_success(
|
|
319
367
|
session.api_call("Post", "AddPostComment", data), action="comment")
|
|
320
368
|
|
|
@@ -427,12 +427,15 @@ def upload_files(
|
|
|
427
427
|
return out
|
|
428
428
|
|
|
429
429
|
|
|
430
|
-
def
|
|
431
|
-
"""
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
430
|
+
def attachment_items(descriptors: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
431
|
+
"""Uploaded-file descriptors as the attachment items the uploader hands
|
|
432
|
+
to whatever it is attached to — the ``formatResponseData`` shape
|
|
433
|
+
(MDPublic src/utils/platform/file/attachment.js:93-111; pd-openweb
|
|
434
|
+
src/components/UploadFiles/utils.js). Posts and post comments send a
|
|
435
|
+
JSON string of these; record cells wrap them further."""
|
|
436
|
+
items = []
|
|
437
|
+
for d in descriptors:
|
|
438
|
+
item = {
|
|
436
439
|
"fileID": d.get("fileID"),
|
|
437
440
|
"fileSize": d.get("fileSize"),
|
|
438
441
|
"serverName": d.get("serverName"),
|
|
@@ -443,12 +446,20 @@ def record_attachment_cell(descriptors: list[dict[str, Any]]) -> dict[str, Any]:
|
|
|
443
446
|
"key": d.get("key"),
|
|
444
447
|
"url": d.get("url"),
|
|
445
448
|
"oldOriginalFileName": d.get("originalFileName"),
|
|
446
|
-
|
|
447
|
-
"isEdit": False,
|
|
448
|
-
})
|
|
449
|
+
}
|
|
449
450
|
# Carried, not recomputed: the descriptor already decided this at
|
|
450
451
|
# upload time — see _download_permission().
|
|
451
452
|
for key in ("allowDown", "docVersionID"):
|
|
452
453
|
if key in d:
|
|
453
|
-
|
|
454
|
+
item[key] = d[key]
|
|
455
|
+
items.append(item)
|
|
456
|
+
return items
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def record_attachment_cell(descriptors: list[dict[str, Any]]) -> dict[str, Any]:
|
|
460
|
+
"""Wrap uploaded-file descriptors into a worksheet Attachment (type 14)
|
|
461
|
+
cell value: ``{attachmentData, attachments, knowledgeAtts}``."""
|
|
462
|
+
attachments = []
|
|
463
|
+
for i, item in enumerate(attachment_items(descriptors)):
|
|
464
|
+
attachments.append({**item, "index": i, "isEdit": False})
|
|
454
465
|
return {"attachmentData": [], "attachments": attachments, "knowledgeAtts": []}
|
|
@@ -2222,20 +2222,34 @@ def update_view_spec(
|
|
|
2222
2222
|
from hap_cli.core import view_spec_adapter as _vsa
|
|
2223
2223
|
field_resolver, control_types = _view_field_maps(
|
|
2224
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"]
|
|
2225
2237
|
payload = _vsa.build_view_payload(
|
|
2226
2238
|
spec, worksheet_id=worksheet_id, app_id=app_id, view_id=view_id,
|
|
2227
2239
|
field_resolver=field_resolver or None,
|
|
2228
2240
|
control_types=control_types or None,
|
|
2229
2241
|
)
|
|
2242
|
+
if "name" not in spec:
|
|
2243
|
+
payload.pop("name", None)
|
|
2230
2244
|
# Changing the view TYPE is not a partial edit. The product handles it
|
|
2231
2245
|
# by posting the whole view object — read back, merged, re-defaulted for
|
|
2232
2246
|
# the new type — with no editAttrs (ViewControl.jsx:256-259). Naming
|
|
2233
2247
|
# viewType in editAttrs is a path the product never takes.
|
|
2234
2248
|
new_type = payload.get("viewType")
|
|
2235
2249
|
if new_type is not None:
|
|
2236
|
-
current = get_view_detail(
|
|
2237
|
-
session, worksheet_id, view_id, app_id=app_id) or {}
|
|
2238
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)
|
|
2239
2253
|
merged = {**current, **payload}
|
|
2240
2254
|
merged.pop("editAttrs", None)
|
|
2241
2255
|
merged.pop("editAdKeys", None)
|
|
@@ -106,6 +106,8 @@ hap post list # list posts
|
|
|
106
106
|
hap post search -k "kw" --scope myself # only your own posts
|
|
107
107
|
hap post get <postId> # one post with its comments
|
|
108
108
|
hap post comment <postId> -m "..." # comment
|
|
109
|
+
hap post create -m "demo" -f ./demo.mp4 # attach a file (repeat -f for more)
|
|
110
|
+
hap post comment <postId> -m "..." -f ./notes.pdf # comment with a file
|
|
109
111
|
hap post delete <postId> # delete
|
|
110
112
|
```
|
|
111
113
|
|
|
@@ -94,6 +94,8 @@ hap post list # 动态列表
|
|
|
94
94
|
hap post search -k "关键字" --scope myself # 只搜自己发的
|
|
95
95
|
hap post get <动态ID> # 查看某条动态及评论
|
|
96
96
|
hap post comment <动态ID> -m "..." # 评论
|
|
97
|
+
hap post create -m "演示" -f ./demo.mp4 # 附带文件(多个就重复 -f)
|
|
98
|
+
hap post comment <动态ID> -m "..." -f ./notes.pdf # 评论附带文件
|
|
97
99
|
hap post delete <动态ID> # 删除
|
|
98
100
|
```
|
|
99
101
|
|
|
@@ -4420,8 +4420,12 @@
|
|
|
4420
4420
|
"zh-Hans": "以 JSON 格式输出"
|
|
4421
4421
|
},
|
|
4422
4422
|
"post comment": {
|
|
4423
|
-
"en": "Add a comment to a post.",
|
|
4424
|
-
"zh-Hans": "
|
|
4423
|
+
"en": "Add a comment to a post, optionally with files attached.",
|
|
4424
|
+
"zh-Hans": "为动态添加评论,可同时附带文件。"
|
|
4425
|
+
},
|
|
4426
|
+
"post comment --file": {
|
|
4427
|
+
"en": "Attach a file: a local path or an http(s) address. Repeat for several. Videos, pictures and documents all work.",
|
|
4428
|
+
"zh-Hans": "附带文件:本地路径或 http(s) 地址,可重复指定多个。视频、图片、文档都可以。"
|
|
4425
4429
|
},
|
|
4426
4430
|
"post comment --json": {
|
|
4427
4431
|
"en": "Output in JSON format",
|
|
@@ -4460,8 +4464,8 @@
|
|
|
4460
4464
|
"zh-Hans": "以 JSON 格式输出"
|
|
4461
4465
|
},
|
|
4462
4466
|
"post create": {
|
|
4463
|
-
"en": "Create a new post in the given organization.\n\nAudience is set with --to-group / --to-org and defaults to everyone in\n--org-id when neither is given. Who can see a post is covered in\n`hap guide post audience`; the group-chat card is `hap guide post card
|
|
4464
|
-
"zh-Hans": "在指定组织中发布新动态。用 --to-group / --to-org 指定发布范围(即谁能看到这条动态),两者都不给时默认发给 --org-id 组织的全体同事。谁能看到这条动态见 `hap guide post audience`;群聊卡片是另一回事,见 `hap guide post card
|
|
4467
|
+
"en": "Create a new post in the given organization.\n\nAudience is set with --to-group / --to-org and defaults to everyone in\n--org-id when neither is given. Who can see a post is covered in\n`hap guide post audience`; the group-chat card is `hap guide post card`.\nFiles given with --file are uploaded and attached to the post.",
|
|
4468
|
+
"zh-Hans": "在指定组织中发布新动态。用 --to-group / --to-org 指定发布范围(即谁能看到这条动态),两者都不给时默认发给 --org-id 组织的全体同事。谁能看到这条动态见 `hap guide post audience`;群聊卡片是另一回事,见 `hap guide post card`。用 --file 指定的文件会上传并作为附件随动态发布。"
|
|
4465
4469
|
},
|
|
4466
4470
|
"post create --card-to-group": {
|
|
4467
4471
|
"en": "After publishing, also send a card linking to the post into this group chat (repeatable). This is a chat message and does not change who can see the post.",
|
|
@@ -4471,6 +4475,10 @@
|
|
|
4471
4475
|
"en": "Show the audience and what would be sent, without publishing.",
|
|
4472
4476
|
"zh-Hans": "仅显示发布范围和将要发送的内容,不实际发布。"
|
|
4473
4477
|
},
|
|
4478
|
+
"post create --file": {
|
|
4479
|
+
"en": "Attach a file: a local path or an http(s) address. Repeat for several. Videos, pictures and documents all work.",
|
|
4480
|
+
"zh-Hans": "附带文件:本地路径或 http(s) 地址,可重复指定多个。视频、图片、文档都可以。"
|
|
4481
|
+
},
|
|
4474
4482
|
"post create --json": {
|
|
4475
4483
|
"en": "Output in JSON format",
|
|
4476
4484
|
"zh-Hans": "以 JSON 格式输出"
|
|
@@ -4492,8 +4500,8 @@
|
|
|
4492
4500
|
"zh-Hans": "发布范围:该组织的全体同事能看到这条动态(可重复指定),即公司范围。"
|
|
4493
4501
|
},
|
|
4494
4502
|
"post create --type": {
|
|
4495
|
-
"en": "Post type
|
|
4496
|
-
"zh-Hans": "
|
|
4503
|
+
"en": "Post type. Leave at 0 (text); adding --file makes it an attachment post on its own.",
|
|
4504
|
+
"zh-Hans": "动态类型。保持 0(文本)即可;加了 --file 会自动成为附件动态。"
|
|
4497
4505
|
},
|
|
4498
4506
|
"post delete": {
|
|
4499
4507
|
"en": "Delete a post.",
|
|
@@ -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
|