Skip to content

Commit c65d628

Browse files
Fix issue when first time adds favorite fields and default fav fields disappear (#25530)
* Fix issue when first time adds favorite fields and default fav fields disappear * add changelog * Use only existing message default favorite fields when save edited * fix tsc
1 parent d01ff21 commit c65d628

9 files changed

Lines changed: 75 additions & 30 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type = "f"
2+
message = "Fix issue when default favorite fields disappear after adding favorite field."
3+
4+
pulls = ["25530"]
5+
issues = ["25517"]

graylog2-web-interface/src/components/common/message/details/context/MessageFavoriteFieldsProvider.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@ import { StreamsStore } from 'views/stores/StreamsStore';
2828
import type { Stream } from 'logic/streams/types';
2929
import { isPermitted } from 'util/PermissionsMixin';
3030
import useCurrentUser from 'hooks/useCurrentUser';
31-
32-
import { DEFAULT_FIELDS } from '../fields/hooks/useMessageFavoriteFieldsForEditing';
33-
import useMessageFavoriteFieldsMutation from '../fields/hooks/useMessageFavoriteFieldsMutation';
31+
import { getStreamFavoriteFields } from 'components/common/message/helpers';
32+
import useMessageFavoriteFieldsMutation from 'components/common/message/details/fields/hooks/useMessageFavoriteFieldsMutation';
3433

3534
type OriginalProps = React.PropsWithChildren<{
3635
message: Message;
@@ -51,18 +50,28 @@ const OriginalMessageFavoriteFieldsProvider = ({ children = null, message, messa
5150
return messageStreamIds.map((id) => streamsById?.[id]).filter((s) => !!s);
5251
}, [message?.fields?.streams, permissions, streamsList]);
5352

53+
const initialFavoriteFieldsByStream = useMemo(
54+
() => Object.fromEntries(streams.map((stream) => [stream.id, getStreamFavoriteFields(stream, message?.fields)])),
55+
[message?.fields, streams],
56+
);
57+
5458
const initialFavoriteFields = useMemo(
55-
() => uniq(flattenDeep(zip(streams.map((stream) => stream?.favorite_fields ?? DEFAULT_FIELDS)))),
56-
[streams],
59+
() => uniq(flattenDeep(zip(Object.values(initialFavoriteFieldsByStream)))),
60+
[initialFavoriteFieldsByStream],
5761
);
5862

5963
const editableStreams = useMemo(
60-
() => streams.filter((stream: Stream) => isPermitted(permissions, `streams:edit:${stream.id}`)),
64+
() => streams.filter((stream) => isPermitted(permissions, `streams:edit:${stream.id}`)),
6165
[permissions, streams],
6266
);
6367

68+
const editableStreamsInitialFavoriteFields = useMemo(
69+
() => Object.fromEntries(editableStreams.map(({ id }) => [id, initialFavoriteFieldsByStream[id]])),
70+
[editableStreams, initialFavoriteFieldsByStream],
71+
);
72+
6473
const { saveFavoriteField, toggleField, setFieldsIsPending } = useMessageFavoriteFieldsMutation(
65-
editableStreams,
74+
editableStreamsInitialFavoriteFields,
6675
initialFavoriteFields,
6776
);
6877

@@ -75,15 +84,17 @@ const OriginalMessageFavoriteFieldsProvider = ({ children = null, message, messa
7584
toggleField,
7685
editableStreams,
7786
setFieldsIsPending,
87+
initialFavoriteFieldsByStream,
7888
}),
7989
[
8090
initialFavoriteFields,
8191
saveFavoriteField,
8292
messageFields,
8393
message,
8494
toggleField,
85-
editableStreams,
8695
setFieldsIsPending,
96+
initialFavoriteFieldsByStream,
97+
editableStreams,
8798
],
8899
);
89100

graylog2-web-interface/src/components/common/message/details/fields/MessageFieldsEditModal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ import { StreamsStore } from 'views/stores/StreamsStore';
2525
import MessageFavoriteFieldsContext from 'views/components/contexts/MessageFavoriteFieldsContext';
2626
import StringUtils from 'util/StringUtils';
2727
import { ModalSubmit } from 'components/common';
28+
import { DEFAULT_FIELDS } from 'components/common/message/helpers';
2829

29-
import useMessageFavoriteFieldsForEditing, { DEFAULT_FIELDS } from './hooks/useMessageFavoriteFieldsForEditing';
30+
import useMessageFavoriteFieldsForEditing from './hooks/useMessageFavoriteFieldsForEditing';
3031
import MessageFieldsEditModeLists from './MessageFieldsEditModeLists';
3132
import useSendFavoriteFieldTelemetry from './hooks/useSendFavoriteFieldTelemetry';
3233

graylog2-web-interface/src/components/common/message/details/fields/hooks/useMessageFavoriteFieldsForEditing.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ const createWrapper =
4747
message: undefined,
4848
editableStreams: [],
4949
setFieldsIsPending: false,
50+
initialFavoriteFieldsByStream: {
51+
streamId: initialFavorites,
52+
},
5053
}}>
5154
{children}
5255
</MessageFavoriteFieldsContext.Provider>

