Merge pull request #60 from Bilb/fix-group-v2-create-from-ts

fix: allow to switch from create group/groupv2 based on a ts.flag
pull/3281/head
Audric Ackermann 10 months ago committed by GitHub
commit 17d2b10a09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -92,7 +92,7 @@
"fs-extra": "9.0.0",
"glob": "10.3.10",
"image-type": "^4.1.0",
"libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.15/libsession_util_nodejs-v0.4.15.tar.gz",
"libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz",
"libsodium-wrappers-sumo": "^0.7.9",
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",

@ -51,7 +51,7 @@ window.getUserKeys = async () => {
window.sessionFeatureFlags = {
useOnionRequests: true,
useTestNet: isTestNet() || isTestIntegration(),
useClosedGroupV2: true, // TODO DO NOT MERGE Remove after QA
useClosedGroupV2: false, // TODO DO NOT MERGE Remove after QA
forceLegacyGroupsDeprecated: false, // TODO DO NOT MERGE Remove after QA
useClosedGroupV2QAButtons: true, // TODO DO NOT MERGE Remove after QA
replaceLocalizedStringsWithKeys: false,

@ -69,6 +69,7 @@ import {
useSelectedWeAreAdmin,
} from '../../state/selectors/selectedConversation';
import { useSelectedDisableLegacyGroupDeprecatedActions } from '../../hooks/useRefreshReleasedFeaturesTimestamp';
import { useAreGroupsCreatedAsNewGroupsYet } from '../../state/selectors/releasedFeatures';
const DEFAULT_JPEG_QUALITY = 0.85;
@ -675,6 +676,8 @@ function OutdatedLegacyGroupBanner() {
const isLegacyGroup =
!isPrivate && !isPublic && selectedConversationKey && selectedConversationKey.startsWith('05');
const newGroupsCanBeCreated = useAreGroupsCreatedAsNewGroupsYet();
// FIXME change the date here. Remove after QA
const text = deprecatedLegacyGroups
? localize(
@ -686,7 +689,7 @@ function OutdatedLegacyGroupBanner() {
.withArgs({ date: '[Date]' })
.toString();
return isLegacyGroup ? (
return isLegacyGroup && newGroupsCanBeCreated ? (
<NoticeBanner
text={text}
onBannerClick={() => {

@ -25,6 +25,7 @@ import { groupInfoActions } from '../../../state/ducks/metaGroups';
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { setLeftOverlayMode } from '../../../state/ducks/section';
import { SessionButtonColor, SessionButton } from '../../basic/SessionButton';
import { useAreGroupsCreatedAsNewGroupsYet } from '../../../state/selectors/releasedFeatures';
export const ConversationHeaderWithDetails = () => {
const isSelectionMode = useIsMessageSelectionMode();
@ -121,8 +122,9 @@ function RecreateGroupButton() {
const weAreAdmin = useSelectedWeAreAdmin();
const showRecreateGroupModal = useShowRecreateModal();
const newGroupsCanBeCreated = useAreGroupsCreatedAsNewGroupsYet();
if (!isLegacyGroup || !weAreAdmin) {
if (!isLegacyGroup || !weAreAdmin || !newGroupsCanBeCreated) {
return null;
}

@ -20,6 +20,7 @@ import { OverlayInvite } from './overlay/OverlayInvite';
import { OverlayMessage } from './overlay/OverlayMessage';
import { OverlayMessageRequest } from './overlay/OverlayMessageRequest';
import { OverlayChooseAction } from './overlay/choose-action/OverlayChooseAction';
import { useAreGroupsCreatedAsNewGroupsYet } from '../../state/selectors/releasedFeatures';
const StyledLeftPaneContent = styled.div`
display: flex;
@ -40,17 +41,15 @@ const StyledConversationListContent = styled.div`
const ClosableOverlay = () => {
const leftOverlayMode = useSelector(getLeftOverlayMode);
const shouldCreateNewGroups = useAreGroupsCreatedAsNewGroupsYet();
switch (leftOverlayMode) {
case 'choose-action':
return <OverlayChooseAction />;
case 'open-group':
return <OverlayCommunity />;
case 'closed-group':
return window.sessionFeatureFlags.useClosedGroupV2 ? (
<OverlayClosedGroupV2 />
) : (
<OverlayLegacyClosedGroup />
);
return shouldCreateNewGroups ? <OverlayClosedGroupV2 /> : <OverlayLegacyClosedGroup />;
case 'message':
return <OverlayMessage />;
case 'message-requests':

@ -3,15 +3,19 @@ import { useCallback, useEffect } from 'react';
import { isEmpty, isString } from 'lodash';
import { useDispatch } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import useUpdate from 'react-use/lib/useUpdate';
import { resetLeftOverlayMode, setLeftOverlayMode } from '../../../../state/ducks/section';
import { SpacerSM } from '../../../basic/Text';
import { StyledLeftPaneOverlay } from '../OverlayMessage';
import { ActionRow, StyledActionRowContainer } from './ActionRow';
import { ContactsListWithBreaks } from './ContactsListWithBreaks';
import { groupInfoActions } from '../../../../state/ducks/metaGroups';
import { SessionToggle } from '../../../basic/SessionToggle';
export const OverlayChooseAction = () => {
const dispatch = useDispatch();
const forceRefresh = useUpdate();
function closeOverlay() {
dispatch(resetLeftOverlayMode());
}
@ -78,6 +82,19 @@ export const OverlayChooseAction = () => {
onClick={openNewMessage}
dataTestId="chooser-new-conversation-button"
/>
{window.sessionFeatureFlags.useClosedGroupV2QAButtons ? (
<span style={{ display: 'flex', alignItems: 'center', alignSelf: 'center' }}>
Create group v2?{' '}
<SessionToggle
active={window.sessionFeatureFlags.useClosedGroupV2}
onClick={() => {
window.sessionFeatureFlags.useClosedGroupV2 =
!window.sessionFeatureFlags.useClosedGroupV2;
forceRefresh();
}}
/>
</span>
) : null}
<ActionRow
title={window.i18n('groupCreate')}
ariaLabel={'Create a group button'}

@ -4,7 +4,7 @@ import { DURATION } from '../session/constants';
import { updateLegacyGroupDeprecationTimestampUpdatedAt } from '../state/ducks/releasedFeatures';
import { NetworkTime } from '../util/NetworkTime';
import { PubKey } from '../session/types';
import { areLegacyGroupsDeprecatedYet } from '../state/selectors/releasedFeatures';
import { areLegacyGroupsReadOnly } from '../state/selectors/releasedFeatures';
import { useSelectedConversationKey } from '../state/selectors/selectedConversation';
import type { StateType } from '../state/reducer';
import { ConversationTypeEnum } from '../models/types';
@ -27,7 +27,7 @@ export function getDisableLegacyGroupDeprecatedActions(state: StateType, convoId
if (!selectedConvoIsGroup) {
return false;
}
const legacyGroupDeprecated = areLegacyGroupsDeprecatedYet();
const legacyGroupDeprecated = areLegacyGroupsReadOnly();
// here we have
// - a valid convoId
// - that starts with 05

@ -58,7 +58,7 @@ import {
} from './types';
import { ConversationTypeEnum } from '../../../models/types';
import { Snode } from '../../../data/types';
import { areLegacyGroupsDeprecatedYetOutsideRedux } from '../../../state/selectors/releasedFeatures';
import { areLegacyGroupsReadOnlyOutsideRedux } from '../../../state/selectors/releasedFeatures';
const minMsgCountShouldRetry = 95;
/**
@ -297,7 +297,7 @@ export class SwarmPolling {
.filter(m => !allGroupsInWrapper.some(w => w.pubkeyHex === m.pubkey.key))
.map(entryToKey);
const legacyGroupDeprecatedDisabled = areLegacyGroupsDeprecatedYetOutsideRedux();
const legacyGroupDeprecatedDisabled = areLegacyGroupsReadOnlyOutsideRedux();
const allLegacyGroupsTracked = legacyGroupDeprecatedDisabled
? []

@ -99,9 +99,24 @@ export const REACT_LIMIT = 6;
export const UPDATER_INTERVAL_MS = 10 * DURATION.MINUTES;
// update this to be when we ship desktop groups REMOVE AFTER QA
const GROUP_DESKTOP_RELEASE = 1767225600000; // currently 1st Jan 2026
/**
* 3+7 days after the release of groups (more or less), we force new groups to be created as new groups
*/
const START_CREATE_NEW_GROUP = GROUP_DESKTOP_RELEASE + DURATION.DAYS * 10;
/**
* 2 weeks after `START_CREATE_NEW_GROUP`, we mark legacy groups readonly
*/
const LEGACY_GROUP_READONLY = START_CREATE_NEW_GROUP + DURATION.WEEKS * 2;
export const FEATURE_RELEASE_TIMESTAMPS = {
DISAPPEARING_MESSAGES_V2: 1710284400000, // 13/03/2024 10:00 Melbourne time
USER_CONFIG: 1690761600000, // Monday July 31st at 10am Melbourne time
START_CREATE_NEW_GROUP,
LEGACY_GROUP_READONLY,
};
export const ONBOARDING_TIMES = {

@ -59,8 +59,6 @@ export type GroupState = {
members: Record<GroupPubkeyType, Array<GroupMemberGet>>;
memberChangesFromUIPending: boolean;
nameChangesFromUIPending: boolean;
membersInviteSending: Record<GroupPubkeyType, Array<PubkeyType>>;
membersPromoteSending: Record<GroupPubkeyType, Array<PubkeyType>>;
// those are group creation-related fields
creationFromUIPending: boolean;
@ -74,8 +72,6 @@ export const initialGroupState: GroupState = {
creationFromUIPending: false,
memberChangesFromUIPending: false,
nameChangesFromUIPending: false,
membersInviteSending: {},
membersPromoteSending: {},
creationMembersSelected: [],
creationGroupName: '',
};
@ -406,6 +402,10 @@ const loadMetaDumpsFromDB = createAsyncThunk(
metaDumped: data,
});
// If we were sending to that member an invite/promote, we won't auto retry.
// We need to reset the sending state (on load from disk) so that the user can resend manually if needed
await MetaGroupWrapperActions.memberResetAllSendingState(groupPk);
const infos = await MetaGroupWrapperActions.infoGet(groupPk);
const members = await MetaGroupWrapperActions.memberGetAll(groupPk);
@ -680,6 +680,9 @@ async function handleMemberAddedFromUI({
updateMessagesToPush.push(groupChange);
}
}
await LibSessionUtil.saveDumpsToDb(groupPk);
refreshConvosModelProps([groupPk]);
window.inboxStore?.dispatch(refreshGroupDetailsFromWrapper({ groupPk }) as any);
const extraStoreRequests = await StoreGroupRequestFactory.makeGroupMessageSubRequest(
updateMessagesToPush,
@ -1281,8 +1284,6 @@ const metaGroupSlice = createSlice({
) {
delete state.infos[payload.groupPk];
delete state.members[payload.groupPk];
delete state.membersInviteSending[payload.groupPk];
delete state.membersPromoteSending[payload.groupPk];
},
addSelectedGroupMember(
state: GroupState,

@ -1,15 +1,17 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import { DURATION } from '../../session/constants';
// FIXME update this to the correct timestamp REMOVE AFTER QA
export const LEGACY_GROUP_DEPRECATED_TIMESTAMP_MS = Date.now() + DURATION.WEEKS * 52;
import { NetworkTime } from '../../util/NetworkTime';
import { FEATURE_RELEASE_TIMESTAMPS } from '../../session/constants';
export interface ReleasedFeaturesState {
legacyGroupDeprecationTimestampRefreshAtMs: number;
canCreateGroupV2: boolean;
legacyGroupsReadOnly: boolean;
}
export const initialReleasedFeaturesState = {
legacyGroupDeprecationTimestampRefreshAtMs: Date.now(),
canCreateGroupV2: Date.now() >= FEATURE_RELEASE_TIMESTAMPS.START_CREATE_NEW_GROUP,
legacyGroupsReadOnly: Date.now() >= FEATURE_RELEASE_TIMESTAMPS.LEGACY_GROUP_READONLY,
};
const releasedFeaturesSlice = createSlice({
@ -18,6 +20,11 @@ const releasedFeaturesSlice = createSlice({
reducers: {
updateLegacyGroupDeprecationTimestampUpdatedAt: (state, action: PayloadAction<number>) => {
state.legacyGroupDeprecationTimestampRefreshAtMs = action.payload;
state.canCreateGroupV2 =
NetworkTime.now() >= FEATURE_RELEASE_TIMESTAMPS.START_CREATE_NEW_GROUP;
state.legacyGroupsReadOnly =
NetworkTime.now() >= FEATURE_RELEASE_TIMESTAMPS.LEGACY_GROUP_READONLY;
return state;
},
},
});

@ -1,15 +1,29 @@
import { NetworkTime } from '../../util/NetworkTime';
import { LEGACY_GROUP_DEPRECATED_TIMESTAMP_MS } from '../ducks/releasedFeatures';
import { useSelector } from 'react-redux';
import type { StateType } from '../reducer';
export const areLegacyGroupsDeprecatedYet = (): boolean => {
const theyAreDeprecated = NetworkTime.now() >= LEGACY_GROUP_DEPRECATED_TIMESTAMP_MS;
const areGroupsCreatedAsNewGroupsYet = (): boolean => {
const shouldCreateNewGroups = !!window.inboxStore?.getState()?.releasedFeatures.canCreateGroupV2;
return window.sessionFeatureFlags.forceLegacyGroupsDeprecated || theyAreDeprecated;
return window.sessionFeatureFlags.useClosedGroupV2 || shouldCreateNewGroups;
};
export function areLegacyGroupsDeprecatedYetOutsideRedux() {
export const areLegacyGroupsReadOnly = (): boolean => {
const theyAre = !!window.inboxStore?.getState()?.releasedFeatures.legacyGroupsReadOnly;
return window.sessionFeatureFlags.forceLegacyGroupsDeprecated || theyAre;
};
export function useAreGroupsCreatedAsNewGroupsYet() {
useSelector((state: StateType) => state.releasedFeatures.canCreateGroupV2);
return useSelector(areGroupsCreatedAsNewGroupsYet);
}
/**
* @returns true if legacy groups should not be polled anymore
*/
export function areLegacyGroupsReadOnlyOutsideRedux() {
if (!window.inboxStore) {
return false;
}
return areLegacyGroupsDeprecatedYet();
return areLegacyGroupsReadOnly();
}

@ -674,6 +674,10 @@ export const MetaGroupWrapperActions: MetaGroupWrapperActionsCalls = {
pubkeyHex,
profilePicture,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetProfilePicture']>>,
memberResetAllSendingState: async (groupPk: GroupPubkeyType) =>
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'memberResetAllSendingState']) as Promise<
ReturnType<MetaGroupWrapperActionsCalls['memberResetAllSendingState']>
>,
/** GroupKeys wrapper specific actions */
keyRekey: async (groupPk: GroupPubkeyType) =>

@ -4944,9 +4944,9 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
"libsession_util_nodejs@https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.15/libsession_util_nodejs-v0.4.15.tar.gz":
version "0.4.15"
resolved "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.15/libsession_util_nodejs-v0.4.15.tar.gz#de0e90e14327e60d81d2a6941bcd0af33fcfed82"
"libsession_util_nodejs@https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz":
version "0.4.16"
resolved "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz#253d4d02388b5bfb41f24c88fae5061b137ca615"
dependencies:
cmake-js "7.2.1"
node-addon-api "^6.1.0"

Loading…
Cancel
Save