Skip to content

Studio: add a new action to an installed app's object, saved in the customization package #30088

Open

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

The maintainer: 「studio没有操作类型的元数据吗?除了批量操作,别的也需要配置的呀。」 (2026-11-04). Measured by the seat on main 63b86b385d, on the example CRM and a throwaway writable package. No domain:* label is set: triage routes this card.

Business reason

An operations person wants a 标记合格 button on the leads of an installed CRM. Studio has a good action editor, but only for a writable package. On an installed app the object's 操作 tab lists the vendor's actions and offers no 新建, so the most common real case is the one case with no door. The platform already accepts the result.

Measured

Check Result
Writable package, 对象 → 高级 → 操作 新建操作 with presets (修改下拉选择字段, 运行流程, 打开网页, 在对话框中打开页面, 高级), the full editor and placements 记录头部, 记录 · 更多菜单, 记录 · 分区, 记录 · 关联列表, 列表 · 行
Read-only CRM, same tab Lists the actions, with no 新建 or 删除, and the 只读 chip shows
PUT /api/v1/meta/action/eval_1104_lead_qualify?package=com.example.crm.custom&mode=draft, a new name with objectName: 'crm_lead', then publish 200, published
The running CRM The row menu shows the new action, and it ran: POST /api/v1/actions/crm_lead/…. The move it tried was not allowed, and the state machine refused it with 线索不能变更到这个状态。
The Studio tab after that publish Lists it, with type SCRIPT and no 新增 mark

The action in a writable package is stored on the object draft (draft.actions, StudioDesignSurface.tsx CelPanelTab), not as a separate item. On a read-only object that route cannot save, so the door has to write a standalone action item into the pair, as the API call above did.

Acceptance

  1. On a read-only base with a pair, the object's 操作 tab offers 新建. It uses the same presets and editor and saves a new-named action into the pair as a draft.
  2. Vendor actions stay read-only in that list, and the added one carries the customization mark and can be edited and removed.
  3. It publishes with 待发布的变更, and 仅看定制 counts it.
  4. A browser check on the CRM: add, publish, see it in the row menu, run it, remove it.
  5. No spec or server change is expected. If one is needed, report it here.

Not in this card

Changing a vendor's action (#30065), and selection-bar placement (the decision card filed beside this one).

Re-check

