From 1df308d072d95855d883f5d68d3719309d43791a Mon Sep 17 00:00:00 2001 From: Miciah Henderson <48624788+kiahjh@users.noreply.github.com> Date: Fri, 29 Dec 2023 12:23:42 -0500 Subject: [PATCH 1/3] dash: made highlighting activity during suspension optional --- dash/app/cypress/e2e/onboarding.cy.ts | 1 + dash/app/src/components/routes/User.tsx | 4 ++ dash/app/src/reducers/user-reducer.ts | 4 ++ dash/components/src/Users/EditUser.tsx | 37 +++++++++++++++++-- storybook/src/dash/Users/EditUser.stories.tsx | 8 ++-- 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/dash/app/cypress/e2e/onboarding.cy.ts b/dash/app/cypress/e2e/onboarding.cy.ts index 58943ee4..f12b5072 100644 --- a/dash/app/cypress/e2e/onboarding.cy.ts +++ b/dash/app/cypress/e2e/onboarding.cy.ts @@ -9,6 +9,7 @@ describe(`dashboard onboarding nudges`, () => { screenshotsEnabled: false, screenshotsResolution: 1200, screenshotsFrequency: 30, + showSuspensionActivity: true, keychains: [], devices: [], createdAt: new Date().toISOString(), diff --git a/dash/app/src/components/routes/User.tsx b/dash/app/src/components/routes/User.tsx index 4807d1cb..e372c4a0 100644 --- a/dash/app/src/components/routes/User.tsx +++ b/dash/app/src/components/routes/User.tsx @@ -101,6 +101,10 @@ const UserRoute: React.FC = () => { setScreenshotsFrequency={(frequency) => dispatch({ type: `setScreenshotsFrequency`, frequency }) } + showSuspensionActivity={draft.showSuspensionActivity} + setShowSuspensionActivity={(show) => + dispatch({ type: `setShowSuspensionActivity`, show }) + } removeKeychain={(id) => dispatch({ type: `removeKeychain`, id })} keychains={draft.keychains} devices={original.devices.map(deviceProps)} diff --git a/dash/app/src/reducers/user-reducer.ts b/dash/app/src/reducers/user-reducer.ts index 80b67a65..14650bfb 100644 --- a/dash/app/src/reducers/user-reducer.ts +++ b/dash/app/src/reducers/user-reducer.ts @@ -15,6 +15,7 @@ export type Action = | { type: 'setScreenshotsResolution'; resolution: number } | { type: 'setScreenshotsFrequency'; frequency: number } | { type: 'setKeyloggingEnabled'; enabled: boolean } + | { type: 'setShowSuspensionActivity'; show: boolean } | { type: 'removeKeychain'; id: UUID } | { type: 'addKeychain'; keychain: KeychainSummary } | { type: 'setAddingKeychain'; keychain?: KeychainSummary | null }; @@ -50,6 +51,9 @@ function reducer(state: State, action: Action): State | undefined { case `setScreenshotsFrequency`: state.user.draft.screenshotsFrequency = action.frequency; return; + case `setShowSuspensionActivity`: + state.user.draft.showSuspensionActivity = action.show; + return; case `removeKeychain`: state.user.draft.keychains = state.user.draft.keychains.filter( (keychain) => keychain.id !== action.id, diff --git a/dash/components/src/Users/EditUser.tsx b/dash/components/src/Users/EditUser.tsx index 2c9c29dc..611eeaae 100644 --- a/dash/components/src/Users/EditUser.tsx +++ b/dash/components/src/Users/EditUser.tsx @@ -24,6 +24,8 @@ interface Props { setScreenshotsResolution(resolution: number): unknown; screenshotsFrequency: number; setScreenshotsFrequency(frequency: number): unknown; + showSuspensionActivity: boolean; + setShowSuspensionActivity(show: boolean): unknown; removeKeychain(id: UUID): unknown; keychains: Keychain[]; devices: Subcomponents; @@ -56,6 +58,8 @@ const EditUser: React.FC = ({ setScreenshotsResolution, screenshotsFrequency, setScreenshotsFrequency, + showSuspensionActivity, + setShowSuspensionActivity, removeKeychain, keychains, devices, @@ -184,8 +188,10 @@ const EditUser: React.FC = ({

Monitoring

-

Enable keylogging

-

+

+ Enable keylogging +

+

Sends reports of all keystrokes to your review

@@ -196,8 +202,10 @@ const EditUser: React.FC = ({ >
-

Enable screenshots

-

+

+ Enable screenshots +

+

Periodically take a screenshot and upload for your review

@@ -228,7 +236,28 @@ const EditUser: React.FC = ({ />
+
+
+

+ Highlight activity during filter suspensions +

+

+ Visually highlight activity that is recorded while filter is suspended +

+
+ +
+

Keychains

diff --git a/storybook/src/dash/Users/EditUser.stories.tsx b/storybook/src/dash/Users/EditUser.stories.tsx index 66390737..d299eb9d 100644 --- a/storybook/src/dash/Users/EditUser.stories.tsx +++ b/storybook/src/dash/Users/EditUser.stories.tsx @@ -17,15 +17,15 @@ export const Default: Story = props({ id: `1`, isNew: false, name: `Little Jimmy`, - setName: () => {}, - keyloggingEnabled: false, - setKeyloggingEnabled: () => {}, - screenshotsEnabled: false, + keyloggingEnabled: true, + screenshotsEnabled: true, setScreenshotsEnabled: () => {}, screenshotsFrequency: 120, setScreenshotsFrequency: () => {}, screenshotsResolution: 1000, setScreenshotsResolution: () => {}, + showSuspensionActivity: true, + setShowSuspensionActivity: () => {}, saveButtonDisabled: true, onSave: () => {}, onConfirmAddKeychain: () => {}, From f0a25db1b1f4904dbee3e3e8b6ec389b419c0ee0 Mon Sep 17 00:00:00 2001 From: Miciah Henderson <48624788+kiahjh@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:01:17 -0500 Subject: [PATCH 2/3] dash: added tests to make sure suspension activity indicator is hidden for opted-out users --- dash/app/cypress/e2e/activity.cy.ts | 21 ++++++-- .../routes/CombinedUsersActivityFeed.tsx | 1 + .../components/routes/UserActivityFeed.tsx | 1 + .../Activity/CombinedUsersActivityFeed.tsx | 49 +++++++++++-------- .../Activity/DeletableActivityChunks.tsx | 37 +++++++++----- .../src/Users/Activity/UserActivityFeed.tsx | 3 ++ .../Activity/UserActivityFeed.stories.tsx | 1 + storybook/src/story-helpers.ts | 19 ++++--- 8 files changed, 90 insertions(+), 42 deletions(-) diff --git a/dash/app/cypress/e2e/activity.cy.ts b/dash/app/cypress/e2e/activity.cy.ts index d0c6ae67..186ee598 100644 --- a/dash/app/cypress/e2e/activity.cy.ts +++ b/dash/app/cypress/e2e/activity.cy.ts @@ -33,17 +33,21 @@ describe(`activity screens`, () => { it(`activity feed displays items in correct order`, () => { cy.interceptPql(`CombinedUsersActivityFeed`, [ { + showSuspensionActivity: false, userName: `Bob`, numDeleted: 0, - items: [mock.screenshotActivityItem({ id: `screenshot-123` })], + items: [ + mock.screenshotActivityItem({ id: `screenshot-123`, duringSuspension: true }), + ], }, { + showSuspensionActivity: true, userName: `Suzy`, numDeleted: 1, items: [ mock.screenshotActivityItem({ id: `screenshot-234` }), - mock.screenshotActivityItem({ id: `screenshot-345` }), - mock.screenshotActivityItem({ id: `screenshot-456` }), + mock.screenshotActivityItem({ id: `screenshot-345`, duringSuspension: true }), + mock.screenshotActivityItem({ id: `screenshot-456`, duringSuspension: true }), mock.keystrokeActivityItem({ id: `ks-1`, ids: [`ks-1`, `ks-2`, `ks-3`], // <-- aggregated ids @@ -66,6 +70,13 @@ describe(`activity screens`, () => { cy.testId(`page-heading`).first().should(`have.text`, `Suzy’s Activity`); cy.testId(`page-heading`).last().should(`have.text`, `Bob’s Activity`); + cy.testId(`single-user-sub-feed`).first().contains(`During filter suspension`); + // bob has `showSuspensionActivity: false`, so his feed should not have any highlighted suspension items + cy.testId(`single-user-sub-feed`) + .last() + .contains(`During filter suspension`) + .should(`not.exist`); + cy.contains(`Approve all child activity`).click(); cy.wait(`@DeleteActivityItems_v2`) @@ -92,11 +103,13 @@ describe(`activity screens`, () => { ); cy.interceptPql(`CombinedUsersActivityFeed`, [ { + showSuspensionActivity: true, userName: `suzy`, numDeleted: 0, items: suzysItems, }, { + showSuspensionActivity: true, userName: `jimmy`, numDeleted: 0, items: Array.from({ length: 130 }, (_, i) => @@ -117,11 +130,13 @@ describe(`activity screens`, () => { cy.interceptPql(`CombinedUsersActivityFeed`, [ { + showSuspensionActivity: true, userName: `suzy`, numDeleted: 0, items: suzysItems, }, { + showSuspensionActivity: true, userName: `jimmy`, numDeleted: 0, // vv -- only 30 remain diff --git a/dash/app/src/components/routes/CombinedUsersActivityFeed.tsx b/dash/app/src/components/routes/CombinedUsersActivityFeed.tsx index 3a5937ca..377667e6 100644 --- a/dash/app/src/components/routes/CombinedUsersActivityFeed.tsx +++ b/dash/app/src/components/routes/CombinedUsersActivityFeed.tsx @@ -50,6 +50,7 @@ const CombinedUsersActivityFeedRoute: React.FC = () => { .filter((user) => user.items.length > 0) .map((user) => ({ userName: user.userName, + highlightSuspensionActivity: user.showSuspensionActivity, items: user.items.map(outputItemToActivityFeedItem), }))} numDeleted={query.data.reduce((acc, user) => acc + user.numDeleted, 0)} diff --git a/dash/app/src/components/routes/UserActivityFeed.tsx b/dash/app/src/components/routes/UserActivityFeed.tsx index e1b99e81..2fe93c85 100644 --- a/dash/app/src/components/routes/UserActivityFeed.tsx +++ b/dash/app/src/components/routes/UserActivityFeed.tsx @@ -51,6 +51,7 @@ const UserActivityFeedRoute: React.FC = () => { items={query.data.items .map(outputItemToActivityFeedItem) .filter((item) => !item.deleted)} + highlightSuspsensionActivity={query.data.showSuspensionActivity} /> ); }; diff --git a/dash/components/src/Users/Activity/CombinedUsersActivityFeed.tsx b/dash/components/src/Users/Activity/CombinedUsersActivityFeed.tsx index 60a7097b..3fbf78ab 100644 --- a/dash/components/src/Users/Activity/CombinedUsersActivityFeed.tsx +++ b/dash/components/src/Users/Activity/CombinedUsersActivityFeed.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import cx from 'classnames'; import { Button } from '@shared/components'; import { posessive } from '@shared/string'; import type { ActivityFeedItem } from './UserActivityFeed'; @@ -11,7 +12,11 @@ import UserActivityHeader from './UserActivityHeader'; interface Props { date: Date; - activity: Array<{ userName: string; items: ActivityFeedItem[] }>; + activity: Array<{ + userName: string; + highlightSuspensionActivity: boolean; + items: ActivityFeedItem[]; + }>; numDeleted: number; deleteItems(ids: UUID[]): unknown; chunkSize?: number; @@ -51,30 +56,34 @@ const CombinedUsersActivityFeed: React.FC = ({ {items.length > 0 ? ( - {activity.map(({ userName, items }) => ( + {activity.map(({ userName, highlightSuspensionActivity, items }) => (
{userName} - - {items.length > 1 && ( -
- -
- )} +
+ + {items.length > 1 && ( +
+ +
+ )} +
))}