Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/src/components/ai-elements/prompt-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ export const PromptInputActionAddAttachments = ({
return (
<DropdownMenuItem
{...props}
onSelect={(e) => {
e.preventDefault();
closeOnClick={false}
onClick={() => {
attachments.openFileDialog();
}}
>
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/components/pages/topics/Tab.Messages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ import { isServerless } from '../../../../config';
import { useQueryStateWithCallback } from '../../../../hooks/use-query-state-with-callback';
import { PayloadEncoding } from '../../../../protogen/redpanda/api/console/v1alpha1/common_pb';
import { appGlobal } from '../../../../state/app-global';
import { useTopicSettingsStore } from '../../../../stores/topic-settings-store';
import { DEFAULT_SORTING, useTopicSettingsStore } from '../../../../stores/topic-settings-store';
import { IsDev } from '../../../../utils/env';
import { sanitizeString, wrapFilterFragment } from '../../../../utils/filter-helper';
import { trimSlidingWindow } from '../../../../utils/message-table-helpers';
Expand Down Expand Up @@ -472,7 +472,7 @@ export const TopicMessageView: FC<TopicMessageViewProps> = (props) => {
getDefaultValue: () => getSorting(props.topic.topicName),
},
'sort',
sortingParser.withDefault([])
sortingParser.withDefault(DEFAULT_SORTING)
);

// Continuous pagination toggle state
Expand Down Expand Up @@ -572,11 +572,16 @@ export const TopicMessageView: FC<TopicMessageViewProps> = (props) => {
})
: messages;

// For continuous pagination, just use the filtered messages directly
// We don't use placeholders as they cause page content to shift
// Continuous pagination disables header sorting, so the table's sorted row
// model can't impose newest-first there. Force it for the "Newest" fetch only
// (timestamp desc, then offset desc as a cross-partition tiebreak). Other
// origins keep the streamed order.
// In the normal paginated view the table sorts client-side via the default
// `sorting` state (DEFAULT_SORTING = timestamp desc, offset desc), so we pass
// the rows through untouched here.
const filteredMessages =
continuousPaginationEnabled && startOffset === PartitionOffsetOrigin.EndMinusResults
? [...baseFilteredMessages].sort((a, b) => b.timestamp - a.timestamp)
? [...baseFilteredMessages].sort((a, b) => b.timestamp - a.timestamp || b.offset - a.offset)
: baseFilteredMessages;

// Convert @computed activePreviewTags to useMemo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ function DropdownMenuContent({
type DropdownMenuItemProps = React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean;
variant?: 'default' | 'destructive';
/** @deprecated Base UI menu items have no `onSelect`. Use `onClick` (add `closeOnClick={false}` to keep the menu open). */
onSelect?: never;
};

function DropdownMenuItem({
Expand Down Expand Up @@ -276,6 +278,8 @@ function DropdownMenuItem({

type DropdownMenuCheckboxItemProps = React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
inset?: boolean;
/** @deprecated Base UI menu items have no `onSelect`. Use `onClick` (add `closeOnClick={false}` to keep the menu open). */
onSelect?: never;
};

function DropdownMenuCheckboxItem({
Expand Down Expand Up @@ -313,6 +317,8 @@ function DropdownMenuCheckboxItem({

type DropdownMenuRadioItemProps = React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
inset?: boolean;
/** @deprecated Base UI menu items have no `onSelect`. Use `onClick` (add `closeOnClick={false}` to keep the menu open). */
onSelect?: never;
};

function DropdownMenuRadioItem({ className, children, disabled, inset, ...props }: DropdownMenuRadioItemProps) {
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/stores/topic-settings-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,15 @@ export type TopicSettingsStore = {
clearAllSettings: () => void;
};

const DEFAULT_SORTING: SortingState = [];
// Default display order for the message list: newest-first by timestamp, with
// offset descending as a cross-partition tiebreak (offset isn't global across
// partitions, so timestamp is the primary key). The backend's listMessages
// stream isn't globally timestamp-sorted across partitions, so this default
// drives the table's client-side sort to give users a sensible newest-first view.
export const DEFAULT_SORTING: SortingState = [
{ id: 'timestamp', desc: true },
{ id: 'offset', desc: true },
];

const DEFAULT_SEARCH_PARAMS: TopicSearchParams = {
offsetOrigin: -1,
Expand Down Expand Up @@ -214,7 +222,11 @@ export const useTopicSettingsStore = create<TopicSettingsStore>()(

getSorting: (topicName: string) => {
const topic = get().perTopicSettings.find((t) => t.topicName === topicName);
return topic?.searchParams.sorting ?? DEFAULT_SORTING;
const sorting = topic?.searchParams.sorting;
// Treat an empty/unset sort as "use the newest-first default" so the
// default applies on every fresh load, including returning users whose
// persisted settings still hold the old empty sort.
return sorting && sorting.length > 0 ? sorting : DEFAULT_SORTING;
},

setSearchParams: (topicName: string, searchParams: Partial<TopicSearchParams>) => {
Expand Down
Loading