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 = ({
proceed(true)}
- variant="primary"
+ type={'primary'}
className="mr-2"
>
{confirmButton}
diff --git a/frontend/app/mstore/userStore.ts b/frontend/app/mstore/userStore.ts
index d38a2ba5a..cf74f6805 100644
--- a/frontend/app/mstore/userStore.ts
+++ b/frontend/app/mstore/userStore.ts
@@ -1,184 +1,212 @@
-import { makeAutoObservable, observable, action } from "mobx"
-import User from "./types/user";
-import { userService } from "App/services";
-import { toast } from 'react-toastify';
import copy from 'copy-to-clipboard';
+import { action, makeAutoObservable, observable } from 'mobx';
+import { toast } from 'react-toastify';
+
+import { userService } from 'App/services';
+
+import User from './types/user';
export default class UserStore {
- list: User[] = [];
- instance: User|null = null;
- page: number = 1;
- pageSize: number = 10;
- searchQuery: string = "";
- modifiedCount: number = 0;
+ list: User[] = [];
+ instance: User | null = null;
+ page: number = 1;
+ pageSize: number = 10;
+ searchQuery: string = '';
+ modifiedCount: number = 0;
- loading: boolean = false;
- saving: boolean = false;
- limits: any = {};
- initialDataFetched: boolean = false;
+ loading: boolean = false;
+ saving: boolean = false;
+ limits: any = {};
+ initialDataFetched: boolean = false;
- constructor() {
- makeAutoObservable(this, {
- instance: observable,
- updateUser: action,
- updateKey: action,
- initUser: action,
- setLimits: action,
+ constructor() {
+ makeAutoObservable(this, {
+ instance: observable,
+ updateUser: action,
+ updateKey: action,
+ initUser: action,
+ setLimits: action,
+ });
+ }
+
+ fetchLimits(): Promise {
+ return new Promise((resolve, reject) => {
+ userService
+ .getLimits()
+ .then((response: any) => {
+ this.setLimits(response);
+ resolve(response);
})
- }
-
- fetchLimits(): Promise {
- return new Promise((resolve, reject) => {
- userService.getLimits()
- .then((response: any) => {
- this.setLimits(response);
- resolve(response);
- }).catch((error: any) => {
- reject(error);
- });
+ .catch((error: any) => {
+ reject(error);
});
- }
+ });
+ }
- setLimits(limits: any) {
- this.limits = limits;
- }
+ setLimits(limits: any) {
+ this.limits = limits;
+ }
- initUser(user?: any ): Promise {
- return new Promise((resolve) => {
- if (user) {
- this.instance = new User().fromJson(user.toJson());
- } else {
- this.instance = new User();
- }
- resolve();
+ initUser(user?: any): Promise {
+ return new Promise((resolve) => {
+ if (user) {
+ this.instance = new User().fromJson(user.toJson());
+ } else {
+ this.instance = new User();
+ }
+ resolve();
+ });
+ }
+
+ updateKey(key: keyof this, value: any) {
+ this[key] = value;
+
+ if (key === 'searchQuery') {
+ this.page = 1;
+ }
+ }
+
+ updateUser(user: User) {
+ const index = this.list.findIndex((u) => u.userId === user.userId);
+ if (index > -1) {
+ this.list[index] = user;
+ }
+ }
+
+ fetchUser(userId: string): Promise {
+ this.loading = true;
+ return new Promise((resolve, reject) => {
+ userService
+ .one(userId)
+ .then((response) => {
+ this.instance = new User().fromJson(response.data);
+ resolve(response);
})
- }
-
- updateKey(key: keyof this, value: any) {
- this[key] = value
-
- if (key === 'searchQuery') {
- this.page = 1
- }
- }
-
- updateUser(user: User) {
- const index = this.list.findIndex(u => u.userId === user.userId);
- if (index > -1) {
- this.list[index] = user;
- }
- }
-
- fetchUser(userId: string): Promise {
- this.loading = true;
- return new Promise((resolve, reject) => {
- userService.one(userId)
- .then(response => {
- this.instance = new User().fromJson(response.data);
- resolve(response);
- }).catch(error => {
- this.loading = false;
- reject(error);
- }).finally(() => {
- this.loading = false;
- });
- });
- }
-
- fetchUsers(): Promise {
- this.loading = true;
- return new Promise((resolve, reject) => {
- userService.all()
- .then(response => {
- this.list = response.map(user => new User().fromJson(user));
- resolve(response);
- }).catch(error => {
- this.loading = false;
- reject(error);
- }).finally(() => {
- this.loading = false;
- });
- });
- }
-
- saveUser(user: User): Promise {
- this.saving = true;
- const wasCreating = !user.userId;
- return new Promise((resolve, reject) => {
- userService.save(user).then(response => {
- const newUser = new User().fromJson(response);
- if (wasCreating) {
- this.modifiedCount -= 1;
- this.list.push(newUser);
- toast.success('User created successfully');
- } else {
- this.updateUser(newUser);
- toast.success('User updated successfully');
- }
- resolve(response);
- }).catch(async (e) => {
- const err = await e.response?.json();
- this.saving = false;
- toast.error(err.errors[0] ? err.errors[0] : 'Error saving user');
- reject(e);
- }).finally(() => {
- this.saving = false;
- });
- });
- }
-
- deleteUser(userId: string): Promise {
- this.saving = true;
- return new Promise((resolve, reject) => {
- userService.delete(userId)
- .then(response => {
- this.modifiedCount += 1;
- this.list = this.list.filter(user => user.userId !== userId);
- resolve(response);
- }).catch(error => {
- this.saving = false;
- toast.error('Error deleting user');
- reject(error);
- }).finally(() => {
- this.saving = false;
- });
- });
- }
-
- copyInviteCode(userId: string): void {
- const content = this.list.find(u => u.userId === userId)?.invitationLink;
- if (content) {
- copy(content);
- toast.success('Invite code copied successfully');
- } else {
- toast.error('Invite code not found');
- }
- }
-
- generateInviteCode(userId: string): Promise {
- this.saving = true;
- const promise = new Promise((resolve, reject) => {
- userService.generateInviteCode(userId)
- .then(response => {
- const index = this.list.findIndex(u => u.userId === userId);
- if (index > -1) {
- this.list[index].updateKey('isExpiredInvite', false);
- this.list[index].updateKey('invitationLink', response.invitationLink);
- }
- resolve(response);
- }).catch(error => {
- this.saving = false;
- reject(error);
- }).finally(() => {
- this.saving = false;
- });
- });
-
- toast.promise(promise, {
- pending: 'Generating an invite code...',
- success: 'Invite code generated successfully',
+ .catch((error) => {
+ this.loading = false;
+ reject(error);
})
+ .finally(() => {
+ this.loading = false;
+ });
+ });
+ }
- return promise;
+ fetchUsers(): Promise {
+ this.loading = true;
+ return new Promise((resolve, reject) => {
+ userService
+ .all()
+ .then((response) => {
+ this.list = response.map((user) => new User().fromJson(user));
+ resolve(response);
+ })
+ .catch((error) => {
+ this.loading = false;
+ reject(error);
+ })
+ .finally(() => {
+ this.loading = false;
+ });
+ });
+ }
+
+ saveUser(user: User): Promise {
+ this.saving = true;
+ const wasCreating = !user.userId;
+ return new Promise((resolve, reject) => {
+ userService
+ .save(user)
+ .then((response) => {
+ const newUser = new User().fromJson(response);
+ if (wasCreating) {
+ this.modifiedCount -= 1;
+ this.list.push(newUser);
+ toast.success('User created successfully');
+ } else {
+ this.updateUser(newUser);
+ toast.success('User updated successfully');
+ }
+ resolve(response);
+ })
+ .catch(async (e) => {
+ const err = await e.response?.json();
+ this.saving = false;
+ const errStr = err.errors[0]
+ ? err.errors[0].includes('already exists')
+ ? `This email is already linked to an account or team on OpenReplay and can't be used again.`
+ : err.errors[0]
+ : 'Error saving user';
+ toast.error(errStr);
+ reject(e);
+ })
+ .finally(() => {
+ this.saving = false;
+ });
+ });
+ }
+
+ deleteUser(userId: string): Promise {
+ this.saving = true;
+ return new Promise((resolve, reject) => {
+ userService
+ .delete(userId)
+ .then((response) => {
+ this.modifiedCount += 1;
+ this.list = this.list.filter((user) => user.userId !== userId);
+ resolve(response);
+ })
+ .catch((error) => {
+ this.saving = false;
+ toast.error('Error deleting user');
+ reject(error);
+ })
+ .finally(() => {
+ this.saving = false;
+ });
+ });
+ }
+
+ copyInviteCode(userId: string): void {
+ const content = this.list.find((u) => u.userId === userId)?.invitationLink;
+ if (content) {
+ copy(content);
+ toast.success('Invite code copied successfully');
+ } else {
+ toast.error('Invite code not found');
}
+ }
+
+ generateInviteCode(userId: string): Promise {
+ this.saving = true;
+ const promise = new Promise((resolve, reject) => {
+ userService
+ .generateInviteCode(userId)
+ .then((response) => {
+ const index = this.list.findIndex((u) => u.userId === userId);
+ if (index > -1) {
+ this.list[index].updateKey('isExpiredInvite', false);
+ this.list[index].updateKey(
+ 'invitationLink',
+ response.invitationLink
+ );
+ }
+ resolve(response);
+ })
+ .catch((error) => {
+ this.saving = false;
+ reject(error);
+ })
+ .finally(() => {
+ this.saving = false;
+ });
+ });
+
+ toast.promise(promise, {
+ pending: 'Generating an invite code...',
+ success: 'Invite code generated successfully',
+ });
+
+ return promise;
+ }
}
diff --git a/tracker/tracker-assist/README.md b/tracker/tracker-assist/README.md
index 662e1e084..ad265ab89 100644
--- a/tracker/tracker-assist/README.md
+++ b/tracker/tracker-assist/README.md
@@ -61,14 +61,24 @@ function MyApp() {
#### Options
-```js
+```ts
trackerAssist({
- callConfirm?: string|ConfirmOptions;
- controlConfirm?: string|ConfirmOptions;
- config?: object;
- onAgentConnect?: () => (()=>void | void);
- onCallStart?: () => (()=>void | void);
- onRemoteControlStart?: () => (()=>void | void);
+ 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;
})
```