Skip to content

Commit 474b40e

Browse files
fix(plugin-detail): show the action's option label on the record history badge (#28989)
domain:ui#4 · zhuangjianguo · session_01QsR2jR9wsxdgKzces31XWg <!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} --> _Requested by **Steedos** · [project thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbPt4BqVrm2MVcQn63SRJQJh)_ Fixes #28894 Clause-②: yes (widening) Metadata-protocol: none ## 维护者速读 - 改了什么:记录页「历史」时间线的动作徽章,不再把存储值大写后直接显示,而是显示来源字段选项的翻译标签。`HistoryTimeline` 新增可选属性 `actionField`(`{ object, field }`),用 `useSafeFieldLabel().fieldOptionLabel` 读服务端下发的翻译;`record:history` 自取数据时指明来源是 `sys_activity.type`,所以中文界面显示「已更新」「已创建」。 - 为什么改:中文用户打开任何记录的历史标签页,都看到英文大写的 UPDATED / CREATED,旁边的摘要却是中文。翻译早已下发,只是徽章没有用。与卡片原文的偏差:徽章的值来自 `sys_activity.type`(`updated` / `created`),不是 `sys_audit_log.action`(`update` / `create`),席位已按此修订认领。 - 风险与回滚:没有翻译标签的值、以及宿主自行传入的条目,仍按存储值大写显示,英文界面外观不变。不改元数据、不改协议、不发新请求。回滚即还原本 PR。 - 先看:`ui/packages/plugin-detail/src/HistoryTimeline.tsx`(徽章的 `actionLabel` 与 `uppercase` 条件)、`ui/packages/plugin-detail/src/renderers/record-history.tsx`(`SELF_FETCH_ACTION_FIELD`)。 - 两分钟验证:`cd ui && pnpm exec vitest run packages/plugin-detail/src/__tests__/HistoryTimeline.actionLabel-28894.test.tsx packages/plugin-detail/src/renderers/__tests__/record-history.actionLabel-28894.test.tsx`,预期 6 个用例全绿。 - 需要你做的:无,席位落地。 ## What changes - **`HistoryTimeline`** takes an optional `actionField` prop, `{ object, field }`, naming the select field the entries' `action` values come from. Each badge shows `useSafeFieldLabel().fieldOptionLabel(object, field, value, value)`: the option's label in the active language from the served translations, the same read the record page makes for any select option label. A value with no label, and every value when `actionField` is not given, shows as stored. The `uppercase` class now applies only to a value shown as stored, so a translated label is drawn as the translation spells it. - **`record:history`** passes `{ object: 'sys_activity', field: 'type' }` for the entries it fetches itself, because its self-fetch maps each `sys_activity` row's `type` to the entry's `action`. Entries a host passes in name no source and keep the stored value. - The badge tone (`ACTION_VARIANT`) still keys on the stored value. No new request, no ui map of action labels. ## Why The HotCRM lead page's History tab printed `UPDATED` / `CREATED` beside Chinese summaries, although the option labels were already translated and served. **Deviation from the card's text (claim amendment 6568854052).** The card names `sys_audit_log.action` as the label source. Measured at `origin/main` `9a9823d9` and HotCRM `d4ffe99`, the reproduced badge reads `sys_activity.type` instead: - The lead History tab is an authored `record:history` block (HotCRM `src/sales/pages/lead_detail.page.ts`). It has no host entries, so the block self-fetches `sys_activity` and maps `action: r.type`. - The badges seen, `UPDATED` / `CREATED`, are the `sys_activity.type` values `updated` / `created`. `sys_audit_log.action` stores `update` / `create`. - The row text (更新了 线索 …:职位) is the `sys_activity` summary (`plugin-audit` `activityUpdatedFields`). - On the synthesized record page the `sys_audit_log` read feeds `record:activity`, not `HistoryTimeline`. So the badge reads the option labels of `sys_activity.type` (zh-CN: 已更新 / 已创建). The card's intent is unchanged: labels come from the declared options through the served translations, the raw value is the fallback, and the ui holds no map. ## Tests - New `HistoryTimeline.actionLabel-28894.test.tsx`: zh shows 已更新 / 已创建 without `uppercase`; a value with no option label shows as stored, upper-cased; en keeps the upper-cased look where the label is the stored word; no `actionField` shows every value as stored. The bundle is built with `transformSpecTranslations`, the transform the console applies to `/api/v1/i18n/translations/:locale`. - New `record-history.actionLabel-28894.test.tsx`: the self-fetch labels its badges from `sys_activity.type` in zh; host entries keep the stored value. - Ablations, each through `scripts/ablation-replace.mjs`, with the blob restored to HEAD and `git diff HEAD` empty afterwards: - `record-history` stops passing the source (`actionField={undefined}`): 1 red, the self-fetch zh case. - The label read is removed (`fieldOptionLabel(…)` replaced by the stored value): 2 red, the zh cases of both files. - `uppercase` applied unconditionally: 2 red, the zh cases of both files. ## Acceptance notes - Acceptance 1 (zh labels): at head `f7a834c5`, a `pnpm dev:crm -- --fresh` server, signed in as the dev admin, served `GET /api/v1/i18n/translations/zh-CN` with `objects.sys_activity.fields.type.options` = `created: 已创建, updated: 已更新, …` (twelve options). The en bundle serves each option as its value (`updated: updated`). The console flattens that document into the `fieldOptions` keys `fieldOptionLabel` reads, which is the shape the unit tests build. The served document is in the project files at `issue-28894/served-zh-CN-translations.json`. NOT MEASURED: a browser run of the built console on a record's History tab, because it needs `pnpm console:build`. - Acceptance 2 (fallback): a value with no option label (for example a custom `activityMilestones[].type`) shows as stored. - Acceptance 3 (`uppercase`): it applies only to a value shown as stored. English badges look as before, because the en label is the stored word. - `HistoryTimelineProps`, which is exported, gains one optional member (`actionField`), and the package entry now exports its type `HistoryActionField`. That widens a published type, so the declaration is `Clause-②: yes (widening)` (claim amended on the card); the changeset stays `patch` with `Metadata-protocol: none`. - Outside this card: `DetailView`'s own history tab (`schema.history.entries`) names no source, so its badges keep the stored value. `ACTION_VARIANT` keys are `sys_audit_log` actions (`update`, `create`, …), so every `sys_activity` entry gets the neutral outline tone, as it did before this PR. Noted, not filed. ## Verification <details><summary>Local runs</summary> - At head `f7a834c5` (before merging main): - `pnpm exec vitest run` over all 363 `ui/packages/plugin-detail` test files, in three batches: Test Files 362 passed and 1 skipped; Tests 3195 passed and 18 skipped. - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: 34 derived commands, all exit 0. `--ran` reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. These include `check-sdui-manifest.mjs`, `check-changeset-no-major.mjs --base origin/main`, `check-adr-0087-registration.mjs`, `check:type-check-debt`, `check:published-files`, `check:nul-bytes`, and `pnpm --dir ui exec vitest run scripts/` (Test Files 169 passed, 2 skipped; Tests 4900 passed, 2 skipped). - At head 64c9ef5 (main `62b3ec36` merged, clean): - The six history test files: Test Files 6 passed, Tests 45 passed. - `turbo run type-check --filter=@object-ui/plugin-detail`: 48 of 48 tasks successful. The script runs `tsc -p tsconfig.test.json` as well, so it covers the tests. - `dispatch-gates --commands` derived the same 34 commands; all 34 exit 0 again (the PR-body gates read this body). `--ran`: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. `vitest run scripts/`: Test Files 169 passed, 2 skipped; Tests 4900 passed, 2 skipped. - At head `9ec21e47` (main `00d0668d` merged, clean): nothing re-run. The incoming files touch no file under `ui/packages/plugin-detail`, `ui/packages/i18n` or `ui/packages/react`. They include #28895's audit log badge (`ui/apps/console/src/pages/system/`), which labels from the served `sys_audit_log` document. This PR does not touch that page. - At head `cb4cac0c` (declaration rework: `HistoryActionField` exported, `Clause-②: yes (widening)`): `dispatch-gates --commands` derived the same 34 commands. All 34 exit 0, and the PR-body gates read this body. `--ran`: 34 derived, 34 run, 0 NOT-MEASURED. `turbo run type-check --filter=@object-ui/plugin-detail`: 48 of 48 tasks. </details> ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (`packages/spec` not touched.) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` is CI's run. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: not applicable. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the 维护者速读 section is the Chinese summary the repo asks for). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QsR2jR9wsxdgKzces31XWg --- _Generated by [Claude Code](https://claude.ai/code/session_01QsR2jR9wsxdgKzces31XWg)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4df6292 commit 474b40e

