diff --git a/api/types/accesslist/convert/v1/accesslist_test.go b/api/types/accesslist/convert/v1/accesslist_test.go
index 7dfc131435da0..5958934a04e64 100644
--- a/api/types/accesslist/convert/v1/accesslist_test.go
+++ b/api/types/accesslist/convert/v1/accesslist_test.go
@@ -42,12 +42,17 @@ func TestWithOwnersIneligibleStatusField(t *testing.T) {
Name: "dne",
IneligibleStatus: accesslistv1.IneligibleStatus_INELIGIBLE_STATUS_USER_NOT_EXIST,
},
+ {
+ Name: "unspecified",
+ IneligibleStatus: accesslistv1.IneligibleStatus_INELIGIBLE_STATUS_UNSPECIFIED,
+ },
}
owners := []accesslist.Owner{
{Name: "expired"},
{Name: "missing"},
{Name: "dne"},
+ {Name: "unspecified"},
}
al := &accesslist.AccessList{
Spec: accesslist.Spec{
@@ -72,6 +77,10 @@ func TestWithOwnersIneligibleStatusField(t *testing.T) {
Name: "dne",
IneligibleStatus: accesslistv1.IneligibleStatus_INELIGIBLE_STATUS_USER_NOT_EXIST.String(),
},
+ {
+ Name: "unspecified",
+ IneligibleStatus: "",
+ },
}))
}
diff --git a/web/packages/teleport/src/TopBar/Notifications/Notifications.test.tsx b/web/packages/teleport/src/TopBar/Notifications/Notifications.test.tsx
new file mode 100644
index 0000000000000..26b5f0d304d9c
--- /dev/null
+++ b/web/packages/teleport/src/TopBar/Notifications/Notifications.test.tsx
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2023 Gravitational, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { MemoryRouter } from 'react-router';
+import { render, screen } from 'design/utils/testing';
+
+import { createTeleportContext } from 'teleport/mocks/contexts';
+import { ContextProvider } from 'teleport';
+
+import {
+ StoreNotifications,
+ NotificationKind,
+} from 'teleport/stores/storeNotifications';
+
+import { Notifications } from './Notifications';
+
+beforeAll(() => {
+ jest.useFakeTimers();
+ jest.setSystemTime(new Date('2023-01-20'));
+});
+
+afterAll(() => {
+ jest.useRealTimers();
+});
+
+test('due dates and overdue dates', async () => {
+ const ctx = createTeleportContext();
+ const store = new StoreNotifications();
+
+ store.setNotifications([
+ {
+ item: {
+ kind: NotificationKind.AccessList,
+ resourceName: 'carrot',
+ route: '',
+ },
+ id: '1',
+ date: new Date('2023-01-25'),
+ },
+ // overdue 10 days
+ {
+ item: {
+ kind: NotificationKind.AccessList,
+ resourceName: 'carrot',
+ route: '',
+ },
+ id: '2',
+ date: new Date('2023-01-10'),
+ },
+ // overdue month
+ {
+ item: {
+ kind: NotificationKind.AccessList,
+ resourceName: 'carrot',
+ route: '',
+ },
+ id: '3',
+ date: new Date('2022-12-20'),
+ },
+ ]);
+
+ ctx.storeNotifications = store;
+
+ render(
+
+
+
+
+
+ );
+
+ // no need to click on button for render.
+ // it's already in the dom but hidden.
+
+ expect(screen.queryAllByTestId('note-item')).toHaveLength(3);
+
+ expect(
+ screen.getByText(/overdue for a review 10 days ago/i)
+ ).toBeInTheDocument();
+
+ expect(
+ screen.getByText(/overdue for a review about 1 month ago/i)
+ ).toBeInTheDocument();
+
+ expect(
+ screen.getByText(/needs your review within 5 days/i)
+ ).toBeInTheDocument();
+});
+
+test('no notes', async () => {
+ const ctx = createTeleportContext();
+
+ render(
+
+
+
+
+
+ );
+
+ // no need to click on button for render.
+ // it's already in the dom but hidden.
+
+ expect(screen.queryByTestId('note-item')).not.toBeInTheDocument();
+ expect(screen.getByText(/no notifications/i)).toBeInTheDocument();
+});
diff --git a/web/packages/teleport/src/TopBar/Notifications/Notifications.tsx b/web/packages/teleport/src/TopBar/Notifications/Notifications.tsx
index 650af19a086bc..647340e5e428c 100644
--- a/web/packages/teleport/src/TopBar/Notifications/Notifications.tsx
+++ b/web/packages/teleport/src/TopBar/Notifications/Notifications.tsx
@@ -60,6 +60,7 @@ export function Notifications() {
open={open}
$transitionDelay={currentTransitionDelay}
key={notice.id}
+ data-testid="note-item"
>
setOpen(false)} />
@@ -100,6 +101,15 @@ function NotificationItem({
notice: Notification;
close(): void;
}) {
+ const today = new Date();
+ const numDays = formatDistanceToNow(notice.date);
+
+ let dueText;
+ if (notice.date <= today) {
+ dueText = `was overdue for a review ${numDays} ago`;
+ } else {
+ dueText = `needs your review within ${numDays}`;
+ }
switch (notice.item.kind) {
case NotificationKind.AccessList:
return (
@@ -109,8 +119,7 @@ function NotificationItem({
- Access list {notice.item.resourceName} needs your review
- within {formatDistanceToNow(notice.date)}.
+ Access list {notice.item.resourceName} {dueText}.