mattermost-redux 11.2.0 → 11.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/action_types/posts.d.ts +3 -0
- package/lib/action_types/posts.js +3 -0
- package/lib/actions/access_control.d.ts +2 -1
- package/lib/actions/access_control.js +7 -0
- package/lib/actions/teams.d.ts +1 -1
- package/lib/actions/teams.js +2 -1
- package/lib/constants/posts.d.ts +19 -0
- package/lib/constants/posts.js +18 -0
- package/lib/constants/preferences.d.ts +2 -0
- package/lib/constants/preferences.js +2 -0
- package/lib/constants/websocket.d.ts +3 -0
- package/lib/constants/websocket.js +3 -0
- package/lib/reducers/entities/posts.js +84 -4
- package/lib/selectors/entities/channel_banner.d.ts +0 -1
- package/lib/selectors/entities/channel_banner.js +1 -11
- package/lib/selectors/entities/posts.js +9 -2
- package/lib/utils/post_list.js +10 -0
- package/lib/utils/post_utils.js +3 -0
- package/package.json +3 -3
|
@@ -41,5 +41,8 @@ declare const _default: {
|
|
|
41
41
|
DELETE_ACK_POST_SUCCESS: "DELETE_ACK_POST_SUCCESS";
|
|
42
42
|
MOVE_POST_SUCCESS: "MOVE_POST_SUCCESS";
|
|
43
43
|
MOVE_POST_FAILURE: "MOVE_POST_FAILURE";
|
|
44
|
+
REVEAL_BURN_ON_READ_SUCCESS: "REVEAL_BURN_ON_READ_SUCCESS";
|
|
45
|
+
POST_RECIPIENTS_UPDATED: "POST_RECIPIENTS_UPDATED";
|
|
46
|
+
BURN_ON_READ_ALL_REVEALED: "BURN_ON_READ_ALL_REVEALED";
|
|
44
47
|
};
|
|
45
48
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AccessControlPoliciesResult, AccessControlPolicy, AccessControlTestResult } from '@mattermost/types/access_control';
|
|
1
|
+
import type { AccessControlPoliciesResult, AccessControlPolicy, AccessControlPolicyActiveUpdate, AccessControlTestResult } from '@mattermost/types/access_control';
|
|
2
2
|
import type { ChannelSearchOpts, ChannelsWithTotalCount } from '@mattermost/types/channels';
|
|
3
3
|
import type { ActionFuncAsync } from 'mattermost-redux/types/actions';
|
|
4
4
|
export declare function getAccessControlPolicy(id: string, channelId?: string): ActionFuncAsync<AccessControlPolicy, import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
|
|
@@ -18,3 +18,4 @@ export declare function validateExpressionAgainstRequester(expression: string, c
|
|
|
18
18
|
export declare function createAccessControlSyncJob(jobData: {
|
|
19
19
|
policy_id: string;
|
|
20
20
|
}): ActionFuncAsync<any>;
|
|
21
|
+
export declare function updateAccessControlPoliciesActive(states: AccessControlPolicyActiveUpdate[]): ActionFuncAsync<AccessControlPolicy[], import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
|
|
@@ -15,6 +15,7 @@ exports.searchUsersForExpression = searchUsersForExpression;
|
|
|
15
15
|
exports.getVisualAST = getVisualAST;
|
|
16
16
|
exports.validateExpressionAgainstRequester = validateExpressionAgainstRequester;
|
|
17
17
|
exports.createAccessControlSyncJob = createAccessControlSyncJob;
|
|
18
|
+
exports.updateAccessControlPoliciesActive = updateAccessControlPoliciesActive;
|
|
18
19
|
const redux_batched_actions_1 = require("redux-batched-actions");
|
|
19
20
|
const action_types_1 = require("mattermost-redux/action_types");
|
|
20
21
|
const client_1 = require("mattermost-redux/client");
|
|
@@ -170,3 +171,9 @@ function createAccessControlSyncJob(jobData) {
|
|
|
170
171
|
return { data };
|
|
171
172
|
};
|
|
172
173
|
}
|
|
174
|
+
function updateAccessControlPoliciesActive(states) {
|
|
175
|
+
return (0, helpers_1.bindClientFunc)({
|
|
176
|
+
clientFunc: client_1.Client4.updateAccessControlPoliciesActive,
|
|
177
|
+
params: [states],
|
|
178
|
+
});
|
|
179
|
+
}
|
package/lib/actions/teams.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare function removeUserFromTeam(teamId: string, userId: string): Acti
|
|
|
41
41
|
export declare function sendEmailInvitesToTeam(teamId: string, emails: string[]): ActionFuncAsync<import("@mattermost/types/client4").StatusOK, import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
42
42
|
export declare function sendEmailGuestInvitesToChannels(teamId: string, channelIds: string[], emails: string[], message: string): ActionFuncAsync<import("@mattermost/types/client4").StatusOK, import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
43
43
|
export declare function sendEmailInvitesToTeamGracefully(teamId: string, emails: string[]): ActionFuncAsync<import("@mattermost/types/teams").TeamInviteWithError[], import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
44
|
-
export declare function sendEmailGuestInvitesToChannelsGracefully(teamId: string, channelIds: string[], emails: string[], message: string): ActionFuncAsync<import("@mattermost/types/teams").TeamInviteWithError[], import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
44
|
+
export declare function sendEmailGuestInvitesToChannelsGracefully(teamId: string, channelIds: string[], emails: string[], message: string, guestMagicLink?: boolean): ActionFuncAsync<import("@mattermost/types/teams").TeamInviteWithError[], import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
45
45
|
export declare function sendEmailInvitesToTeamAndChannelsGracefully(teamId: string, channelIds: string[], emails: string[], message: string): ActionFuncAsync<import("@mattermost/types/teams").TeamInviteWithError[], import("@mattermost/types/store").GlobalState, AnyAction>;
|
|
46
46
|
export declare function getTeamInviteInfo(inviteId: string): ActionFuncAsync<{
|
|
47
47
|
display_name: string;
|
package/lib/actions/teams.js
CHANGED
|
@@ -544,7 +544,7 @@ function sendEmailInvitesToTeamGracefully(teamId, emails) {
|
|
|
544
544
|
],
|
|
545
545
|
});
|
|
546
546
|
}
|
|
547
|
-
function sendEmailGuestInvitesToChannelsGracefully(teamId, channelIds, emails, message) {
|
|
547
|
+
function sendEmailGuestInvitesToChannelsGracefully(teamId, channelIds, emails, message, guestMagicLink = false) {
|
|
548
548
|
return (0, helpers_1.bindClientFunc)({
|
|
549
549
|
clientFunc: client_1.Client4.sendEmailGuestInvitesToChannelsGracefully,
|
|
550
550
|
params: [
|
|
@@ -552,6 +552,7 @@ function sendEmailGuestInvitesToChannelsGracefully(teamId, channelIds, emails, m
|
|
|
552
552
|
channelIds,
|
|
553
553
|
emails,
|
|
554
554
|
message,
|
|
555
|
+
guestMagicLink,
|
|
555
556
|
],
|
|
556
557
|
});
|
|
557
558
|
}
|
package/lib/constants/posts.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export declare const PostTypes: {
|
|
|
27
27
|
REMINDER: PostType;
|
|
28
28
|
WRANGLER: PostType;
|
|
29
29
|
GM_CONVERTED_TO_CHANNEL: PostType;
|
|
30
|
+
BURN_ON_READ: PostType;
|
|
30
31
|
};
|
|
31
32
|
declare const _default: {
|
|
32
33
|
POST_CHUNK_SIZE: number;
|
|
@@ -61,6 +62,7 @@ declare const _default: {
|
|
|
61
62
|
REMINDER: PostType;
|
|
62
63
|
WRANGLER: PostType;
|
|
63
64
|
GM_CONVERTED_TO_CHANNEL: PostType;
|
|
65
|
+
BURN_ON_READ: PostType;
|
|
64
66
|
};
|
|
65
67
|
MESSAGE_TYPES: {
|
|
66
68
|
POST: string;
|
|
@@ -70,5 +72,22 @@ declare const _default: {
|
|
|
70
72
|
POST_COLLAPSE_TIMEOUT: number;
|
|
71
73
|
IGNORE_POST_TYPES: PostType[];
|
|
72
74
|
USER_ACTIVITY_POST_TYPES: PostType[];
|
|
75
|
+
BURN_ON_READ: {
|
|
76
|
+
DURATION_1_MINUTE: number;
|
|
77
|
+
DURATION_5_MINUTES: number;
|
|
78
|
+
DURATION_10_MINUTES: number;
|
|
79
|
+
DURATION_30_MINUTES: number;
|
|
80
|
+
DURATION_1_HOUR: number;
|
|
81
|
+
DURATION_8_HOURS: number;
|
|
82
|
+
DURATION_DEFAULT: number;
|
|
83
|
+
MAX_TTL_2_MINUTES: number;
|
|
84
|
+
MAX_TTL_5_MINUTES: number;
|
|
85
|
+
MAX_TTL_1_DAY: number;
|
|
86
|
+
MAX_TTL_3_DAYS: number;
|
|
87
|
+
MAX_TTL_7_DAYS: number;
|
|
88
|
+
MAX_TTL_14_DAYS: number;
|
|
89
|
+
MAX_TTL_30_DAYS: number;
|
|
90
|
+
MAX_TTL_DEFAULT: number;
|
|
91
|
+
};
|
|
73
92
|
};
|
|
74
93
|
export default _default;
|
package/lib/constants/posts.js
CHANGED
|
@@ -31,6 +31,7 @@ exports.PostTypes = {
|
|
|
31
31
|
REMINDER: 'reminder',
|
|
32
32
|
WRANGLER: 'system_wrangler',
|
|
33
33
|
GM_CONVERTED_TO_CHANNEL: 'system_gm_to_channel',
|
|
34
|
+
BURN_ON_READ: 'burn_on_read',
|
|
34
35
|
};
|
|
35
36
|
exports.default = {
|
|
36
37
|
POST_CHUNK_SIZE: 60,
|
|
@@ -68,4 +69,21 @@ exports.default = {
|
|
|
68
69
|
exports.PostTypes.LEAVE_TEAM,
|
|
69
70
|
exports.PostTypes.REMOVE_FROM_TEAM,
|
|
70
71
|
],
|
|
72
|
+
BURN_ON_READ: {
|
|
73
|
+
DURATION_1_MINUTE: 60,
|
|
74
|
+
DURATION_5_MINUTES: 300,
|
|
75
|
+
DURATION_10_MINUTES: 600,
|
|
76
|
+
DURATION_30_MINUTES: 1800,
|
|
77
|
+
DURATION_1_HOUR: 3600,
|
|
78
|
+
DURATION_8_HOURS: 28800,
|
|
79
|
+
DURATION_DEFAULT: 600,
|
|
80
|
+
MAX_TTL_2_MINUTES: 120,
|
|
81
|
+
MAX_TTL_5_MINUTES: 300,
|
|
82
|
+
MAX_TTL_1_DAY: 86400,
|
|
83
|
+
MAX_TTL_3_DAYS: 259200,
|
|
84
|
+
MAX_TTL_7_DAYS: 604800,
|
|
85
|
+
MAX_TTL_14_DAYS: 1209600,
|
|
86
|
+
MAX_TTL_30_DAYS: 2592000,
|
|
87
|
+
MAX_TTL_DEFAULT: 604800,
|
|
88
|
+
},
|
|
71
89
|
};
|
|
@@ -62,6 +62,8 @@ declare const Preferences: {
|
|
|
62
62
|
HIDE_MYSQL_STATS_NOTIFICATION: string;
|
|
63
63
|
CATEGORY_OVERAGE_USERS_BANNER: string;
|
|
64
64
|
CATEGORY_POST_HISTORY_LIMIT_BANNER: string;
|
|
65
|
+
CATEGORY_BURN_ON_READ: string;
|
|
66
|
+
BURN_ON_READ_SKIP_CONFIRMATION: string;
|
|
65
67
|
CATEGORY_THEME: string;
|
|
66
68
|
THEMES: Record<ThemeKey, Theme>;
|
|
67
69
|
RECENT_EMOJIS: string;
|
|
@@ -66,6 +66,8 @@ const Preferences = {
|
|
|
66
66
|
HIDE_MYSQL_STATS_NOTIFICATION: 'hide_mysql_stats_notifcation',
|
|
67
67
|
CATEGORY_OVERAGE_USERS_BANNER: 'overage_users_banner',
|
|
68
68
|
CATEGORY_POST_HISTORY_LIMIT_BANNER: 'post_history_limit_banner',
|
|
69
|
+
CATEGORY_BURN_ON_READ: 'burn_on_read',
|
|
70
|
+
BURN_ON_READ_SKIP_CONFIRMATION: 'skip_delete_confirmation',
|
|
69
71
|
CATEGORY_THEME: 'theme',
|
|
70
72
|
THEMES: {
|
|
71
73
|
denim: {
|
|
@@ -49,5 +49,8 @@ declare const WebsocketEvents: {
|
|
|
49
49
|
THREAD_READ_CHANGED: string;
|
|
50
50
|
FIRST_ADMIN_VISIT_MARKETPLACE_STATUS_RECEIVED: string;
|
|
51
51
|
GROUP_MEMBER_DELETED: string;
|
|
52
|
+
BURN_ON_READ_POST_REVEALED: string;
|
|
53
|
+
BURN_ON_READ_POST_BURNED: string;
|
|
54
|
+
BURN_ON_READ_ALL_REVEALED: string;
|
|
52
55
|
};
|
|
53
56
|
export default WebsocketEvents;
|
|
@@ -53,5 +53,8 @@ const WebsocketEvents = {
|
|
|
53
53
|
THREAD_READ_CHANGED: 'thread_read_changed',
|
|
54
54
|
FIRST_ADMIN_VISIT_MARKETPLACE_STATUS_RECEIVED: 'first_admin_visit_marketplace_status_received',
|
|
55
55
|
GROUP_MEMBER_DELETED: 'group_member_deleted',
|
|
56
|
+
BURN_ON_READ_POST_REVEALED: 'post_revealed',
|
|
57
|
+
BURN_ON_READ_POST_BURNED: 'post_burned',
|
|
58
|
+
BURN_ON_READ_ALL_REVEALED: 'burn_on_read_all_revealed',
|
|
56
59
|
};
|
|
57
60
|
exports.default = WebsocketEvents;
|
|
@@ -20,6 +20,7 @@ exports.limitedViews = limitedViews;
|
|
|
20
20
|
exports.default = reducer;
|
|
21
21
|
const action_types_1 = require("mattermost-redux/action_types");
|
|
22
22
|
const constants_1 = require("mattermost-redux/constants");
|
|
23
|
+
const posts_1 = require("mattermost-redux/constants/posts");
|
|
23
24
|
const post_utils_1 = require("mattermost-redux/utils/post_utils");
|
|
24
25
|
function removeUnneededMetadata(post) {
|
|
25
26
|
if (!post.metadata) {
|
|
@@ -151,6 +152,11 @@ function handlePosts(state = {}, action) {
|
|
|
151
152
|
if (!state[post.id]) {
|
|
152
153
|
return state;
|
|
153
154
|
}
|
|
155
|
+
if (state[post.id].type === posts_1.PostTypes.BURN_ON_READ) {
|
|
156
|
+
const nextState = { ...state };
|
|
157
|
+
Reflect.deleteProperty(nextState, post.id);
|
|
158
|
+
return nextState;
|
|
159
|
+
}
|
|
154
160
|
// Mark the post as deleted
|
|
155
161
|
const nextState = {
|
|
156
162
|
...state,
|
|
@@ -229,6 +235,68 @@ function handlePosts(state = {}, action) {
|
|
|
229
235
|
},
|
|
230
236
|
};
|
|
231
237
|
}
|
|
238
|
+
case action_types_1.PostTypes.REVEAL_BURN_ON_READ_SUCCESS: {
|
|
239
|
+
const { post, expireAt } = action.data;
|
|
240
|
+
if (!state[post.id]) {
|
|
241
|
+
return state;
|
|
242
|
+
}
|
|
243
|
+
const currentPost = state[post.id];
|
|
244
|
+
const currentMetadata = currentPost.metadata || {};
|
|
245
|
+
const newMetadata = post.metadata || {};
|
|
246
|
+
return {
|
|
247
|
+
...state,
|
|
248
|
+
[post.id]: {
|
|
249
|
+
...currentPost,
|
|
250
|
+
...post,
|
|
251
|
+
metadata: {
|
|
252
|
+
...currentMetadata,
|
|
253
|
+
...newMetadata,
|
|
254
|
+
expire_at: expireAt,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
case action_types_1.PostTypes.POST_RECIPIENTS_UPDATED: {
|
|
260
|
+
const { postId, recipients } = action.data;
|
|
261
|
+
if (!state[postId]) {
|
|
262
|
+
return state;
|
|
263
|
+
}
|
|
264
|
+
const currentPost = state[postId];
|
|
265
|
+
const currentMetadata = currentPost.metadata || {};
|
|
266
|
+
const currentRecipients = currentMetadata.recipients || [];
|
|
267
|
+
// Merge new recipients with existing ones (don't replace).
|
|
268
|
+
// Server sends incremental updates (only the revealing user), so we must merge.
|
|
269
|
+
const mergedRecipients = [...new Set([...currentRecipients, ...recipients])];
|
|
270
|
+
return {
|
|
271
|
+
...state,
|
|
272
|
+
[postId]: {
|
|
273
|
+
...currentPost,
|
|
274
|
+
metadata: {
|
|
275
|
+
...currentMetadata,
|
|
276
|
+
recipients: mergedRecipients,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
case action_types_1.PostTypes.BURN_ON_READ_ALL_REVEALED: {
|
|
282
|
+
const { postId, senderExpireAt } = action.data;
|
|
283
|
+
if (!state[postId]) {
|
|
284
|
+
return state;
|
|
285
|
+
}
|
|
286
|
+
const currentPost = state[postId];
|
|
287
|
+
const currentMetadata = currentPost.metadata || {};
|
|
288
|
+
// Set sender's expiration time to trigger timer display
|
|
289
|
+
return {
|
|
290
|
+
...state,
|
|
291
|
+
[postId]: {
|
|
292
|
+
...currentPost,
|
|
293
|
+
metadata: {
|
|
294
|
+
...currentMetadata,
|
|
295
|
+
expire_at: senderExpireAt,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
232
300
|
case action_types_1.ChannelTypes.LEAVE_CHANNEL: {
|
|
233
301
|
const channelId = action.data.id;
|
|
234
302
|
let postDeleted = false;
|
|
@@ -605,17 +673,24 @@ function postsInChannel(state = {}, action, prevPosts, nextPosts) {
|
|
|
605
673
|
}
|
|
606
674
|
case action_types_1.PostTypes.POST_DELETED: {
|
|
607
675
|
const post = action.data;
|
|
608
|
-
// Deleting a post removes its comments from the order, but does not remove the post itself
|
|
609
676
|
const postsForChannel = state[post.channel_id] || [];
|
|
610
677
|
if (postsForChannel.length === 0) {
|
|
611
678
|
return state;
|
|
612
679
|
}
|
|
613
680
|
let changed = false;
|
|
614
681
|
let nextPostsForChannel = [...postsForChannel];
|
|
682
|
+
const isBoRPost = prevPosts[post.id]?.type === posts_1.PostTypes.BURN_ON_READ;
|
|
683
|
+
const shouldRemovePost = (postId) => {
|
|
684
|
+
const isTheDeletedPost = postId === post.id;
|
|
685
|
+
const isReplyToDeletedPost = prevPosts[postId]?.root_id === post.id;
|
|
686
|
+
if (isBoRPost) {
|
|
687
|
+
return isTheDeletedPost;
|
|
688
|
+
}
|
|
689
|
+
return isReplyToDeletedPost;
|
|
690
|
+
};
|
|
615
691
|
for (let i = 0; i < nextPostsForChannel.length; i++) {
|
|
616
692
|
const block = nextPostsForChannel[i];
|
|
617
|
-
|
|
618
|
-
const nextOrder = block.order.filter((postId) => prevPosts[postId].root_id !== post.id);
|
|
693
|
+
const nextOrder = block.order.filter((postId) => !shouldRemovePost(postId));
|
|
619
694
|
if (nextOrder.length !== block.order.length) {
|
|
620
695
|
nextPostsForChannel[i] = {
|
|
621
696
|
...block,
|
|
@@ -642,11 +717,16 @@ function postsInChannel(state = {}, action, prevPosts, nextPosts) {
|
|
|
642
717
|
return state;
|
|
643
718
|
}
|
|
644
719
|
let changed = false;
|
|
720
|
+
const isBoRPost = prevPosts[post.id]?.type === posts_1.PostTypes.BURN_ON_READ;
|
|
645
721
|
// Remove the post and its comments from the channel
|
|
646
722
|
let nextPostsForChannel = [...postsForChannel];
|
|
647
723
|
for (let i = 0; i < nextPostsForChannel.length; i++) {
|
|
648
724
|
const block = nextPostsForChannel[i];
|
|
649
|
-
|
|
725
|
+
// For BoR posts: only remove the post itself (BoR doesn't support threads)
|
|
726
|
+
// For regular posts: remove the post and its thread replies
|
|
727
|
+
const nextOrder = isBoRPost ?
|
|
728
|
+
block.order.filter((postId) => postId !== post.id) :
|
|
729
|
+
block.order.filter((postId) => postId !== post.id && prevPosts[postId]?.root_id !== post.id);
|
|
650
730
|
if (nextOrder.length !== block.order.length) {
|
|
651
731
|
nextPostsForChannel[i] = {
|
|
652
732
|
...block,
|
|
@@ -2,21 +2,11 @@
|
|
|
2
2
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.selectShowChannelBanner =
|
|
5
|
+
exports.selectShowChannelBanner = void 0;
|
|
6
6
|
const channels_1 = require("@mattermost/types/channels");
|
|
7
7
|
const constants_1 = require("mattermost-redux/constants");
|
|
8
8
|
const channels_2 = require("mattermost-redux/selectors/entities/channels");
|
|
9
|
-
const general_1 = require("mattermost-redux/selectors/entities/general");
|
|
10
|
-
const selectChannelBannerEnabled = (state) => {
|
|
11
|
-
const license = (0, general_1.getLicense)(state);
|
|
12
|
-
return license?.SkuShortName === constants_1.General.SKUEnterpriseAdvanced;
|
|
13
|
-
};
|
|
14
|
-
exports.selectChannelBannerEnabled = selectChannelBannerEnabled;
|
|
15
9
|
const selectShowChannelBanner = (state, channelId) => {
|
|
16
|
-
const enabled = (0, exports.selectChannelBannerEnabled)(state);
|
|
17
|
-
if (!enabled) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
10
|
const channelBannerInfo = (0, channels_2.getChannelBanner)(state, channelId);
|
|
21
11
|
const channel = (0, channels_2.getChannel)(state, channelId);
|
|
22
12
|
const isValidChannelType = Boolean(channel && (channel.type === constants_1.General.OPEN_CHANNEL || channel.type === constants_1.General.PRIVATE_CHANNEL));
|
|
@@ -132,7 +132,8 @@ function isPostInteractable(post) {
|
|
|
132
132
|
!(0, post_utils_1.isPostEphemeral)(post) &&
|
|
133
133
|
!(0, post_utils_1.isSystemMessage)(post) &&
|
|
134
134
|
!(0, post_utils_1.isPostPendingOrFailed)(post) &&
|
|
135
|
-
post.state !== constants_1.Posts.POST_DELETED
|
|
135
|
+
post.state !== constants_1.Posts.POST_DELETED &&
|
|
136
|
+
post.type !== constants_1.Posts.POST_TYPES.BURN_ON_READ;
|
|
136
137
|
}
|
|
137
138
|
function getLatestInteractablePostId(state, channelId, rootId = '') {
|
|
138
139
|
const postsIds = rootId ? getPostsInThreadOrdered(state, rootId) : getPostIdsInChannel(state, channelId);
|
|
@@ -398,7 +399,13 @@ function getUnreadPostsChunk(state, channelId, timeStamp) {
|
|
|
398
399
|
return oldestPostsChunk;
|
|
399
400
|
}
|
|
400
401
|
}
|
|
401
|
-
|
|
402
|
+
// Try to find a chunk where lastViewedAt falls within the post range
|
|
403
|
+
const chunkAroundTime = getPostsChunkInChannelAroundTime(state, channelId, timeStamp);
|
|
404
|
+
if (chunkAroundTime) {
|
|
405
|
+
return chunkAroundTime;
|
|
406
|
+
}
|
|
407
|
+
// All fetched posts are newer than lastViewedAt. Return the recent chunk.
|
|
408
|
+
return recentChunk;
|
|
402
409
|
}
|
|
403
410
|
const isPostsChunkIncludingUnreadsPosts = (state, chunk, timeStamp) => {
|
|
404
411
|
const postsEntity = state.entities.posts;
|
package/lib/utils/post_list.js
CHANGED
|
@@ -73,6 +73,16 @@ function makeFilterPostsAndAddSeparators() {
|
|
|
73
73
|
if ((0, post_utils_1.shouldFilterJoinLeavePost)(post, showJoinLeave, currentUser.username)) {
|
|
74
74
|
continue;
|
|
75
75
|
}
|
|
76
|
+
// Filter out expired burn-on-read posts
|
|
77
|
+
// Note: BoR posts should display regardless of feature flag being enabled/disabled
|
|
78
|
+
// The feature flag only controls creation of NEW BoR messages, not display of existing ones
|
|
79
|
+
if (post.type === constants_1.Posts.POST_TYPES.BURN_ON_READ) {
|
|
80
|
+
// Skip if already expired and deleted
|
|
81
|
+
const expireAt = post.metadata?.expire_at;
|
|
82
|
+
if (expireAt && typeof expireAt === 'number' && expireAt <= Date.now()) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
76
86
|
lastDate = pushPostDateIfNeeded(post, currentUser, out, lastDate);
|
|
77
87
|
if (lastViewedAt &&
|
|
78
88
|
post.create_at > lastViewedAt &&
|
package/lib/utils/post_utils.js
CHANGED
|
@@ -62,6 +62,9 @@ function canEditPost(state, config, license, teamId, channelId, userId, post) {
|
|
|
62
62
|
if (!post || isSystemMessage(post)) {
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
65
|
+
if (post.type === constants_1.Posts.POST_TYPES.BURN_ON_READ) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
65
68
|
const isOwner = isPostOwner(userId, post);
|
|
66
69
|
let canEdit = true;
|
|
67
70
|
const permission = isOwner ? constants_1.Permissions.EDIT_POST : constants_1.Permissions.EDIT_OTHERS_POSTS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mattermost-redux",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.0",
|
|
4
4
|
"description": "Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mattermost"
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"directory": "webapp/platform/mattermost-redux"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@mattermost/client": "11.
|
|
43
|
-
"@mattermost/types": "11.
|
|
42
|
+
"@mattermost/client": "11.3.0",
|
|
43
|
+
"@mattermost/types": "11.3.0",
|
|
44
44
|
"@redux-devtools/extension": "3.3.0",
|
|
45
45
|
"lodash": "^4.17.21",
|
|
46
46
|
"moment-timezone": "^0.5.38",
|