MM-52419 - move preparing workspace onboarding behind usecaseonboarding ff for self-hosted (#23090)

* MM-52419 - move preparing workspace onboarding behind usecaseonboarding ff for self-hosted

* fetch active teams instead of just my teams

* use the onboarding flow enabled config value

* remove unnecessary conditions

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Pablo Andrés Vélez Vidal 2023-04-26 19:38:45 +02:00 committed by GitHub
parent 8e359790a7
commit 9e3f6e1840
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 69 additions and 23 deletions

View File

@ -12,8 +12,8 @@ import {
import {logout, loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {Preferences} from 'mattermost-redux/constants';
import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general';
import {getCurrentTeamId, getMyTeams, getTeam, getMyTeamMember, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
import {getBool, isCollapsedThreadsEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getMyTeams, getTeam, getMyTeamMember, getTeamMemberships, getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {getBool, getIsOnboardingFlowEnabled, isCollapsedThreadsEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUser, getCurrentUserId, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {getCurrentChannelStats, getCurrentChannelId, getMyChannelMember, getRedirectChannelNameForTeam, getChannelsNameMapInTeam, getAllDirectChannels, getChannelMessageCount} from 'mattermost-redux/selectors/entities/channels';
import {appsEnabled} from 'mattermost-redux/selectors/entities/apps';
@ -352,7 +352,7 @@ export async function redirectUserToDefaultTeam() {
// Assume we need to load the user if they don't have any team memberships loaded or the user loaded
let user = getCurrentUser(state);
const shouldLoadUser = Utils.isEmptyObject(getTeamMemberships(state)) || !user;
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(state);
if (shouldLoadUser) {
if (isGraphQLEnabled(state)) {
await dispatch(loadMe());
@ -374,8 +374,9 @@ export async function redirectUserToDefaultTeam() {
const teamId = LocalStorageStore.getPreviousTeamId(user.id);
let myTeams = getMyTeams(state);
if (myTeams.length === 0) {
if (isUserFirstAdmin) {
const teams = getActiveTeamsList(state);
if (teams.length === 0) {
if (isUserFirstAdmin && onboardingFlowEnabled) {
getHistory().push('/preparing-workspace');
return;
}

View File

@ -6,6 +6,7 @@ import {useIntl} from 'react-intl';
import {useSelector, useDispatch} from 'react-redux';
import {useLocation, useHistory} from 'react-router-dom';
import {redirectUserToDefaultTeam} from 'actions/global_actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import LaptopAlertSVG from 'components/common/svg_images_components/laptop_alert_svg';
@ -14,6 +15,7 @@ import LoadingScreen from 'components/loading_screen';
import {clearErrors, logError} from 'mattermost-redux/actions/errors';
import {verifyUserEmail, getMe} from 'mattermost-redux/actions/users';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {DispatchFunc} from 'mattermost-redux/types/actions';
@ -38,6 +40,7 @@ const DoVerifyEmail = () => {
const token = params.get('token') ?? '';
const loggedIn = Boolean(useSelector(getCurrentUserId));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const [verifyStatus, setVerifyStatus] = useState(VerifyStatus.PENDING);
const [serverError, setServerError] = useState('');
@ -49,11 +52,15 @@ const DoVerifyEmail = () => {
const handleRedirect = () => {
if (loggedIn) {
// need info about whether admin or not,
// and whether admin has already completed
// first time onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
history.push('/');
if (onboardingFlowEnabled) {
// need info about whether admin or not,
// and whether admin has already completed
// first time onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
history.push('/');
return;
}
redirectUserToDefaultTeam();
return;
}

View File

@ -8,6 +8,7 @@ import {withRouter} from 'react-router-dom';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {GenericAction} from 'mattermost-redux/types/actions';
import {getCurrentRelativeTeamUrl} from 'mattermost-redux/selectors/entities/teams';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {getUserGuideDropdownPluginMenuItems} from 'selectors/plugins';
@ -31,6 +32,7 @@ function mapStateToProps(state: GlobalState) {
teamUrl: getCurrentRelativeTeamUrl(state),
pluginMenuItems: getUserGuideDropdownPluginMenuItems(state),
isFirstAdmin: isFirstAdmin(state),
onboardingFlowEnabled: getIsOnboardingFlowEnabled(state),
};
}

View File

@ -34,6 +34,7 @@ describe('components/channel_header/components/UserGuideDropdown', () => {
},
pluginMenuItems: [],
isFirstAdmin: false,
onboardingFlowEnabled: false,
};
test('should match snapshot', () => {

View File

@ -13,7 +13,7 @@ import {UserProfile} from '@mattermost/types/users';
import {Client4} from 'mattermost-redux/client';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getIsOnboardingFlowEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getTeamByName, getMyTeamMember} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {isSystemAdmin} from 'mattermost-redux/utils/user_utils';
@ -104,6 +104,7 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const currentUser = useSelector(getCurrentUser);
const experimentalPrimaryTeam = useSelector((state: GlobalState) => (ExperimentalPrimaryTeam ? getTeamByName(state, ExperimentalPrimaryTeam) : undefined));
const experimentalPrimaryTeamMember = useSelector((state: GlobalState) => getMyTeamMember(state, experimentalPrimaryTeam?.id ?? ''));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const isCloud = useSelector(isCurrentLicenseCloud);
const graphQLEnabled = useSelector(isGraphQLEnabled);
@ -634,12 +635,14 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
} else if (experimentalPrimaryTeamMember.team_id) {
// Only set experimental team if user is on that team
history.push(`/${ExperimentalPrimaryTeam}`);
} else {
} else if (onboardingFlowEnabled) {
// need info about whether admin or not,
// and whether admin has already completed
// first time onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
history.push('/');
} else {
redirectUserToDefaultTeam();
}
};

View File

@ -12,6 +12,7 @@ import {sendEmailInvitesToTeamGracefully} from 'mattermost-redux/actions/teams';
import {getFirstAdminSetupComplete as getFirstAdminSetupCompleteAction} from 'mattermost-redux/actions/general';
import {ActionResult} from 'mattermost-redux/types/actions';
import {Team} from '@mattermost/types/teams';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {getCurrentTeam, getMyTeams} from 'mattermost-redux/selectors/entities/teams';
import {getFirstAdminSetupComplete, getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
@ -109,6 +110,7 @@ const PreparingWorkspace = (props: Props) => {
defaultMessage: 'Something went wrong. Please try again.',
});
const isUserFirstAdmin = useSelector(isFirstAdmin);
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const currentTeam = useSelector(getCurrentTeam);
const myTeams = useSelector(getMyTeams);
@ -289,7 +291,7 @@ const PreparingWorkspace = (props: Props) => {
}, [submissionState]);
const adminRevisitedPage = firstAdminSetupComplete && submissionState === SubmissionStates.Presubmit;
const shouldRedirect = !isUserFirstAdmin || adminRevisitedPage;
const shouldRedirect = !isUserFirstAdmin || adminRevisitedPage || !onboardingFlowEnabled;
useEffect(() => {
if (shouldRedirect) {

View File

@ -10,9 +10,10 @@ import classNames from 'classnames';
import {Client4} from 'mattermost-redux/client';
import {rudderAnalytics, RudderTelemetryHandler} from 'mattermost-redux/client/rudder';
import {General} from 'mattermost-redux/constants';
import {Theme} from 'mattermost-redux/selectors/entities/preferences';
import {Theme, getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentUser, isCurrentUserSystemAdmin, checkIsFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {setUrl} from 'mattermost-redux/actions/general';
import {setSystemEmojis} from 'mattermost-redux/actions/emojis';
@ -89,8 +90,6 @@ import {ActionResult} from 'mattermost-redux/types/actions';
import WelcomePostRenderer from 'components/welcome_post_renderer';
import {getMyTeams} from 'mattermost-redux/selectors/entities/teams';
import {applyLuxonDefaults} from './effects';
import RootProvider from './root_provider';
@ -360,8 +359,11 @@ export default class Root extends React.PureComponent<Props, State> {
return;
}
const myTeams = getMyTeams(storeState);
if (myTeams.length > 0) {
const teams = getActiveTeamsList(storeState);
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(storeState);
if (teams.length > 0 || !onboardingFlowEnabled) {
GlobalActions.redirectUserToDefaultTeam();
return;
}

View File

@ -6,6 +6,7 @@ import {connect} from 'react-redux';
import {getFirstAdminSetupComplete} from 'mattermost-redux/actions/general';
import {getCurrentUserId, isCurrentUserSystemAdmin, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {GenericAction} from 'mattermost-redux/types/actions';
import {GlobalState} from 'types/store';
@ -13,7 +14,11 @@ import {GlobalState} from 'types/store';
import RootRedirect, {Props} from './root_redirect';
function mapStateToProps(state: GlobalState) {
const isElegibleForFirstAdmingOnboarding = isCurrentUserSystemAdmin(state);
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(state);
let isElegibleForFirstAdmingOnboarding = onboardingFlowEnabled;
if (isElegibleForFirstAdmingOnboarding) {
isElegibleForFirstAdmingOnboarding = isCurrentUserSystemAdmin(state);
}
return {
currentUserId: getCurrentUserId(state),
isElegibleForFirstAdmingOnboarding,

View File

@ -17,7 +17,7 @@ import {getTeamInviteInfo} from 'mattermost-redux/actions/teams';
import {createUser, loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {DispatchFunc} from 'mattermost-redux/types/actions';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getIsOnboardingFlowEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {isEmail} from 'mattermost-redux/utils/helpers';
@ -25,6 +25,7 @@ import {GlobalState} from 'types/store';
import {getGlobalItem} from 'selectors/storage';
import {redirectUserToDefaultTeam} from 'actions/global_actions';
import {removeGlobalItem, setGlobalItem} from 'actions/storage';
import {addUserToTeamFromInvite} from 'actions/team_actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
@ -103,6 +104,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
} = config;
const {IsLicensed} = useSelector(getLicense);
const loggedIn = Boolean(useSelector(getCurrentUserId));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const usedBefore = useSelector((state: GlobalState) => (!inviteId && !loggedIn && token ? getGlobalItem(state, token, null) : undefined));
const graphQLEnabled = useSelector(isGraphQLEnabled);
@ -307,7 +309,15 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
} else if (inviteId) {
getInviteInfo(inviteId);
} else if (loggedIn) {
history.push('/');
if (onboardingFlowEnabled) {
// need info about whether admin or not,
// and whether admin has already completed
// first tiem onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
history.push('/');
} else {
redirectUserToDefaultTeam();
}
}
}
@ -450,12 +460,14 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
if (redirectTo) {
history.push(redirectTo);
} else {
} else if (onboardingFlowEnabled) {
// need info about whether admin or not,
// and whether admin has already completed
// first tiem onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
history.push('/');
} else {
redirectUserToDefaultTeam();
}
};

View File

@ -6,6 +6,7 @@ import {bindActionCreators, Dispatch, ActionCreatorsMapObject} from 'redux';
import {getTermsOfService, updateMyTermsOfServiceStatus} from 'mattermost-redux/actions/users';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {GlobalState} from '@mattermost/types/store';
import {ActionFunc, GenericAction} from 'mattermost-redux/types/actions';
@ -25,7 +26,9 @@ type Actions = {
function mapStateToProps(state: GlobalState) {
const config = getConfig(state);
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(state);
return {
onboardingFlowEnabled,
termsEnabled: config.EnableCustomTermsOfService === 'true',
emojiMap: getEmojiMap(state),
};

View File

@ -27,6 +27,7 @@ describe('components/terms_of_service/TermsOfService', () => {
location: {search: ''},
termsEnabled: true,
emojiMap: {} as EmojiMap,
onboardingFlowEnabled: false,
};
test('should match snapshot', () => {

View File

@ -38,6 +38,7 @@ export interface TermsOfServiceProps {
) => {data: UpdateMyTermsOfServiceStatusResponse};
};
emojiMap: EmojiMap;
onboardingFlowEnabled: boolean;
}
interface TermsOfServiceState {
@ -110,12 +111,14 @@ export default class TermsOfService extends React.PureComponent<TermsOfServicePr
const redirectTo = query.get('redirect_to');
if (redirectTo && redirectTo.match(/^\/([^/]|$)/)) {
getHistory().push(redirectTo);
} else {
} else if (this.props.onboardingFlowEnabled) {
// need info about whether admin or not,
// and whether admin has already completed
// first time onboarding. Instead of fetching and orchestrating that here,
// let the default root component handle it.
getHistory().push('/');
} else {
GlobalActions.redirectUserToDefaultTeam();
}
},
);

View File

@ -245,6 +245,10 @@ export function isCustomGroupsEnabled(state: GlobalState): boolean {
return getConfig(state).EnableCustomGroups === 'true';
}
export function getIsOnboardingFlowEnabled(state: GlobalState): boolean {
return getConfig(state).EnableOnboardingFlow === 'true';
}
export function insightsAreEnabled(state: GlobalState): boolean {
const isConfiguredForFeature = getConfig(state).InsightsEnabled === 'true';
const featureIsEnabled = getFeatureFlagValue(state, 'InsightsEnabled') === 'true';