6 files changed

Lines changed: 230 additions & 5 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): the record history badge shows the action's option label, not the stored word upper-cased
6+
7+
Clause-②: yes (widening)
8+
Metadata-protocol: none
9+
10+
A record's history tab printed each entry's stored action value in an upper-cased badge. A zh reader saw `UPDATED` and `CREATED` beside a Chinese summary, although the option's zh label was already served.
11+
12+
What changes:
13+
14+
- `HistoryTimeline` takes an optional `actionField` prop, `{ object, field }` (its type, `HistoryActionField`, is exported from the package entry), that names the select field its entries' `action` values come from. Each badge then shows that option's label in the active language, read through `useSafeFieldLabel().fieldOptionLabel` like any select option label on the record page.
15+
- `record:history` names `sys_activity.type` for the entries it fetches itself, so in zh its badges read 已更新 and 已创建.
16+
- A value with no label, and every value when no field is named (entries a host passes in, for example), shows as stored. Only a value shown as stored is upper-cased, so the English badges look the same as before.
17+
18+
What to do: nothing. No metadata a page, view or object declares changes.

‎ui/packages/plugin-detail/src/HistoryTimeline.tsx‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
* - Never re-fetches data on its own; relies on the caller to resolve
2020
* `user_name` / `user_avatar` from `user_id` and to provide a pre-computed
2121
* `changes` diff so this component stays presentation-only and SSR-safe.
22+
* - The action badge shows the declared option label of the field the entries'
23+
* `action` values come from, when the caller names that field
24+
* (`actionField`). It holds no list of action labels of its own.
2225
*/
2326
import * as React from 'react';
2427
import {
@@ -34,6 +37,7 @@ import {
3437
cn,
3538
} from '@object-ui/components';
3639
import { useDisplayLocale, useSafeTranslate } from '@object-ui/i18n';
40+
import { useSafeFieldLabel } from '@object-ui/react';
3741
import { Cog } from 'lucide-react';
3842
import { hasCellValue } from './emptiness';
3943

@@ -59,6 +63,16 @@ export interface HistoryEntry {
5963
[extra: string]: unknown;
6064
}
6165

66+
/**
67+
* The select field an entry's `action` value is stored in, named by object and
68+
* field (`{ object: 'sys_activity', field: 'type' }` for `record:history`'s
69+
* self-fetch).
70+
*/
71+
export interface HistoryActionField {
72+
object: string;
73+
field: string;
74+
}
75+
6276
export interface HistoryTimelineProps {
6377
entries: HistoryEntry[];
6478
loading?: boolean;
@@ -79,6 +93,17 @@ export interface HistoryTimelineProps {
7993
* (objectui#9786). Pass this only to OVERRIDE that composition.
8094
*/
8195
locale?: string;
96+
/**
97+
* The select field the entries' `action` values come from. Each badge then
98+
* shows that field's option label in the active language, read from the
99+
* served translations through `useSafeFieldLabel().fieldOptionLabel`, the
100+
* read the record page uses for any select option label.
101+
*
102+
* A value with no label there, and every value when this is not given, shows
103+
* as stored. Only a value shown as stored is drawn upper-case: a translated
104+
* label is drawn as the translation spells it.
105+
*/
106+
actionField?: HistoryActionField;
82107
}
83108

84109
// Kept keys mirror the server-declared `sys_audit_log.action` enum
@@ -179,13 +204,15 @@ export function HistoryTimeline({
179204
unknownUserText,
180205
className,
181206
locale,
207+
actionField,
182208
}: HistoryTimelineProps) {
183209
// The composed tag this timeline formats with when the caller states none.
184210
// Read before the early returns below so the hook order never varies.
185211
const displayLocale = useDisplayLocale();
186212
const resolvedLocale = locale ?? displayLocale;
187213
const tt = useSafeTranslate();
188214
const systemActorText = tt('detail.systemActor', 'System');
215+
const { fieldOptionLabel } = useSafeFieldLabel();
189216
if (loading) {
190217
return (
191218
<div className={cn('space-y-3', className)}>
@@ -221,6 +248,10 @@ export function HistoryTimeline({
221248
{entries.map((entry, idx) => {
222249
const action = (entry.action ?? '').toLowerCase();
223250
const variant = ACTION_VARIANT[action] ?? 'outline';
251+
const actionLabel =
252+
entry.action && actionField
253+
? fieldOptionLabel(actionField.object, actionField.field, entry.action, entry.action)
254+
: entry.action;
224255
const resolvedName =
225256
(typeof entry.user_name === 'string' && entry.user_name.trim()) || '';
226257
// No name AND no id: nobody acted, so this is a system write, not
@@ -253,8 +284,11 @@ export function HistoryTimeline({
253284
<div className="flex flex-wrap items-baseline gap-x-2 gap-y-1">
254285
<span className="text-sm font-medium text-foreground">{displayName}</span>
255286
{entry.action && (
256-
<Badge variant={variant} className="text-[10px] uppercase tracking-wide">
257-
{entry.action}
287+
<Badge
288+
variant={variant}
289+
className={cn('text-[10px] tracking-wide', actionLabel === entry.action && 'uppercase')}
290+
>
291+
{actionLabel}
258292
</Badge>
259293
)}
260294
{absoluteWhen && (
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* The action badge shows the declared option label of the field its entries
6+
* come from (objectstack#28894).
7+
*
8+
* The badge printed the stored value and upper-cased it with CSS, so a zh
9+
* reader saw "UPDATED" beside a Chinese summary although the option's zh label
10+
* was already served. With `actionField` named, the badge reads the label the
11+
* served translations give that option; a value with no label, and every value
12+
* when no field is named, shows as stored. Only a stored value is upper-cased.
13+
*
14+
* The bundle is built with `transformSpecTranslations`, the transform the
15+
* console applies to `/api/v1/i18n/translations/:locale`, so the keys are the
16+
* ones the console really holds.
17+
*/
18+
import { describe, it, expect, afterEach } from 'vitest';
19+
import { render, screen, cleanup } from '@testing-library/react';
20+
import { I18nProvider, transformSpecTranslations } from '@object-ui/i18n';
21+
import { HistoryTimeline, type HistoryEntry } from '../HistoryTimeline';
22+
23+
const SOURCE = { object: 'sys_activity', field: 'type' } as const;
24+
25+
const spec = (options: Record<string, string>) =>
26+
transformSpecTranslations({
27+
objects: { sys_activity: { label: 'Activity', fields: { type: { label: 'Type', options } } } },
28+
});
29+
30+
const RESOURCES = {
31+
// The zh-CN labels plugin-audit serves for these two options.
32+
zh: spec({ created: '已创建', updated: '已更新' }),
33+
// The en bundle spells each option as its value.
34+
en: spec({ created: 'created', updated: 'updated' }),
35+
};
36+
37+
const entries: HistoryEntry[] = [
38+
{ id: 1, action: 'updated', user_name: 'Ada Lovelace', created_at: '2026-01-02T00:00:00.000Z' },
39+
{ id: 2, action: 'created', user_name: 'Ada Lovelace', created_at: '2026-01-01T00:00:00.000Z' },
40+
{ id: 3, action: 'assigned', user_name: 'Ada Lovelace', created_at: '2025-12-31T00:00:00.000Z' },
41+
];
42+
43+
function mount(language: 'zh' | 'en', actionField?: typeof SOURCE) {
44+
return render(
45+
<I18nProvider config={{ defaultLanguage: language, detectBrowserLanguage: false, resources: RESOURCES }}>
46+
<HistoryTimeline entries={entries} actionField={actionField} />
47+
</I18nProvider>,
48+
);
49+
}
50+
51+
afterEach(() => cleanup());
52+
53+
describe('HistoryTimeline action badge label (objectstack#28894)', () => {
54+
it('shows the option label in zh, not the stored value, and does not upper-case it', () => {
55+
mount('zh', SOURCE);
56+
const updated = screen.getByText('已更新');
57+
const created = screen.getByText('已创建');
58+
expect(updated.className).not.toContain('uppercase');
59+
expect(created.className).not.toContain('uppercase');
60+
expect(screen.queryByText('updated')).toBeNull();
61+
expect(screen.queryByText('created')).toBeNull();
62+
});
63+
64+
it('shows a value with no option label as stored, upper-cased', () => {
65+
mount('zh', SOURCE);
66+
const assigned = screen.getByText('assigned');
67+
expect(assigned.className).toContain('uppercase');
68+
});
69+
70+
it('keeps the English look where the label is the stored word', () => {
71+
mount('en', SOURCE);
72+
expect(screen.getByText('updated').className).toContain('uppercase');
73+
expect(screen.getByText('created').className).toContain('uppercase');
74+
});
75+
76+
it('shows every value as stored when no source field is named', () => {
77+
mount('zh');
78+
expect(screen.queryByText('已更新')).toBeNull();
79+
expect(screen.getByText('updated').className).toContain('uppercase');
80+
expect(screen.getByText('created').className).toContain('uppercase');
81+
});
82+
});

‎ui/packages/plugin-detail/src/index.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export type { SectionGroupProps } from './SectionGroup';
166166
export type { HeaderHighlightProps } from './HeaderHighlight';
167167
export type { RecordCommentsProps } from './RecordComments';
168168
export type { ActivityTimelineProps, ActivityFilterType } from './ActivityTimeline';
169-
export type { HistoryTimelineProps, HistoryEntry } from './HistoryTimeline';
169+
export type { HistoryTimelineProps, HistoryEntry, HistoryActionField } from './HistoryTimeline';
170170
export type { RichTextCommentInputProps, MentionSuggestion } from './RichTextCommentInput';
171171
export { extractMentions } from './extractMentions';
172172
export type { MentionTarget } from './extractMentions';
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
/**
10+
* `record:history` labels each badge from `sys_activity.type` (objectstack#28894).
11+
*
12+
* The block self-fetches `sys_activity` and maps each row's `type` to the
13+
* entry's `action`, so the badge's source field is `sys_activity.type`. In zh
14+
* the badge reads that option's served label (已更新), not the stored word
15+
* upper-cased (UPDATED). Entries a host passes in name no source, so they keep
16+
* the stored value.
17+
*/
18+
19+
import * as React from 'react';
20+
import { describe, it, expect, vi, afterEach } from 'vitest';
21+
import { render, screen, cleanup } from '@testing-library/react';
22+
import { I18nProvider, transformSpecTranslations } from '@object-ui/i18n';
23+
import { RecordContextProvider } from '@object-ui/react';
24+
import { RecordHistoryRenderer } from '../record-history';
25+
26+
const RESOURCES = {
27+
zh: transformSpecTranslations({
28+
objects: {
29+
sys_activity: {
30+
label: '活动',
31+
fields: { type: { label: '类型', options: { created: '已创建', updated: '已更新' } } },
32+
},
33+
},
34+
}),
35+
};
36+
37+
const ROWS = [
38+
{ id: 'a-1', type: 'updated', summary: '更新了 线索 "Lead 1":职位', timestamp: '2026-01-02T00:00:00.000Z' },
39+
{ id: 'a-2', type: 'created', summary: '创建了 线索 "Lead 1"', timestamp: '2026-01-01T00:00:00.000Z' },
40+
];
41+
42+
function mount(schema: Record<string, unknown> = {}) {
43+
const dataSource = { find: vi.fn(async () => ({ data: ROWS })) } as any;
44+
render(
45+
<I18nProvider config={{ defaultLanguage: 'zh', detectBrowserLanguage: false, resources: RESOURCES }}>
46+
<RecordContextProvider
47+
objectName="crm_lead"
48+
recordId="rec-1"
49+
data={{ id: 'rec-1', name: 'Lead 1' }}
50+
dataSource={dataSource}
51+
>
52+
<RecordHistoryRenderer schema={schema as any} />
53+
</RecordContextProvider>
54+
</I18nProvider>,
55+
);
56+
return dataSource;
57+
}
58+
59+
afterEach(() => cleanup());
60+
61+
describe('record:history badge label (objectstack#28894)', () => {
62+
it('labels self-fetched entries from sys_activity.type in zh', async () => {
63+
const dataSource = mount();
64+
const updated = await screen.findByText('已更新');
65+
expect(updated.className).not.toContain('uppercase');
66+
expect(screen.getByText('已创建')).toBeTruthy();
67+
expect(screen.queryByText('updated')).toBeNull();
68+
expect(dataSource.find).toHaveBeenCalledWith('sys_activity', expect.anything());
69+
});
70+
71+
it('keeps the stored value for host-supplied entries, which name no source', () => {
72+
mount({ entries: [{ id: 'h-1', action: 'updated', user_name: 'Ada Lovelace', created_at: '2026-01-02T00:00:00.000Z' }] });
73+
expect(screen.getByText('updated').className).toContain('uppercase');
74+
expect(screen.queryByText('已更新')).toBeNull();
75+
});
76+
});

‎ui/packages/plugin-detail/src/renderers/record-history.tsx‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import React from 'react';
2222
import { useRecordContext } from '@object-ui/react';
23-
import { HistoryTimeline, type HistoryEntry } from '../HistoryTimeline';
23+
import { HistoryTimeline, type HistoryActionField, type HistoryEntry } from '../HistoryTimeline';
2424
import { activityActorName } from './recordActivityFeed';
2525

2626
const splitDesigner = (props: Record<string, any>) => {
@@ -61,6 +61,15 @@ function activityActorId(row: { actor_id?: unknown }): string | number | null {
6161
* history (comments/mentions/logins are not record-history). */
6262
const HISTORY_TYPES = new Set(['created', 'updated', 'assigned', 'shared', 'deleted']);
6363

64+
/**
65+
* Where a self-fetched entry's `action` comes from: `sys_activity.type`, a
66+
* select whose declared options carry translated labels. The timeline labels
67+
* each badge from that field, so 'updated' reads as the language spells the
68+
* option, not as the stored word. Host-supplied entries name no source and
69+
* keep the stored value.
70+
*/
71+
const SELF_FETCH_ACTION_FIELD: HistoryActionField = { object: 'sys_activity', field: 'type' };
72+
6473
/**
6574
* Rows this block shows when the author declared no usable cap.
6675
*
@@ -233,7 +242,13 @@ export const RecordHistoryRenderer: React.FC<RecordHistoryRendererProps> = ({
233242

234243
return (
235244
<div className={className} {...designer}>
236-
<HistoryTimeline entries={entries} loading={loading} emptyText={emptyText} unknownUserText={unknownUserText} />
245+
<HistoryTimeline
246+
entries={entries}
247+
loading={loading}
248+
emptyText={emptyText}
249+
unknownUserText={unknownUserText}
250+
actionField={hostEntries === undefined ? SELF_FETCH_ACTION_FIELD : undefined}
251+
/>
237252
</div>
238253
);
239254
};

0 commit comments

Comments
 (0)