git grep -n "viewMode === 'actions'" origin/main -- ui/packages/app-shell/src/views/studio-design

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 kept · domain:ui · 2026-11-04T13:57Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-support-ai · session_01WGufzinedUGSXteN45poyo

    Claim: PM loop round 1
    Session: session_01WGufzemmgi8p8uY913FXHx (card thread executor; seat session session_01WGufzinedUGSXteN45poyo)
    Account: os-support-ai
    Branch: claude/project-thread-yom13c (harness-pinned card thread branch; the claude/issue-<n>-<slug> convention does not apply to a project card thread)
    Worktree: objectstack-issue-30088
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: ui/packages/app-shell/src/views/studio-design/** (ObjectActionsPanel.tsx, StudioDesignSurface.tsx actions branch, pair/customization helpers), its tests, root .changeset/
    Container & model: M–L, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate; PM judgment call, default tier), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6632526505
    Premise: holds
    Serial constraints cleared: #30063 (domain:ui#1, page customize door, may touch StudioDesignSurface.tsx / StudioCustomizeControls.tsx) and #30064 (domain:ui#3, dataset door) share studio-design files: ordinary concurrency, merge main before PR and after a sibling lands. #30089 (ruled A) and #30065 (domain:server) are triage-serial on the action editor and stay unclaimed by this seat until this card lands.

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-support-ai · session_01WGufzemmgi8p8uY913FXHx
    os-dev-report
    Stamp: 2026-11-05T02:07Z

    {
      "issue": 30088,
      "status": "done",
      "branch": "claude/project-thread-yom13c",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30211",
      "head": "238e15e3",
      "session": "session_01WGufzemmgi8p8uY913FXHx",
      "premise_still_valid": true,
      "summary": "Acceptance 1-4 ship in one PR. On a read-only base with a pair (or one the ensure door can create), the Data pillar Actions view offers New with the same presets and editor; the action is written as a standalone action item into the pair as a draft (objectName bound, ifNoneMatch star, ensure door asked on first write). Vendor rows stay read-only; added rows carry the added CustomizationMark, autosave into the pair draft, and Delete resets the pair draft then the published row. The Actions list has its own only-customizations toggle counting added actions. No spec or server change (Acceptance 5 holds). The object rail count does not include pair actions because the served customization read lists none; noted in Acceptance notes.",
      "tests": "New DataPillar.pairActions-30088.test.tsx 5/5 passed (incl. CONTROL on a writable package). Ablations via scripts/ablation-replace.mjs, each restored with git diff HEAD empty: pair route off -> 3 failed/2 passed; door gate off -> 1 failed/4 passed; underscore-key strip off -> 1 failed/4 passed. Sweep on head 238e15e3: 79 app-shell files importing DataPillar/ObjectActionsPanel/pairObjectActions + 95 i18n files = 174 files, 1977 passed, 13 skipped (narrowed from 214 StudioDesignSurface importers; only the Data pillar Actions branch changed there). Browser check on app-crm dev boot with 12 screenshots in ui-orders/30088-shots/: add (ensure 201, PUT draft into pair 200), publish (publishedCount 1), row menu shows the action, run (POST /actions/crm_lead/crm_lead_action_2 200, row turned qualified), remove (DELETE at pair 200, gone from Studio and the row menu).",
      "gates": "Local, head 238e15e3: full pnpm build exit 0 then turbo build app-shell closure exit 0; type-check app-shell + i18n exit 0; npx eslint on 4 touched files 0 errors; dispatch-gates --commands 35 commands all exit 0 (incl. check-sdui-manifest.mjs, vitest run scripts/, check:type-check-debt); --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. CI check-runs: in_progress at report time.",
      "line_budget": "+908 / -30, 7 files, about 940 changed lines; under the 1,500 split line and 3,000 cap",
      "files_changed": [
        ".changeset/30088-studio-pair-object-actions.md",
        "ui/packages/app-shell/src/views/studio-design/DataPillar.pairActions-30088.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/ObjectActionsPanel.tsx",
        "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
        "ui/packages/app-shell/src/views/studio-design/pairObjectActions.ts",
        "ui/packages/i18n/src/namespaces/studio/en.ts",
        "ui/packages/i18n/src/namespaces/studio/zh.ts"
      ],
      "deviations": [
        "File surface: the claim names ui/packages/app-shell/src/views/studio-design/** and the changeset; the diff also adds one key (engine.studio.actions.renameHeld) to ui/packages/i18n/src/namespaces/studio/en.ts and zh.ts, and the changeset names @object-ui/i18n. Seat may append that to the claim's file surface.",
        "The harness asked to set an assignee and reviewer on the PR via MCP; skipped per the order (no assignee, no reviewer, no MCP writes).",
        "Browser check ran on f8bdead2 (before merging main 474c030b); the merge touched no file this diff changes."
      ],
      "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 MCP GitHub calls (reads went through gh api REST search and issue reads)",
      "api_writes": "2: relay pr_create (PR 30211, read back identical, 9887 bytes) and this os-dev-report comment via post-stamped.mjs; plus 4 git pushes",
      "open_questions": [
        {
          "question": "Should the object rail (not only the Actions list) mark and count a base object that carries a pair action?",
          "options": [
            "A: leave it on the Actions list (this PR)",
            "B: extend the served customization read with pair actions on base objects (spec + server card)"
          ],
          "recommendation": "A, because B is a spec and server change outside Acceptance 5; file B only if the maintainer wants the object row marked."
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: the object rail only-customizations count reads the served customization read, which lists no standalone pair action (PR Acceptance notes)"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-support-ai · session_01WGufzinedUGSXteN45poyo

    Landing stroke refused · PR #30211 · 2026-11-05T02:24Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions