mattermost-redux 11.2.0 → 11.4.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.
@@ -22,6 +22,7 @@ import PlaybookType from './playbooks';
22
22
  import PluginTypes from './plugins';
23
23
  import PostTypes from './posts';
24
24
  import PreferenceTypes from './preferences';
25
+ import RecapTypes from './recaps';
25
26
  import RoleTypes from './roles';
26
27
  import SchemeTypes from './schemes';
27
28
  import ScheduledPostTypes from './scheudled_posts';
@@ -30,7 +31,7 @@ import SharedChannelTypes from './shared_channels';
30
31
  import TeamTypes from './teams';
31
32
  import ThreadTypes from './threads';
32
33
  import UserTypes from './users';
33
- export { ErrorTypes, GeneralTypes, UserTypes, TeamTypes, ChannelTypes, PostTypes, FileTypes, PreferenceTypes, IntegrationTypes, EmojiTypes, AdminTypes, JobTypes, LimitsTypes, SearchTypes, RoleTypes, SchemeTypes, GroupTypes, BotTypes, PluginTypes, ChannelCategoryTypes, CloudTypes, AppsTypes, ThreadTypes, HostedCustomerTypes, DraftTypes, PlaybookType, ChannelBookmarkTypes, ScheduledPostTypes, SharedChannelTypes, ContentFlaggingTypes, AgentTypes, };
34
+ export { ErrorTypes, GeneralTypes, UserTypes, TeamTypes, ChannelTypes, PostTypes, FileTypes, PreferenceTypes, RecapTypes, IntegrationTypes, EmojiTypes, AdminTypes, JobTypes, LimitsTypes, SearchTypes, RoleTypes, SchemeTypes, GroupTypes, BotTypes, PluginTypes, ChannelCategoryTypes, CloudTypes, AppsTypes, ThreadTypes, HostedCustomerTypes, DraftTypes, PlaybookType, ChannelBookmarkTypes, ScheduledPostTypes, SharedChannelTypes, ContentFlaggingTypes, AgentTypes, };
34
35
  /**
35
36
  * An MMReduxAction is any non-Thunk Redux action accepted by mattermost-redux.
36
37
  */
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  return (mod && mod.__esModule) ? mod : { "default": mod };
6
6
  };
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.AgentTypes = exports.ContentFlaggingTypes = exports.SharedChannelTypes = exports.ScheduledPostTypes = exports.ChannelBookmarkTypes = exports.PlaybookType = exports.DraftTypes = exports.HostedCustomerTypes = exports.ThreadTypes = exports.AppsTypes = exports.CloudTypes = exports.ChannelCategoryTypes = exports.PluginTypes = exports.BotTypes = exports.GroupTypes = exports.SchemeTypes = exports.RoleTypes = exports.SearchTypes = exports.LimitsTypes = exports.JobTypes = exports.AdminTypes = exports.EmojiTypes = exports.IntegrationTypes = exports.PreferenceTypes = exports.FileTypes = exports.PostTypes = exports.ChannelTypes = exports.TeamTypes = exports.UserTypes = exports.GeneralTypes = exports.ErrorTypes = void 0;
8
+ exports.AgentTypes = exports.ContentFlaggingTypes = exports.SharedChannelTypes = exports.ScheduledPostTypes = exports.ChannelBookmarkTypes = exports.PlaybookType = exports.DraftTypes = exports.HostedCustomerTypes = exports.ThreadTypes = exports.AppsTypes = exports.CloudTypes = exports.ChannelCategoryTypes = exports.PluginTypes = exports.BotTypes = exports.GroupTypes = exports.SchemeTypes = exports.RoleTypes = exports.SearchTypes = exports.LimitsTypes = exports.JobTypes = exports.AdminTypes = exports.EmojiTypes = exports.IntegrationTypes = exports.RecapTypes = exports.PreferenceTypes = exports.FileTypes = exports.PostTypes = exports.ChannelTypes = exports.TeamTypes = exports.UserTypes = exports.GeneralTypes = exports.ErrorTypes = void 0;
9
9
  const admin_1 = __importDefault(require("./admin"));
10
10
  exports.AdminTypes = admin_1.default;
11
11
  const agents_1 = __importDefault(require("./agents"));
@@ -52,6 +52,8 @@ const posts_1 = __importDefault(require("./posts"));
52
52
  exports.PostTypes = posts_1.default;
53
53
  const preferences_1 = __importDefault(require("./preferences"));
54
54
  exports.PreferenceTypes = preferences_1.default;
55
+ const recaps_1 = __importDefault(require("./recaps"));
56
+ exports.RecapTypes = recaps_1.default;
55
57
  const roles_1 = __importDefault(require("./roles"));
56
58
  exports.RoleTypes = roles_1.default;
57
59
  const schemes_1 = __importDefault(require("./schemes"));
@@ -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;
@@ -49,4 +49,7 @@ exports.default = (0, key_mirror_1.default)({
49
49
  DELETE_ACK_POST_SUCCESS: null,
50
50
  MOVE_POST_SUCCESS: null,
51
51
  MOVE_POST_FAILURE: null,
52
+ REVEAL_BURN_ON_READ_SUCCESS: null,
53
+ POST_RECIPIENTS_UPDATED: null,
54
+ BURN_ON_READ_ALL_REVEALED: null,
52
55
  });
@@ -0,0 +1,23 @@
1
+ declare const _default: {
2
+ CREATE_RECAP_REQUEST: "CREATE_RECAP_REQUEST";
3
+ CREATE_RECAP_SUCCESS: "CREATE_RECAP_SUCCESS";
4
+ CREATE_RECAP_FAILURE: "CREATE_RECAP_FAILURE";
5
+ RECEIVED_RECAP: "RECEIVED_RECAP";
6
+ RECEIVED_RECAPS: "RECEIVED_RECAPS";
7
+ GET_RECAP_REQUEST: "GET_RECAP_REQUEST";
8
+ GET_RECAP_SUCCESS: "GET_RECAP_SUCCESS";
9
+ GET_RECAP_FAILURE: "GET_RECAP_FAILURE";
10
+ GET_RECAPS_REQUEST: "GET_RECAPS_REQUEST";
11
+ GET_RECAPS_SUCCESS: "GET_RECAPS_SUCCESS";
12
+ GET_RECAPS_FAILURE: "GET_RECAPS_FAILURE";
13
+ MARK_RECAP_READ_REQUEST: "MARK_RECAP_READ_REQUEST";
14
+ MARK_RECAP_READ_SUCCESS: "MARK_RECAP_READ_SUCCESS";
15
+ MARK_RECAP_READ_FAILURE: "MARK_RECAP_READ_FAILURE";
16
+ DELETE_RECAP_REQUEST: "DELETE_RECAP_REQUEST";
17
+ DELETE_RECAP_SUCCESS: "DELETE_RECAP_SUCCESS";
18
+ DELETE_RECAP_FAILURE: "DELETE_RECAP_FAILURE";
19
+ REGENERATE_RECAP_REQUEST: "REGENERATE_RECAP_REQUEST";
20
+ REGENERATE_RECAP_SUCCESS: "REGENERATE_RECAP_SUCCESS";
21
+ REGENERATE_RECAP_FAILURE: "REGENERATE_RECAP_FAILURE";
22
+ };
23
+ export default _default;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const key_mirror_1 = __importDefault(require("mattermost-redux/utils/key_mirror"));
9
+ exports.default = (0, key_mirror_1.default)({
10
+ CREATE_RECAP_REQUEST: null,
11
+ CREATE_RECAP_SUCCESS: null,
12
+ CREATE_RECAP_FAILURE: null,
13
+ RECEIVED_RECAP: null,
14
+ RECEIVED_RECAPS: null,
15
+ GET_RECAP_REQUEST: null,
16
+ GET_RECAP_SUCCESS: null,
17
+ GET_RECAP_FAILURE: null,
18
+ GET_RECAPS_REQUEST: null,
19
+ GET_RECAPS_SUCCESS: null,
20
+ GET_RECAPS_FAILURE: null,
21
+ MARK_RECAP_READ_REQUEST: null,
22
+ MARK_RECAP_READ_SUCCESS: null,
23
+ MARK_RECAP_READ_FAILURE: null,
24
+ DELETE_RECAP_REQUEST: null,
25
+ DELETE_RECAP_SUCCESS: null,
26
+ DELETE_RECAP_FAILURE: null,
27
+ REGENERATE_RECAP_REQUEST: null,
28
+ REGENERATE_RECAP_SUCCESS: null,
29
+ REGENERATE_RECAP_FAILURE: null,
30
+ });
@@ -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>;
@@ -9,7 +9,6 @@ export declare function searchAccessControlPolicyChannels(id: string, term: stri
9
9
  export declare function assignChannelsToAccessControlPolicy(policyId: string, channelIds: string[]): ActionFuncAsync<import("@mattermost/types/client4").StatusOK, import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
10
10
  export declare function unassignChannelsFromAccessControlPolicy(policyId: string, channelIds: string[]): ActionFuncAsync<import("@mattermost/types/client4").StatusOK, import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
11
11
  export declare function getAccessControlFields(after: string, limit: number, channelId?: string): ActionFuncAsync<import("@mattermost/types/properties").UserPropertyField[], import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
12
- export declare function updateAccessControlPolicyActive(policyId: string, active: boolean): ActionFuncAsync<import("@mattermost/types/client4").StatusOK, import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
13
12
  export declare function searchUsersForExpression(expression: string, term: string, after: string, limit: number, channelId?: string): ActionFuncAsync<AccessControlTestResult>;
14
13
  export declare function getVisualAST(expression: string, channelId?: string): ActionFuncAsync<import("@mattermost/types/access_control").AccessControlVisualAST, import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
15
14
  export declare function validateExpressionAgainstRequester(expression: string, channelId?: string): ActionFuncAsync<{
@@ -18,3 +17,4 @@ export declare function validateExpressionAgainstRequester(expression: string, c
18
17
  export declare function createAccessControlSyncJob(jobData: {
19
18
  policy_id: string;
20
19
  }): ActionFuncAsync<any>;
20
+ export declare function updateAccessControlPoliciesActive(states: AccessControlPolicyActiveUpdate[]): ActionFuncAsync<AccessControlPolicy[], import("@mattermost/types/store").GlobalState, import("redux").AnyAction>;
@@ -10,11 +10,11 @@ exports.searchAccessControlPolicyChannels = searchAccessControlPolicyChannels;
10
10
  exports.assignChannelsToAccessControlPolicy = assignChannelsToAccessControlPolicy;
11
11
  exports.unassignChannelsFromAccessControlPolicy = unassignChannelsFromAccessControlPolicy;
12
12
  exports.getAccessControlFields = getAccessControlFields;
13
- exports.updateAccessControlPolicyActive = updateAccessControlPolicyActive;
14
13
  exports.searchUsersForExpression = searchUsersForExpression;
15
14
  exports.getVisualAST = getVisualAST;
16
15
  exports.validateExpressionAgainstRequester = validateExpressionAgainstRequester;
17
16
  exports.createAccessControlSyncJob = createAccessControlSyncJob;
17
+ exports.updateAccessControlPoliciesActive = updateAccessControlPoliciesActive;
18
18
  const redux_batched_actions_1 = require("redux-batched-actions");
19
19
  const action_types_1 = require("mattermost-redux/action_types");
20
20
  const client_1 = require("mattermost-redux/client");
@@ -115,15 +115,6 @@ function getAccessControlFields(after, limit, channelId) {
115
115
  ],
116
116
  });
117
117
  }
118
- function updateAccessControlPolicyActive(policyId, active) {
119
- return (0, helpers_1.bindClientFunc)({
120
- clientFunc: client_1.Client4.updateAccessControlPolicyActive,
121
- params: [
122
- policyId,
123
- active,
124
- ],
125
- });
126
- }
127
118
  function searchUsersForExpression(expression, term, after, limit, channelId) {
128
119
  return async (dispatch, getState) => {
129
120
  let data;
@@ -170,3 +161,9 @@ function createAccessControlSyncJob(jobData) {
170
161
  return { data };
171
162
  };
172
163
  }
164
+ function updateAccessControlPoliciesActive(states) {
165
+ return (0, helpers_1.bindClientFunc)({
166
+ clientFunc: client_1.Client4.updateAccessControlPoliciesActive,
167
+ params: [states],
168
+ });
169
+ }
@@ -0,0 +1,8 @@
1
+ import type { Recap } from '@mattermost/types/recaps';
2
+ import type { ActionFuncAsync } from 'mattermost-redux/types/actions';
3
+ export declare function createRecap(title: string, channelIds: string[], agentId: string): ActionFuncAsync<Recap>;
4
+ export declare function getRecaps(page?: number, perPage?: number): ActionFuncAsync<Recap[]>;
5
+ export declare function getRecap(recapId: string): ActionFuncAsync<Recap>;
6
+ export declare function markRecapAsRead(recapId: string): ActionFuncAsync<Recap>;
7
+ export declare function regenerateRecap(recapId: string): ActionFuncAsync<Recap>;
8
+ export declare function deleteRecap(recapId: string): ActionFuncAsync;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.createRecap = createRecap;
6
+ exports.getRecaps = getRecaps;
7
+ exports.getRecap = getRecap;
8
+ exports.markRecapAsRead = markRecapAsRead;
9
+ exports.regenerateRecap = regenerateRecap;
10
+ exports.deleteRecap = deleteRecap;
11
+ const action_types_1 = require("mattermost-redux/action_types");
12
+ const errors_1 = require("mattermost-redux/actions/errors");
13
+ const client_1 = require("mattermost-redux/client");
14
+ const helpers_1 = require("./helpers");
15
+ function createRecap(title, channelIds, agentId) {
16
+ return (0, helpers_1.bindClientFunc)({
17
+ clientFunc: () => client_1.Client4.createRecap({ title, channel_ids: channelIds, agent_id: agentId }),
18
+ onRequest: action_types_1.RecapTypes.CREATE_RECAP_REQUEST,
19
+ onSuccess: [action_types_1.RecapTypes.CREATE_RECAP_SUCCESS, action_types_1.RecapTypes.RECEIVED_RECAP],
20
+ onFailure: action_types_1.RecapTypes.CREATE_RECAP_FAILURE,
21
+ });
22
+ }
23
+ function getRecaps(page = 0, perPage = 60) {
24
+ return (0, helpers_1.bindClientFunc)({
25
+ clientFunc: () => client_1.Client4.getRecaps(page, perPage),
26
+ onRequest: action_types_1.RecapTypes.GET_RECAPS_REQUEST,
27
+ onSuccess: [action_types_1.RecapTypes.GET_RECAPS_SUCCESS, action_types_1.RecapTypes.RECEIVED_RECAPS],
28
+ onFailure: action_types_1.RecapTypes.GET_RECAPS_FAILURE,
29
+ });
30
+ }
31
+ function getRecap(recapId) {
32
+ return (0, helpers_1.bindClientFunc)({
33
+ clientFunc: () => client_1.Client4.getRecap(recapId),
34
+ onRequest: action_types_1.RecapTypes.GET_RECAP_REQUEST,
35
+ onSuccess: [action_types_1.RecapTypes.GET_RECAP_SUCCESS, action_types_1.RecapTypes.RECEIVED_RECAP],
36
+ onFailure: action_types_1.RecapTypes.GET_RECAP_FAILURE,
37
+ });
38
+ }
39
+ function markRecapAsRead(recapId) {
40
+ return (0, helpers_1.bindClientFunc)({
41
+ clientFunc: () => client_1.Client4.markRecapAsRead(recapId),
42
+ onRequest: action_types_1.RecapTypes.MARK_RECAP_READ_REQUEST,
43
+ onSuccess: [action_types_1.RecapTypes.MARK_RECAP_READ_SUCCESS, action_types_1.RecapTypes.RECEIVED_RECAP],
44
+ onFailure: action_types_1.RecapTypes.MARK_RECAP_READ_FAILURE,
45
+ });
46
+ }
47
+ function regenerateRecap(recapId) {
48
+ return (0, helpers_1.bindClientFunc)({
49
+ clientFunc: () => client_1.Client4.regenerateRecap(recapId),
50
+ onRequest: action_types_1.RecapTypes.REGENERATE_RECAP_REQUEST,
51
+ onSuccess: [action_types_1.RecapTypes.REGENERATE_RECAP_SUCCESS, action_types_1.RecapTypes.RECEIVED_RECAP],
52
+ onFailure: action_types_1.RecapTypes.REGENERATE_RECAP_FAILURE,
53
+ });
54
+ }
55
+ function deleteRecap(recapId) {
56
+ return async (dispatch, getState) => {
57
+ dispatch({ type: action_types_1.RecapTypes.DELETE_RECAP_REQUEST, data: recapId });
58
+ try {
59
+ await client_1.Client4.deleteRecap(recapId);
60
+ dispatch({
61
+ type: action_types_1.RecapTypes.DELETE_RECAP_SUCCESS,
62
+ data: { recapId },
63
+ });
64
+ return { data: true };
65
+ }
66
+ catch (error) {
67
+ dispatch((0, errors_1.logError)(error));
68
+ (0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
69
+ dispatch({
70
+ type: action_types_1.RecapTypes.DELETE_RECAP_FAILURE,
71
+ error,
72
+ });
73
+ return { error };
74
+ }
75
+ };
76
+ }
@@ -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;
@@ -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
  }
@@ -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;
@@ -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;
@@ -98,6 +98,7 @@ declare const _default: import("redux").Reducer<{
98
98
  [key: string]: import("@mattermost/types/preferences").PreferencesType;
99
99
  };
100
100
  };
