Compare commits

...

1 Commits

Author SHA1 Message Date
Nikhil Soni
e6c7c09d11 feat: add pinned attributes preference support for log details
Mirrors the trace-details pin feature (#11092): pinned fields persist
as the per-user preference log_details_pinned_attributes and sync
across devices via the existing PrettyView/usePinnedFields machinery.

Assisted-by: Claude Opus 4.8
2026-08-25 15:57:15 +05:30
7 changed files with 64 additions and 0 deletions

View File

@@ -6,4 +6,5 @@ export const USER_PREFERENCES = {
SPAN_DETAILS_PREVIEW_ATTRIBUTES: 'span_details_preview_attributes',
SPAN_DETAILS_COLOR_BY_ATTRIBUTE: 'span_details_color_by_attribute',
SPAN_PERCENTILE_RESOURCE_ATTRIBUTES: 'span_percentile_resource_attributes',
LOG_DETAILS_PINNED_ATTRIBUTES: 'log_details_pinned_attributes',
};

View File

@@ -20,6 +20,7 @@ import { ILog } from 'types/api/logs/log';
import { ActionItemProps } from './ActionItem';
import { useLogAttributeActions } from './hooks/useLogAttributeActions';
import { useLogPinnedFields } from './hooks/useLogPinnedFields';
import TableView from './TableView';
import {
aggregateAttributesResourcesToObject,
@@ -71,6 +72,8 @@ function Overview({
isListViewPanel,
onApplyLogFilter,
});
const { value: pinnedFieldsValue, onChange: onPinnedFieldsChange } =
useLogPinnedFields();
const isLogDetailsV2 = useIsLogDetailsV2();
@@ -86,6 +89,9 @@ function Overview({
prettyViewProps={{
actions,
visibleActions,
showPinned: true,
pinnedFieldsValue,
onPinnedFieldsChange,
renderLeafValue: (value, keyPath): ReactNode | undefined => {
// Sanitize (unescape + ANSI→color) string values under `body`.
// Skip huge ones (render raw, still safe) to avoid the sanitize

View File

@@ -10,4 +10,5 @@ export enum LogDetailsAction {
FILTER_OUT = 'filter-out',
GROUP_BY = 'group-by',
REPLACE_FILTER = 'replace-filter',
PIN = 'pin',
}

View File

@@ -44,6 +44,7 @@ const ALL_LEAF_ACTIONS = [
LogDetailsAction.FILTER_OUT,
LogDetailsAction.GROUP_BY,
LogDetailsAction.REPLACE_FILTER,
LogDetailsAction.PIN,
];
/**

View File

@@ -0,0 +1,44 @@
import { useCallback, useMemo } from 'react';
import { useMutation } from 'react-query';
import updateUserPreferenceAPI from 'api/v1/user/preferences/name/update';
import { USER_PREFERENCES } from 'constants/userPreferences';
import { useAppContext } from 'providers/App/App';
interface UseLogPinnedFieldsReturn {
value: string[];
onChange: (next: string[]) => void;
}
/**
* Reads/writes log-details pinned attributes from the user preference
* `log_details_pinned_attributes` (cross-device sync).
*/
export function useLogPinnedFields(): UseLogPinnedFieldsReturn {
const { userPreferences, updateUserPreferenceInContext } = useAppContext();
const { mutate } = useMutation(updateUserPreferenceAPI);
const value = useMemo<string[]>(() => {
const pref = userPreferences?.find(
(p) => p.name === USER_PREFERENCES.LOG_DETAILS_PINNED_ATTRIBUTES,
);
return (pref?.value as string[] | undefined) ?? [];
}, [userPreferences]);
const onChange = useCallback(
(next: string[]) => {
const existing = userPreferences?.find(
(p) => p.name === USER_PREFERENCES.LOG_DETAILS_PINNED_ATTRIBUTES,
);
if (existing) {
updateUserPreferenceInContext({ ...existing, value: next });
}
mutate({
name: USER_PREFERENCES.LOG_DETAILS_PINNED_ATTRIBUTES,
value: next,
});
},
[userPreferences, updateUserPreferenceInContext, mutate],
);
return { value, onChange };
}

View File

@@ -23,6 +23,7 @@ var (
NameSpanDetailsPreviewAttributes = Name{valuer.NewString("span_details_preview_attributes")}
NameSpanDetailsColorByAttribute = Name{valuer.NewString("span_details_color_by_attribute")}
NameSpanPercentileResourceAttributes = Name{valuer.NewString("span_percentile_resource_attributes")}
NameLogDetailsPinnedAttributes = Name{valuer.NewString("log_details_pinned_attributes")}
)
type Name struct{ valuer.String }
@@ -45,6 +46,7 @@ func NewName(name string) (Name, error) {
NameSpanDetailsPreviewAttributes.StringValue(),
NameSpanDetailsColorByAttribute.StringValue(),
NameSpanPercentileResourceAttributes.StringValue(),
NameLogDetailsPinnedAttributes.StringValue(),
},
name,
)

View File

@@ -190,6 +190,15 @@ func NewAvailablePreference() map[Name]Preference {
AllowedValues: []string{},
Value: MustNewValue([]any{}, ValueTypeArray),
},
NameLogDetailsPinnedAttributes: {
Name: NameLogDetailsPinnedAttributes,
Description: "List of pinned attributes in log details drawer.",
ValueType: ValueTypeArray,
DefaultValue: MustNewValue([]any{}, ValueTypeArray),
AllowedScopes: []Scope{ScopeUser},
AllowedValues: []string{},
Value: MustNewValue([]any{}, ValueTypeArray),
},
}
}