graylog2-web-interface/src/components/common/message/details/fields/hooks/useMessageFavoriteFieldsForEditing.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ import { useState, useCallback, useContext } from 'react';
1818
import uniq from 'lodash/uniq';
1919

2020
import MessageFavoriteFieldsContext from 'views/components/contexts/MessageFavoriteFieldsContext';
21+
import type { FormattedField } from 'components/common/message/details/fields/types';
22+
import { DEFAULT_FIELDS } from 'components/common/message/helpers';
2123

2224
import useSendFavoriteFieldTelemetry from './useSendFavoriteFieldTelemetry';
2325

24-
import type { FormattedField } from '../types';
25-
26-
export const DEFAULT_FIELDS = ['source', 'destination_ip', 'usernames'];
27-
2826
const useMessageFavoriteFieldsForEditing = () => {
2927
const sendFavoriteFieldTelemetry = useSendFavoriteFieldTelemetry();
3028
const { saveFavoriteField, favoriteFields: initialFavoriteFields } = useContext(MessageFavoriteFieldsContext);

graylog2-web-interface/src/components/common/message/details/fields/hooks/useMessageFavoriteFieldsMutation.test.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,14 @@ const queryClient = new QueryClient({
6262
const wrapper = ({ children }) => <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
6363

6464
const renderTestHook = (streams: Array<Stream>, initialFavoriteFields: Array<string>) =>
65-
renderHook(() => useMessageFavoriteFieldsMutation(streams, initialFavoriteFields), { wrapper });
65+
renderHook(
66+
() =>
67+
useMessageFavoriteFieldsMutation(
68+
Object.fromEntries(streams.map((stream) => [stream.id, stream.favorite_fields])),
69+
initialFavoriteFields,
70+
),
71+
{ wrapper },
72+
);
6673
describe('useMessageFavoriteFieldsMutation', () => {
6774
const streams: Array<Stream> = [
6875
{

graylog2-web-interface/src/components/common/message/details/fields/hooks/useMessageFavoriteFieldsMutation.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@
1616
*/
1717
import { useCallback } from 'react';
1818
import { useMutation } from '@tanstack/react-query';
19+
import mapValues from 'lodash/mapValues';
1920

2021
import { FavoriteFields } from '@graylog/server-api';
2122

2223
import { StreamsActions } from 'views/stores/StreamsStore';
2324
import UserNotification from 'util/UserNotification';
24-
import type { Stream } from 'logic/streams/types';
25-
26-
import useSendFavoriteFieldTelemetry from './useSendFavoriteFieldTelemetry';
25+
import useSendFavoriteFieldTelemetry from 'components/common/message/details/fields/hooks/useSendFavoriteFieldTelemetry';
2726

2827
interface FavoriteFieldRequest {
2928
readonly field: string;
@@ -36,7 +35,10 @@ interface SetFavoriteFieldsRequest {
3635
};
3736
}
3837

39-
const useMessageFavoriteFieldsMutation = (streams: Array<Stream>, initialFavoriteFields: Array<string>) => {
38+
const useMessageFavoriteFieldsMutation = (
39+
initialFavoriteFieldsByStream: Record<string, Array<string>>,
40+
initialFavoriteFields: Array<string>,
41+
) => {
4042
const sendFavoriteFieldTelemetry = useSendFavoriteFieldTelemetry();
4143
const { isPending: setFieldsIsPending, mutate: setFavoriteFields } = useMutation({
4244
mutationFn: (props: SetFavoriteFieldsRequest) => FavoriteFields.set(props),
@@ -90,34 +92,27 @@ const useMessageFavoriteFieldsMutation = (streams: Array<Stream>, initialFavorit
9092
(favoritesToSave: Array<string>) => {
9193
const newAddedFields = favoritesToSave.filter((f) => !initialFavoriteFields.includes(f));
9294

93-
const newFavoriteFieldsByStream = Object.fromEntries(
94-
streams.map((stream) => [
95-
stream.id,
96-
favoritesToSave.filter((f) => {
97-
const streamFavoriteFields = stream?.favorite_fields ?? [];
98-
99-
return streamFavoriteFields.includes(f) || newAddedFields.includes(f);
100-
}),
101-
]),
95+
const newFavoriteFieldsByStream = mapValues(initialFavoriteFieldsByStream, (streamFavoriteFields) =>
96+
favoritesToSave.filter((f) => streamFavoriteFields.includes(f) || newAddedFields.includes(f)),
10297
);
10398

10499
setFavoriteFields({ fields: newFavoriteFieldsByStream });
105100
},
106-
[initialFavoriteFields, setFavoriteFields, streams],
101+
[initialFavoriteFields, initialFavoriteFieldsByStream, setFavoriteFields],
107102
);
108103

109104
const toggleField = useCallback(
110105
(field: string) => {
111106
const isFavorite = initialFavoriteFields?.includes(field);
112-
const streamIds = streams.map((stream) => stream.id);
107+
const streamIds = Object.keys(initialFavoriteFieldsByStream);
113108

114109
if (isFavorite) {
115110
removeFavoriteField({ field, stream_ids: streamIds });
116111
} else {
117112
addFavoriteField({ field, stream_ids: streamIds });
118113
}
119114
},
120-
[addFavoriteField, initialFavoriteFields, removeFavoriteField, streams],
115+
[addFavoriteField, initialFavoriteFields, initialFavoriteFieldsByStream, removeFavoriteField],
121116
);
122117

123118
return {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (C) 2020 Graylog, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the Server Side Public License, version 1,
6+
* as published by MongoDB, Inc.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* Server Side Public License for more details.
12+
*
13+
* You should have received a copy of the Server Side Public License
14+
* along with this program. If not, see
15+
* <http://www.mongodb.com/licensing/server-side-public-license>.
16+
*/
17+
import type { Stream } from 'logic/streams/types';
18+
import type { Message } from 'views/components/messagelist/Types';
19+
20+
export const DEFAULT_FIELDS = ['source', 'destination_ip', 'usernames'];
21+
22+
export const getStreamFavoriteFields = (stream: Stream, fields: Message['fields'] = {}) =>
23+
stream?.favorite_fields ?? DEFAULT_FIELDS.filter((field) => Object.hasOwn(fields, field));

graylog2-web-interface/src/views/components/contexts/MessageFavoriteFieldsContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type MessageFavoriteFieldsContextState = {
3131
message: Message;
3232
editableStreams: Array<Stream>;
3333
setFieldsIsPending: boolean;
34+
initialFavoriteFieldsByStream: Record<string, Array<string>>;
3435
};
3536

3637
const MessageFavoriteFieldsContext = React.createContext<MessageFavoriteFieldsContextState>({
@@ -41,6 +42,7 @@ const MessageFavoriteFieldsContext = React.createContext<MessageFavoriteFieldsCo
4142
message: undefined,
4243
editableStreams: [],
4344
setFieldsIsPending: false,
45+
initialFavoriteFieldsByStream: {},
4446
});
4547

4648
export default singleton('contexts.MessageFavoriteFieldsContext', () => MessageFavoriteFieldsContext);

0 commit comments

Comments
 (0)