diff --git a/web/packages/teleport/src/Users/Users.story.tsx b/web/packages/teleport/src/Users/Users.story.tsx
index 38d07d5193197..fc905715582c2 100644
--- a/web/packages/teleport/src/Users/Users.story.tsx
+++ b/web/packages/teleport/src/Users/Users.story.tsx
@@ -47,6 +47,14 @@ export const Loaded = () => {
);
};
+export const UsersNotEqualMauNotice = () => {
+ return (
+
+
+
+ );
+};
+
export const Failed = () => {
const attempt = {
isProcessing: false,
@@ -139,4 +147,6 @@ const sample = {
InviteCollaborators: null,
onEmailPasswordResetClose: () => null,
EmailPasswordReset: null,
+ showMauInfo: false,
+ onDismissUsersMauNotice: () => null,
};
diff --git a/web/packages/teleport/src/Users/Users.test.tsx b/web/packages/teleport/src/Users/Users.test.tsx
index a05f70bf8550f..154047002d29e 100644
--- a/web/packages/teleport/src/Users/Users.test.tsx
+++ b/web/packages/teleport/src/Users/Users.test.tsx
@@ -18,7 +18,7 @@
import React from 'react';
import { MemoryRouter } from 'react-router';
-import { render, screen } from 'design/utils/testing';
+import { render, screen, userEvent } from 'design/utils/testing';
import { ContextProvider } from 'teleport';
import { createTeleportContext } from 'teleport/mocks/contexts';
@@ -57,6 +57,8 @@ describe('invite collaborators integration', () => {
inviteCollaboratorsOpen: false,
onEmailPasswordResetClose: () => undefined,
EmailPasswordReset: null,
+ showMauInfo: false,
+ onDismissUsersMauNotice: () => null,
};
});
@@ -105,6 +107,55 @@ describe('invite collaborators integration', () => {
});
});
+test('Users not equal to MAU Notice', async () => {
+ const ctx = createTeleportContext();
+ let props: State;
+
+ props = {
+ attempt: {
+ message: 'success',
+ isSuccess: true,
+ isProcessing: false,
+ isFailed: false,
+ },
+ users: [],
+ fetchRoles: async () => [],
+ operation: { type: 'invite-collaborators' },
+ onStartCreate: () => undefined,
+ onStartDelete: () => undefined,
+ onStartEdit: () => undefined,
+ onStartReset: () => undefined,
+ onStartInviteCollaborators: () => undefined,
+ onClose: () => undefined,
+ onDelete: () => undefined,
+ onCreate: () => undefined,
+ onUpdate: () => undefined,
+ onReset: () => undefined,
+ onInviteCollaboratorsClose: () => undefined,
+ InviteCollaborators: null,
+ inviteCollaboratorsOpen: false,
+ onEmailPasswordResetClose: () => undefined,
+ EmailPasswordReset: null,
+ showMauInfo: true,
+ onDismissUsersMauNotice: jest.fn(),
+ };
+
+ const user = userEvent.setup();
+
+ render(
+
+
+
+
+
+ );
+
+ expect(screen.getByTestId('users-not-mau-alert')).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: 'Dismiss' }));
+ expect(props.onDismissUsersMauNotice).toHaveBeenCalled();
+ expect(screen.queryByTestId('users-not-mau-alert')).not.toBeInTheDocument();
+});
+
describe('email password reset integration', () => {
const ctx = createTeleportContext();
@@ -139,6 +190,8 @@ describe('email password reset integration', () => {
inviteCollaboratorsOpen: false,
onEmailPasswordResetClose: () => undefined,
EmailPasswordReset: null,
+ showMauInfo: false,
+ onDismissUsersMauNotice: () => null,
};
});
diff --git a/web/packages/teleport/src/Users/Users.tsx b/web/packages/teleport/src/Users/Users.tsx
index 220576e48d5ec..f36b8d70bf6d0 100644
--- a/web/packages/teleport/src/Users/Users.tsx
+++ b/web/packages/teleport/src/Users/Users.tsx
@@ -17,7 +17,7 @@
*/
import React from 'react';
-import { Indicator, Box, Alert, Button } from 'design';
+import { Indicator, Box, Alert, Button, Link } from 'design';
import {
FeatureBox,
@@ -46,6 +46,8 @@ export function Users(props: State) {
onStartDelete,
onStartEdit,
onStartReset,
+ showMauInfo,
+ onDismissUsersMauNotice,
onClose,
onCreate,
onUpdate,
@@ -98,6 +100,40 @@ export function Users(props: State) {
)}
+ {showMauInfo && (
+ theme.colors.buttons.link.default};
+ }
+ `}
+ >
+ The users displayed here are not an accurate reflection of Monthly
+ Active Users (MAU). For example, users who log in through Single
+ Sign-On (SSO) providers such as Okta may only appear here temporarily
+ and disappear once their sessions expire. For more information, read
+ our documentation on{' '}
+
+ MAU
+ {' '}
+ and{' '}
+
+ User Types
+
+ .
+
+ )}
{attempt.isFailed && }
{attempt.isSuccess && (
r.name);
}
+ function onDismissUsersMauNotice() {
+ storageService.setUsersMAUAcknowledged();
+ }
+
useEffect(() => {
attemptActions.do(() => ctx.userService.fetchUsers().then(setUsers));
}, []);
+ // if the cluster has billing enabled, and usageBasedBilling, and they haven't acknowledged
+ // the info yet
+ const showMauInfo =
+ ctx.getFeatureFlags().billing &&
+ cfg.isUsageBasedBilling &&
+ !storageService.getUsersMauAcknowledged();
+
return {
attempt,
users,
@@ -143,6 +156,8 @@ export default function useUsers({
inviteCollaboratorsOpen,
onEmailPasswordResetClose,
EmailPasswordReset,
+ showMauInfo,
+ onDismissUsersMauNotice,
};
}
diff --git a/web/packages/teleport/src/services/storageService/storageService.ts b/web/packages/teleport/src/services/storageService/storageService.ts
index af9a3601d9c46..644543046f59d 100644
--- a/web/packages/teleport/src/services/storageService/storageService.ts
+++ b/web/packages/teleport/src/services/storageService/storageService.ts
@@ -43,6 +43,7 @@ const KEEP_LOCALSTORAGE_KEYS_ON_LOGOUT = [
KeysEnum.USER_PREFERENCES,
KeysEnum.RECOMMEND_FEATURE,
KeysEnum.LICENSE_ACKNOWLEDGED,
+ KeysEnum.USERS_NOT_EQUAL_TO_MAU_ACKNOWLEDGED,
];
export const storageService = {
@@ -207,6 +208,21 @@ export const storageService = {
window.localStorage.setItem(KeysEnum.LICENSE_ACKNOWLEDGED, 'true');
},
+ getUsersMauAcknowledged(): boolean {
+ return (
+ window.localStorage.getItem(
+ KeysEnum.USERS_NOT_EQUAL_TO_MAU_ACKNOWLEDGED
+ ) === 'true'
+ );
+ },
+
+ setUsersMAUAcknowledged() {
+ window.localStorage.setItem(
+ KeysEnum.USERS_NOT_EQUAL_TO_MAU_ACKNOWLEDGED,
+ 'true'
+ );
+ },
+
broadcast(messageType, messageBody) {
window.localStorage.setItem(messageType, messageBody);
window.localStorage.removeItem(messageType);
diff --git a/web/packages/teleport/src/services/storageService/types.ts b/web/packages/teleport/src/services/storageService/types.ts
index d604d289bfa7e..71ad6d5992ab7 100644
--- a/web/packages/teleport/src/services/storageService/types.ts
+++ b/web/packages/teleport/src/services/storageService/types.ts
@@ -33,7 +33,8 @@ export const KeysEnum = {
EXTERNAL_AUDIT_STORAGE_CTA_DISABLED:
'grv_teleport_external_audit_storage_disabled',
LICENSE_ACKNOWLEDGED: 'grv_teleport_license_acknowledged',
-
+ USERS_NOT_EQUAL_TO_MAU_ACKNOWLEDGED:
+ 'grv_users_not_equal_to_mau_acknowledged',
LOCAL_NOTIFICATION_STATES: 'grv_teleport_notification_states',
};