101
+ recaps: import("./recaps").RecapsState;
101
102
  typing: import("@mattermost/types/typing").Typing;
102
103
  integrations: {
103
104
  incomingHooks: import("@mattermost/types/utilities").IDMappedObjects<import("@mattermost/types/integrations").IncomingWebhook>;
@@ -470,6 +471,7 @@ declare const _default: import("redux").Reducer<{
470
471
  myPreferences: Record<string, import("@mattermost/types/preferences").PreferenceType> | undefined;
471
472
  userPreferences: Record<string, import("@mattermost/types/preferences").PreferencesType> | undefined;
472
473
  }> | undefined;
474
+ recaps: import("./recaps").RecapsState | undefined;
473
475
  typing: import("@mattermost/types/typing").Typing | undefined;
474
476
  integrations: {
475
477
  incomingHooks: import("@mattermost/types/utilities").IDMappedObjects<import("@mattermost/types/integrations").IncomingWebhook>;
@@ -25,6 +25,7 @@ const jobs_1 = __importDefault(require("./jobs"));
25
25
  const limits_1 = __importDefault(require("./limits"));
26
26
  const posts_1 = __importDefault(require("./posts"));
27
27
  const preferences_1 = __importDefault(require("./preferences"));
28
+ const recaps_1 = __importDefault(require("./recaps"));
28
29
  const roles_1 = __importDefault(require("./roles"));
29
30
  const scheduled_posts_1 = __importDefault(require("./scheduled_posts"));
30
31
  const schemes_1 = __importDefault(require("./schemes"));
@@ -45,6 +46,7 @@ exports.default = (0, redux_1.combineReducers)({
45
46
  posts: posts_1.default,
46
47
  files: files_1.default,
47
48
  preferences: preferences_1.default,
49
+ recaps: recaps_1.default,
48
50
  typing: typing_1.default,
49
51
  integrations: integrations_1.default,
50
52
  emojis: emojis_1.default,
@@ -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) {
@@ -129,6 +130,46 @@ function nextPostsReplies(state = {}, action) {
129
130
  return state;
130
131
  }
131
132
  }
133
+ // Helper function to remove posts and permalink embeds for a set of channel IDs.
134
+ function removePostsAndEmbedsForChannels(state, channelIds) {
135
+ let postModified = false;
136
+ const nextState = { ...state };
137
+ for (const post of Object.values(state)) {
138
+ // Remove posts from the channels
139
+ if (channelIds.has(post.channel_id)) {
140
+ Reflect.deleteProperty(nextState, post.id);
141
+ postModified = true;
142
+ continue;
143
+ }
144
+ // Remove permalink embeds referencing those channels (matches server behavior)
145
+ if (post.metadata?.embeds?.length) {
146
+ const newEmbeds = [];
147
+ let embedRemoved = false;
148
+ for (const embed of post.metadata.embeds) {
149
+ if (embed.type === 'permalink' && embed.data && channelIds.has(embed.data.channel_id)) {
150
+ embedRemoved = true;
151
+ }
152
+ else {
153
+ newEmbeds.push(embed);
154
+ }
155
+ }
156
+ if (embedRemoved) {
157
+ nextState[post.id] = {
158
+ ...nextState[post.id],
159
+ metadata: {
160
+ ...nextState[post.id].metadata,
161
+ embeds: newEmbeds,
162
+ },
163
+ };
164
+ postModified = true;
165
+ }
166
+ }
167
+ }
168
+ if (!postModified) {
169
+ return state;
170
+ }
171
+ return nextState;
172
+ }
132
173
  function handlePosts(state = {}, action) {
133
174
  switch (action.type) {
134
175
  case action_types_1.PostTypes.RECEIVED_POST:
@@ -151,6 +192,11 @@ function handlePosts(state = {}, action) {
151
192
  if (!state[post.id]) {
152
193
  return state;
153
194
  }
195
+ if (state[post.id].type === posts_1.PostTypes.BURN_ON_READ) {
196
+ const nextState = { ...state };
197
+ Reflect.deleteProperty(nextState, post.id);
198
+ return nextState;
199
+ }
154
200
  // Mark the post as deleted
155
201
  const nextState = {
156
202
  ...state,
@@ -229,22 +275,78 @@ function handlePosts(state = {}, action) {
229
275
  },
230
276
  };
231
277
  }
278
+ case action_types_1.PostTypes.REVEAL_BURN_ON_READ_SUCCESS: {
279
+ const { post, expireAt } = action.data;
280
+ if (!state[post.id]) {
281
+ return state;
282
+ }
283
+ const currentPost = state[post.id];
284
+ const currentMetadata = currentPost.metadata || {};
285
+ const newMetadata = post.metadata || {};
286
+ return {
287
+ ...state,
288
+ [post.id]: {
289
+ ...currentPost,
290
+ ...post,
291
+ metadata: {
292
+ ...currentMetadata,
293
+ ...newMetadata,
294
+ expire_at: expireAt,
295
+ },
296
+ },
297
+ };
298
+ }
299
+ case action_types_1.PostTypes.POST_RECIPIENTS_UPDATED: {
300
+ const { postId, recipients } = action.data;
301
+ if (!state[postId]) {
302
+ return state;
303
+ }
304
+ const currentPost = state[postId];
305
+ const currentMetadata = currentPost.metadata || {};
306
+ const currentRecipients = currentMetadata.recipients || [];
307
+ // Merge new recipients with existing ones (don't replace).
308
+ // Server sends incremental updates (only the revealing user), so we must merge.
309
+ const mergedRecipients = [...new Set([...currentRecipients, ...recipients])];
310
+ return {
311
+ ...state,
312
+ [postId]: {
313
+ ...currentPost,
314
+ metadata: {
315
+ ...currentMetadata,
316
+ recipients: mergedRecipients,
317
+ },
318
+ },
319
+ };
320
+ }
321
+ case action_types_1.PostTypes.BURN_ON_READ_ALL_REVEALED: {
322
+ const { postId, senderExpireAt } = action.data;
323
+ if (!state[postId]) {
324
+ return state;
325
+ }
326
+ const currentPost = state[postId];
327
+ const currentMetadata = currentPost.metadata || {};
328
+ // Set sender's expiration time to trigger timer display
329
+ return {
330
+ ...state,
331
+ [postId]: {
332
+ ...currentPost,
333
+ metadata: {
334
+ ...currentMetadata,
335
+ expire_at: senderExpireAt,
336
+ },
337
+ },
338
+ };
339
+ }
232
340
  case action_types_1.ChannelTypes.LEAVE_CHANNEL: {
233
341
  const channelId = action.data.id;
234
- let postDeleted = false;
235
- // Remove any posts from the channel left by the user
236
- const nextState = { ...state };
237
- for (const post of Object.values(state)) {
238
- if (post.channel_id === channelId) {
239
- Reflect.deleteProperty(nextState, post.id);
240
- postDeleted = true;
241
- }
242
- }
243
- if (!postDeleted) {
244
- // Nothing changed
342
+ return removePostsAndEmbedsForChannels(state, new Set([channelId]));
343
+ }
344
+ case action_types_1.TeamTypes.LEAVE_TEAM: {
345
+ const channelIds = action.data.channelIds || [];
346
+ if (channelIds.length === 0) {
245
347
  return state;
246
348
  }
247
- return nextState;
349
+ return removePostsAndEmbedsForChannels(state, new Set(channelIds));
248
350
  }
249
351
  case action_types_1.ThreadTypes.FOLLOW_CHANGED_THREAD: {
250
352
  const { id, following } = action.data;
@@ -605,17 +707,24 @@ function postsInChannel(state = {}, action, prevPosts, nextPosts) {
605
707
  }
606
708
  case action_types_1.PostTypes.POST_DELETED: {
607
709
  const post = action.data;
608
- // Deleting a post removes its comments from the order, but does not remove the post itself
609
710
  const postsForChannel = state[post.channel_id] || [];
610
711
  if (postsForChannel.length === 0) {
611
712
  return state;
612
713
  }
613
714
  let changed = false;
614
715
  let nextPostsForChannel = [...postsForChannel];
716
+ const isBoRPost = prevPosts[post.id]?.type === posts_1.PostTypes.BURN_ON_READ;
717
+ const shouldRemovePost = (postId) => {
718
+ const isTheDeletedPost = postId === post.id;
719
+ const isReplyToDeletedPost = prevPosts[postId]?.root_id === post.id;
720
+ if (isBoRPost) {
721
+ return isTheDeletedPost;
722
+ }
723
+ return isReplyToDeletedPost;
724
+ };
615
725
  for (let i = 0; i < nextPostsForChannel.length; i++) {
616
726
  const block = nextPostsForChannel[i];
617
- // Remove any comments for this post
618
- const nextOrder = block.order.filter((postId) => prevPosts[postId].root_id !== post.id);
727
+ const nextOrder = block.order.filter((postId) => !shouldRemovePost(postId));
619
728
  if (nextOrder.length !== block.order.length) {
620
729
  nextPostsForChannel[i] = {
621
730
  ...block,
@@ -642,11 +751,16 @@ function postsInChannel(state = {}, action, prevPosts, nextPosts) {
642
751
  return state;
643
752
  }
644
753
  let changed = false;
754
+ const isBoRPost = prevPosts[post.id]?.type === posts_1.PostTypes.BURN_ON_READ;
645
755
  // Remove the post and its comments from the channel
646
756
  let nextPostsForChannel = [...postsForChannel];
647
757
  for (let i = 0; i < nextPostsForChannel.length; i++) {
648
758
  const block = nextPostsForChannel[i];
649
- const nextOrder = block.order.filter((postId) => postId !== post.id && prevPosts[postId].root_id !== post.id);
759
+ // For BoR posts: only remove the post itself (BoR doesn't support threads)
760
+ // For regular posts: remove the post and its thread replies
761
+ const nextOrder = isBoRPost ?
762
+ block.order.filter((postId) => postId !== post.id) :
763
+ block.order.filter((postId) => postId !== post.id && prevPosts[postId]?.root_id !== post.id);
650
764
  if (nextOrder.length !== block.order.length) {
651
765
  nextPostsForChannel[i] = {
652
766
  ...block,
@@ -0,0 +1,7 @@
1
+ import type { Recap } from '@mattermost/types/recaps';
2
+ import type { MMReduxAction } from 'mattermost-redux/action_types';
3
+ export type RecapsState = {
4
+ byId: Record<string, Recap>;
5
+ allIds: string[];
6
+ };
7
+ export default function recapsReducer(state: RecapsState | undefined, action: MMReduxAction): RecapsState;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.default = recapsReducer;
6
+ const action_types_1 = require("mattermost-redux/action_types");
7
+ const initialState = {
8
+ byId: {},
9
+ allIds: [],
10
+ };
11
+ function recapsReducer(state = initialState, action) {
12
+ switch (action.type) {
13
+ case action_types_1.RecapTypes.RECEIVED_RECAP: {
14
+ const recap = action.data;
15
+ const nextState = { ...state };
16
+ nextState.byId = {
17
+ ...state.byId,
18
+ [recap.id]: recap,
19
+ };
20
+ if (!state.allIds.includes(recap.id)) {
21
+ nextState.allIds = [...state.allIds, recap.id];
22
+ }
23
+ return nextState;
24
+ }
25
+ case action_types_1.RecapTypes.RECEIVED_RECAPS: {
26
+ const recaps = action.data;
27
+ const nextState = { ...state };
28
+ const newById = { ...state.byId };
29
+ const newAllIds = new Set(state.allIds);
30
+ recaps.forEach((recap) => {
31
+ newById[recap.id] = recap;
32
+ newAllIds.add(recap.id);
33
+ });
34
+ nextState.byId = newById;
35
+ nextState.allIds = Array.from(newAllIds);
36
+ return nextState;
37
+ }
38
+ case action_types_1.RecapTypes.DELETE_RECAP_SUCCESS: {
39
+ const { recapId } = action.data;
40
+ const nextState = { ...state };
41
+ const newById = { ...state.byId };
42
+ delete newById[recapId];
43
+ nextState.byId = newById;
44
+ nextState.allIds = state.allIds.filter((id) => id !== recapId);
45
+ return nextState;
46
+ }
47
+ case action_types_1.UserTypes.LOGOUT_SUCCESS:
48
+ return initialState;
49
+ default:
50
+ return state;
51
+ }
52
+ }
@@ -100,6 +100,7 @@ declare const _default: {
100
100
  [key: string]: import("@mattermost/types/preferences").PreferencesType;
101
101
  };
102
102
  };
103
+ recaps: import("./entities/recaps").RecapsState;
103
104
  typing: import("@mattermost/types/typing").Typing;
104
105
  integrations: {
105
106
  incomingHooks: import("@mattermost/types/utilities").IDMappedObjects<import("@mattermost/types/integrations").IncomingWebhook>;
@@ -472,6 +473,7 @@ declare const _default: {
472
473
  myPreferences: Record<string, import("@mattermost/types/preferences").PreferenceType> | undefined;
473
474
  userPreferences: Record<string, import("@mattermost/types/preferences").PreferencesType> | undefined;
474
475
  }> | undefined;
476
+ recaps: import("./entities/recaps").RecapsState | undefined;
475
477
  typing: import("@mattermost/types/typing").Typing | undefined;
476
478
  integrations: {
477
479
  incomingHooks: import("@mattermost/types/utilities").IDMappedObjects<import("@mattermost/types/integrations").IncomingWebhook>;
@@ -1,3 +1,2 @@
1
1
  import type { GlobalState } from '@mattermost/types/store';
2
- export declare const selectChannelBannerEnabled: (state: GlobalState) => boolean;
3
2
  export declare const selectShowChannelBanner: (state: GlobalState, channelId: string) => boolean;
@@ -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 = exports.selectChannelBannerEnabled = void 0;
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
- return getPostsChunkInChannelAroundTime(state, channelId, timeStamp);
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;
@@ -0,0 +1,11 @@
1
+ import type { Recap } from '@mattermost/types/recaps';
2
+ import { RecapStatus } from '@mattermost/types/recaps';
3
+ import type { GlobalState } from '@mattermost/types/store';
4
+ export declare function getAllRecaps(state: GlobalState): Recap[];
5
+ export declare function getRecap(state: GlobalState, recapId: string): Recap | undefined;
6
+ export declare const getRecapsByStatus: import("mattermost-redux/selectors/create_selector").OutputParametricSelector<GlobalState, RecapStatus, Recap[], (res1: Recap[], res2: RecapStatus) => Recap[]>;
7
+ export declare const getSortedRecaps: import("mattermost-redux/selectors/create_selector").OutputSelector<GlobalState, Recap[], (res: Recap[]) => Recap[]>;
8
+ export declare const getCompletedRecaps: import("mattermost-redux/selectors/create_selector").OutputSelector<GlobalState, Recap[], (res: Recap[]) => Recap[]>;
9
+ export declare const getPendingRecaps: import("mattermost-redux/selectors/create_selector").OutputSelector<GlobalState, Recap[], (res: Recap[]) => Recap[]>;
10
+ export declare const getUnreadRecaps: import("mattermost-redux/selectors/create_selector").OutputSelector<GlobalState, Recap[], (res: Recap[]) => Recap[]>;
11
+ export declare const getReadRecaps: import("mattermost-redux/selectors/create_selector").OutputSelector<GlobalState, Recap[], (res: Recap[]) => Recap[]>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.getReadRecaps = exports.getUnreadRecaps = exports.getPendingRecaps = exports.getCompletedRecaps = exports.getSortedRecaps = exports.getRecapsByStatus = void 0;
6
+ exports.getAllRecaps = getAllRecaps;
7
+ exports.getRecap = getRecap;
8
+ const recaps_1 = require("@mattermost/types/recaps");
9
+ const create_selector_1 = require("mattermost-redux/selectors/create_selector");
10
+ function getAllRecaps(state) {
11
+ const { byId, allIds } = state.entities.recaps;
12
+ return allIds.map((id) => byId[id]);
13
+ }
14
+ function getRecap(state, recapId) {
15
+ return state.entities.recaps.byId[recapId] || undefined;
16
+ }
17
+ exports.getRecapsByStatus = (0, create_selector_1.createSelector)('getRecapsByStatus', getAllRecaps, (_state, status) => status, (recaps, status) => {
18
+ return recaps.filter((recap) => recap.status === status);
19
+ });
20
+ exports.getSortedRecaps = (0, create_selector_1.createSelector)('getSortedRecaps', getAllRecaps, (recaps) => {
21
+ return [...recaps].sort((a, b) => b.create_at - a.create_at);
22
+ });
23
+ exports.getCompletedRecaps = (0, create_selector_1.createSelector)('getCompletedRecaps', getAllRecaps, (recaps) => {
24
+ return recaps.filter((recap) => recap.status === recaps_1.RecapStatus.COMPLETED).sort((a, b) => b.create_at - a.create_at);
25
+ });
26
+ exports.getPendingRecaps = (0, create_selector_1.createSelector)('getPendingRecaps', getAllRecaps, (recaps) => {
27
+ return recaps.filter((recap) => recap.status === recaps_1.RecapStatus.PENDING || recap.status === recaps_1.RecapStatus.PROCESSING);
28
+ });
29
+ exports.getUnreadRecaps = (0, create_selector_1.createSelector)('getUnreadRecaps', getAllRecaps, (recaps) => {
30
+ return recaps.filter((recap) => recap.read_at === 0).sort((a, b) => b.create_at - a.create_at);
31
+ });
32
+ exports.getReadRecaps = (0, create_selector_1.createSelector)('getReadRecaps', getAllRecaps, (recaps) => {
33
+ return recaps.filter((recap) => recap.read_at > 0).sort((a, b) => b.read_at - a.read_at);
34
+ });
@@ -100,6 +100,10 @@ const state = {
100
100
  counts: {},
101
101
  countsIncludingDirect: {},
102
102
  },
103
+ recaps: {
104
+ byId: {},
105
+ allIds: [],
106
+ },
103
107
  preferences: {
104
108
  myPreferences: {},
105
109
  userPreferences: {},
@@ -60,8 +60,9 @@ function checkDialogElementForError(elem, value) {
60
60
  if (value && value.length < elem.min_length) {
61
61
  return (0, react_intl_1.defineMessage)({
62
62
  id: 'interactive_dialog.error.too_short',
63
+ // minLength provided by InteractiveDialog
64
+ // eslint-disable-next-line formatjs/enforce-placeholders
63
65
  defaultMessage: 'Minimum input length is {minLength}.',
64
- values: { minLength: elem.min_length },
65
66
  });
66
67
  }
67
68
  if (elem.subtype === 'email') {
@@ -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 &&
@@ -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.2.0",
3
+ "version": "11.4.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.2.0",
43
- "@mattermost/types": "11.2.0",
42
+ "@mattermost/client": "11.4.0",
43
+ "@mattermost/types": "11.4.0",
44
44
  "@redux-devtools/extension": "3.3.0",
45
45
  "lodash": "^4.17.21",
46
46
  "moment-timezone": "^0.5.38",