From 8b52432a9a42c395604b03ab37f6ffbee409d006 Mon Sep 17 00:00:00 2001 From: Delirium Date: Mon, 25 Mar 2024 16:27:51 +0100 Subject: [PATCH] fix(ui): onboarding design fixes (#1993) * fix(ui): onboarding design fixes * more stuff * some assist details and options --- .../Integrations/AssistDoc/AssistNpm.tsx | 32 +- .../components/Client/Sites/NewSiteForm.tsx | 97 +++-- .../InsightsCard/InsightItem.tsx | 2 +- .../DashboardList/DashboardList.tsx | 2 +- .../IdentifyUsersTab/IdentifyUsersTab.tsx | 30 +- .../InstallOpenReplayTab.tsx | 12 +- .../IntegrationsTab/IntegrationsTab.tsx | 33 +- .../ManageUsersTab/ManageUsersTab.tsx | 8 +- .../OnboardingTabs/InstallDocs/InstallDocs.js | 45 ++- .../ui/Confirmation/Confirmation.js | 6 +- frontend/app/mstore/userStore.ts | 368 ++++++++++-------- tracker/tracker-assist/README.md | 24 +- 12 files changed, 410 insertions(+), 249 deletions(-) diff --git a/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx b/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx index 1e017a8a6..b839a7557 100644 --- a/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx +++ b/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx @@ -43,8 +43,36 @@ function MyApp() {
Options
{`trackerAssist({ - confirmText: string; -})`} + onAgentConnect: StartEndCallback; + onCallStart: StartEndCallback; + onRemoteControlStart: StartEndCallback; + onRecordingRequest?: (agentInfo: Record) => any; + onCallDeny?: () => any; + onRemoteControlDeny?: (agentInfo: Record) => any; + onRecordingDeny?: (agentInfo: Record) => any; + session_calling_peer_key: string; + session_control_peer_key: string; + callConfirm: ConfirmOptions; + controlConfirm: ConfirmOptions; + recordingConfirm: ConfirmOptions; + socketHost?: string; + config: RTCConfiguration; + serverURL: string + callUITemplate?: string; +}) + +type ConfirmOptions = { + text?:string, + style?: StyleObject, // style object (i.e {color: 'red', borderRadius: '10px'}) + confirmBtn?: ButtonOptions, + declineBtn?: ButtonOptions +} + +type ButtonOptions = HTMLButtonElement | string | { + innerHTML?: string, // to pass an svg string or text + style?: StyleObject, // style object (i.e {color: 'red', borderRadius: '10px'}) +} +`} ); diff --git a/frontend/app/components/Client/Sites/NewSiteForm.tsx b/frontend/app/components/Client/Sites/NewSiteForm.tsx index db7f5fb28..3291f3218 100644 --- a/frontend/app/components/Client/Sites/NewSiteForm.tsx +++ b/frontend/app/components/Client/Sites/NewSiteForm.tsx @@ -1,17 +1,20 @@ -import React, { useState, useEffect, ChangeEvent, FormEvent } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; -import { Form, Input, Button, Icon, SegmentSelection } from 'UI'; -import { save, edit, update, fetchList, remove } from 'Duck/site'; -import { pushNewSite } from 'Duck/user'; -import { setSiteId } from 'Duck/site'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; -import styles from './siteForm.module.css'; -import { confirm } from 'UI'; -import { clearSearch } from 'Duck/search'; -import { clearSearch as clearSearchLive } from 'Duck/liveSearch'; -import { withStore } from 'App/mstore'; +import { Segmented } from 'antd'; +import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; +import { ConnectedProps, connect } from 'react-redux'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; import { toast } from 'react-toastify'; +import { withStore } from 'App/mstore'; +import { clearSearch as clearSearchLive } from 'Duck/liveSearch'; +import { clearSearch } from 'Duck/search'; +import { edit, fetchList, remove, save, update } from 'Duck/site'; +import { setSiteId } from 'Duck/site'; +import { pushNewSite } from 'Duck/user'; +import { Button, Form, Icon, Input, SegmentSelection } from 'UI'; +import { confirm } from 'UI'; + +import styles from './siteForm.module.css'; + type OwnProps = { onClose: (arg: any) => void; mstore: any; @@ -81,8 +84,10 @@ const NewSiteForm = ({ const handleRemove = async () => { if ( await confirm({ - header: 'Projects', - confirmation: `Are you sure you want to delete this Project? We won't be able to record anymore sessions.`, + header: 'Project Deletion Alert', + confirmation: `Are you sure you want to delete this project? Deleting it will permanently remove the project, along with all associated sessions and data.`, + confirmButton: 'Yes, delete', + cancelButton: 'Cancel', }) ) { remove(site.id).then(() => { @@ -94,15 +99,25 @@ const NewSiteForm = ({ } }; - const handleEdit = ({ target: { name, value } }: ChangeEvent) => { + const handleEdit = ({ + target: { name, value }, + }: ChangeEvent) => { setExistsError(false); edit({ [name]: value }); }; return ( -
-

{site.exists() ? 'Edit Project' : 'New Project'}

-
+
+

+ {site.exists() ? 'Edit Project' : 'New Project'} +

+
@@ -117,17 +132,24 @@ const NewSiteForm = ({ - { - edit({ platform: value }); - }} - /> +
+ { + edit({ platform: value }); + }} + /> +
)}
- {existsError &&
{'Project exists already.'}
} + {existsError && ( +
+ {'Project exists already.'} +
+ )}
@@ -156,7 +187,9 @@ const mapStateToProps = (state: any) => ({ activeSiteId: state.getIn(['site', 'active', 'id']), site: state.getIn(['site', 'instance']), siteList: state.getIn(['site', 'list']), - loading: state.getIn(['site', 'save', 'loading']) || state.getIn(['site', 'remove', 'loading']), + loading: + state.getIn(['site', 'save', 'loading']) || + state.getIn(['site', 'remove', 'loading']), canDelete: state.getIn(['site', 'list']).size > 1, }); diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/InsightsCard/InsightItem.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/InsightsCard/InsightItem.tsx index c8acf5c1a..cf827aa80 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/InsightsCard/InsightItem.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/InsightsCard/InsightItem.tsx @@ -11,7 +11,7 @@ interface Props { function InsightItem(props: Props) { const { item, onClick = () => {} } = props; const className = - 'whitespace-nowrap flex items-center py-4 hover:bg-active-blue -mx-4 px-4 border-b last:border-transparent cursor-pointer'; + 'flex items-start flex-wrap py-4 hover:bg-active-blue -mx-4 px-4 border-b last:border-transparent cursor-pointer'; switch (item.category) { case IssueCategory.RAGE: diff --git a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx index beecb7c63..9651ba90c 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx @@ -34,7 +34,7 @@ function DashboardList() {
Title
Visibility
-
Creation Date
+
Last Modified
{sliceListPerPage(list, dashboardStore.page - 1, dashboardStore.pageSize).map( diff --git a/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.tsx b/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.tsx index 21a5d623e..b3322b6b6 100644 --- a/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.tsx +++ b/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.tsx @@ -7,6 +7,7 @@ import DocCard from 'Shared/DocCard/DocCard'; import withOnboarding, { WithOnboardingProps } from '../withOnboarding'; import { OB_TABS } from 'App/routes'; import withPageTitle from 'App/components/hocs/withPageTitle'; +import { Button as AntButton } from 'antd' interface Props extends WithOnboardingProps { platforms: Array<{ @@ -41,13 +42,14 @@ function IdentifyUsersTab(props: Props) { href={`https://docs.openreplay.com/en/installation/identify-user${platform.value === "web" ? "/#with-npm" : "/#with-ios-app"}`} target="_blank" > - + + +
See Documentation
+
- Your platform + Project Type ) : ( - - )} + + )} {platform.value === 'web' ? (
@@ -121,11 +123,11 @@ function IdentifyUsersTab(props: Props) { {platform.value === 'web' ? ( ) : ( - - )} + + )}
diff --git a/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.tsx b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.tsx index 66fa8a092..448ed2d9e 100644 --- a/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.tsx +++ b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.tsx @@ -8,6 +8,7 @@ import { WithOnboardingProps } from '../withOnboarding'; import { OB_TABS } from 'App/routes'; import withPageTitle from 'App/components/hocs/withPageTitle'; import { Segmented } from 'antd'; +import { Button as AntButton } from 'antd' interface Props extends WithOnboardingProps { platforms: Array<{ @@ -39,14 +40,15 @@ function InstallOpenReplayTab(props: Props) { - - + + + +
See Documentation
+
- Your platform + Project Type Integrations
- - + + + +
See Documentation
+
-
@@ -30,4 +45,6 @@ function IntegrationsTab(props: Props) { ); } -export default withOnboarding(withPageTitle("Integrations - OpenReplay")(IntegrationsTab)); +export default withOnboarding( + withPageTitle('Integrations - OpenReplay')(IntegrationsTab) +); diff --git a/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.tsx b/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.tsx index 381fe3b0a..60984a602 100644 --- a/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.tsx +++ b/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.tsx @@ -5,6 +5,7 @@ import { Button, Icon } from 'UI'; import withOnboarding, { WithOnboardingProps } from '../withOnboarding'; import { OB_TABS } from 'App/routes'; import withPageTitle from 'App/components/hocs/withPageTitle'; +import { Button as AntButton } from 'antd' interface Props extends WithOnboardingProps {} @@ -21,9 +22,10 @@ function ManageUsersTab(props: Props) { href="https://docs.openreplay.com/en/tutorials/adding-users/" target="_blank" > - + + +
See Documentation
+
diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js index c8ff3f788..031c7b2e8 100644 --- a/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js @@ -36,7 +36,7 @@ function InstallDocs({ site }) { const [isSpa, setIsSpa] = useState(true); return (
-
+
Install the npm package. @@ -48,7 +48,7 @@ function InstallDocs({ site }) { {installationCommand}
-
+
Continue with one of the following options. @@ -87,7 +87,9 @@ function InstallDocs({ site }) {
Otherwise, if your web app is Server-Side-Rendered (SSR) (i.e. - NextJS, NuxtJS) use this snippet: + NextJS, NuxtJS),{' '} + consider async imports + or cjs version of the library:
@@ -100,6 +102,43 @@ function InstallDocs({ site }) {
+ +
+
+ + Enable Assist (Optional) +
+
+
+
+
+ Install the plugin via npm: +
+
+
+ +
+ {`$ npm i @openreplay/tracker-assist`} +
+
+
+
+ Then enable it with your tracker: +
+
+
+ +
+ {`tracker.use(trackerAssist(options));`} +
+
Read more about available options here. +
+
+
+
+
); } diff --git a/frontend/app/components/ui/Confirmation/Confirmation.js b/frontend/app/components/ui/Confirmation/Confirmation.js index ad77ab7ad..7a2e27e5a 100644 --- a/frontend/app/components/ui/Confirmation/Confirmation.js +++ b/frontend/app/components/ui/Confirmation/Confirmation.js @@ -1,8 +1,8 @@ import React from 'react'; -import { Button} from 'UI'; import { confirmable } from 'react-confirm'; import { Modal } from 'UI' - +import { Button } from 'antd' + const Confirmation = ({ show, proceed, @@ -31,7 +31,7 @@ const Confirmation = ({