Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b70254c
feat: add rrweb web-extension package
YunFeng0817 Oct 16, 2022
be295bd
refactor: make the extension suitable for manifest v3
YunFeng0817 Oct 17, 2022
6d7ae5d
update tsconfig.json
YunFeng0817 Oct 31, 2022
c99b049
use version_name rather than recorder_version in manifest.json
YunFeng0817 Oct 31, 2022
e87d539
update manifest.json
YunFeng0817 Nov 1, 2022
579d5b8
enable to keep recording after changing tabs
YunFeng0817 Nov 1, 2022
8739a6f
enable to record between tabs and urls
YunFeng0817 Nov 2, 2022
6fd4f2a
fix CI error
YunFeng0817 Nov 2, 2022
7fbc406
Merge branch 'master' into extension
YunFeng0817 Nov 2, 2022
3209471
try to fix CI error
YunFeng0817 Nov 2, 2022
f134ddc
feat: add pause and resume buttons
YunFeng0817 Nov 3, 2022
ab0b588
feat: add a link to new session after recording
YunFeng0817 Nov 3, 2022
0d633e5
improve session list
YunFeng0817 Nov 5, 2022
8246457
refactor: migrate session storage from chrome local storage to indexedDB
YunFeng0817 Nov 5, 2022
5fe51f1
feat: add pagination to session list
YunFeng0817 Nov 5, 2022
1266dae
fix: multiple recorders are started after pausing and resuming process
YunFeng0817 Nov 5, 2022
6186f6a
fix: can't stop recording on firefox browser
YunFeng0817 Nov 5, 2022
0c7e5ef
Merge remote-tracking branch 'origin/master' into extension
YunFeng0817 Nov 5, 2022
5340919
update type import of 'eventWithTime'
YunFeng0817 Nov 5, 2022
9670fd3
fix CI error
YunFeng0817 Nov 5, 2022
196082b
doc: add readme
YunFeng0817 Nov 5, 2022
558ec5d
Merge branch 'master' into extension
YunFeng0817 Nov 7, 2022
c0126c9
Apply suggestions from Justin's code review
YunFeng0817 Nov 12, 2022
2d35e10
refactor: make use of webNavigation API to implement recording consis…
YunFeng0817 Nov 12, 2022
2fbd399
fix firefox compatibility issue and add title to pages
YunFeng0817 Nov 12, 2022
4a56727
add mouseleave listener to enhance the recording liability
YunFeng0817 Nov 13, 2022
6abfb40
fix firefox compatibility issue and improve the experience of recordi…
YunFeng0817 Nov 13, 2022
c931c51
Merge branch 'master' into extension
YunFeng0817 Nov 13, 2022
da99bc2
update tsconfig
YunFeng0817 Nov 13, 2022
d65135c
upgrade vite-plugin-web-extension config to fix some bugs on facebook…
YunFeng0817 Nov 17, 2022
f08f334
update import links
YunFeng0817 Nov 17, 2022
46140be
refactor: cross tab recording mechanism
YunFeng0817 Nov 17, 2022
6665ca4
Merge branch 'master' into extension
YunFeng0817 Nov 18, 2022
36248e2
refactor: slipt util/index.ts into multiple files
YunFeng0817 Dec 1, 2022
d978ab6
implement cross-origin iframe recording
YunFeng0817 Dec 2, 2022
70e6155
fix: regression of issue: ShadowHost can't be a string (issue 941)
YunFeng0817 Jan 13, 2023
407a48a
refactor shadow dom recording to make tests cover key code
YunFeng0817 Jan 13, 2023
719ca76
Merge branch 'master' into extension
YunFeng0817 Jan 13, 2023
2409f76
Merge branch 'fix-shadow-dom-bug' into extension
YunFeng0817 Jan 17, 2023
1174194
Merge branch 'master' into extension
YunFeng0817 Feb 11, 2023
4e779f9
Apply formatting changes
Feb 11, 2023
36a8c00
increase the node memory limitation to avoid CI failure
YunFeng0817 Feb 11, 2023
6101714
Merge remote-tracking branch 'origin/master' into extension
YunFeng0817 Feb 12, 2023
1041fac
Create lovely-pears-cross.md
Juice10 Feb 13, 2023
1e4c582
Apply formatting changes
Juice10 Feb 13, 2023
86a88e0
Update packages/web-extension/package.json
Juice10 Feb 13, 2023
1f8a29a
Update .changeset/lovely-pears-cross.md
Juice10 Feb 13, 2023
3e5ab6f
Merge branch 'master' into extension
YunFeng0817 Feb 13, 2023
802b9b2
update change logs
YunFeng0817 Feb 13, 2023
832d7eb
delete duplicated property
YunFeng0817 Feb 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: migrate session storage from chrome local storage to indexedDB
  • Loading branch information
YunFeng0817 committed Nov 5, 2022
commit 824645708c7faa4807ed97ac378f07f3a87446a6
1 change: 1 addition & 0 deletions packages/web-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@emotion/styled": "^11.10.4",
"@tanstack/react-table": "^8.5.22",
"framer-motion": "^7.3.6",
"idb": "^7.1.1",
"mitt": "^3.0.0",
"nanoid": "^4.0.0",
"react": "^18.2.0",
Expand Down
19 changes: 4 additions & 15 deletions packages/web-extension/src/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ void (async () => {
return new Promise((resolve) => {
stopResponseCb = (response: RecordStoppedMessage) => {
stopResponseCb = undefined;
const session = saveEvents(response.events);
session.events = [];
response.session = session;
const newSession = generateSession();
response.session = newSession;
storedEvents = [];
resolve(response);
};
Expand Down Expand Up @@ -133,24 +132,14 @@ function startRecord() {
};
}

function saveEvents(events: eventWithTime[]) {
function generateSession() {
const newSession: Session = {
id: nanoid(),
name: document.title,
tags: [],
events,
createTimestamp: Date.now(),
modifyTimestamp: Date.now(),
recorderVersion: Browser.runtime.getManifest().version_name || 'unknown',
};
void Browser.storage.local.get(LocalDataKey.sessions).then((res) => {
const data = res as LocalData;
if (!data.sessions) data.sessions = {};
data.sessions[newSession.id] = newSession;
void Browser.storage.local.set(data);
});

return {
...newSession,
};
return newSession;
}
54 changes: 32 additions & 22 deletions packages/web-extension/src/pages/Player.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { useRef, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import Browser from 'webextension-polyfill';
import type rrwebPlayer from 'rrweb-player';
import rrwebPlayer from 'rrweb-player';
import Replayer from 'rrweb-player';
import { LocalData } from '../types';
import {
Box,
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
Center,
} from '@chakra-ui/react';
import { getEvents, getSession } from '../utils';

export default function Player() {
const playerElRef = useRef<HTMLDivElement>(null);
Expand All @@ -19,27 +18,38 @@ export default function Player() {
const [sessionName, setSessionName] = useState('');

useEffect(() => {
void Browser.storage.local.get().then((data) => {
if (!playerElRef.current || !sessionId) return;
const localData = data as LocalData;
const session = localData.sessions[sessionId];
if (!session) return;
setSessionName(session.name);
if (!sessionId) return;
getSession(sessionId)
.then((session) => {
setSessionName(session.name);
})
.catch((err) => {
console.error(err);
});
getEvents(sessionId)
.then((events) => {
if (!playerElRef.current || !sessionId) return;

const linkEl = document.createElement('link');
linkEl.href =
'https://cdn.jsdelivr.net/npm/[email protected]/dist/style.css';
linkEl.rel = 'stylesheet';
document.head.appendChild(linkEl);
playerRef.current = new Replayer({
target: playerElRef.current as HTMLElement,
props: {
events: session.events,
autoPlay: true,
},
const linkEl = document.createElement('link');
linkEl.href =
'https://cdn.jsdelivr.net/npm/[email protected]/dist/style.css';
linkEl.rel = 'stylesheet';
document.head.appendChild(linkEl);
playerRef.current = new Replayer({
target: playerElRef.current as HTMLElement,
props: {
events,
autoPlay: true,
},
});
})
.catch((err) => {
console.error(err);
});
});
}, []);
return () => {
playerRef.current?.pause();
};
}, [sessionId]);

return (
<>
Expand Down
63 changes: 30 additions & 33 deletions packages/web-extension/src/pages/SessionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import {
getSortedRowModel,
} from '@tanstack/react-table';
import { VscTriangleDown, VscTriangleUp } from 'react-icons/vsc';
import { LocalData, LocalDataKey, Session } from '../types';
import Browser from 'webextension-polyfill';
import { useNavigate } from 'react-router-dom';
import { Session, EventName } from '../types';
import Channel from '../utils/channel';
import { deleteSessions, getAllSessions } from '../utils';

const columnHelper = createColumnHelper<Session>();
const channel = new Channel();

export function SessionList() {
const [sessions, setSessions] = useState<Session[]>([]);
Expand Down Expand Up @@ -88,19 +90,15 @@ export function SessionList() {
},
});

const updateSessions = async () => {
const sessions = await getAllSessions();
setSessions(sessions);
};

useEffect(() => {
const getSessions = (sessions?: LocalData['sessions']) => {
if (!sessions) return;
const sessionArray = [];
for (const id in sessions) sessionArray.push(sessions[id]);
setSessions(sessionArray);
};
void Browser.storage.local
.get(LocalDataKey.sessions)
.then((data) => getSessions((data as LocalData).sessions));
Browser.storage.onChanged.addListener((changes, area) => {
if (area === 'local' && changes.sessions)
getSessions(changes.sessions.newValue as LocalData['sessions']);
void updateSessions();
channel.on(EventName.SessionUpdated, () => {
void updateSessions();
});
}, []);

Expand Down Expand Up @@ -179,27 +177,26 @@ export function SessionList() {
</TableContainer>
<Flex mt={4}>
<Spacer />
<Button
mr={4}
colorScheme="red"
onClick={() => {
if (table.getSelectedRowModel().flatRows.length === 0) return;
void Browser.storage.local
.get(LocalDataKey.sessions)
.then((data) => {
const sessions = (data as LocalData).sessions;
if (!sessions) return;
for (const row of table.getSelectedRowModel().flatRows)
delete sessions[row.original.id];
return Browser.storage.local.set({ sessions });
})
.then(() => {
{Object.keys(rowSelection).length > 0 && (
<Button
mr={4}
size="sm"
colorScheme="red"
onClick={() => {
if (table.getSelectedRowModel().flatRows.length === 0) return;
const ids = table
.getSelectedRowModel()
.flatRows.map((row) => row.original.id);
void deleteSessions(ids).then(() => {
setRowSelection({});
void updateSessions();
channel.emit(EventName.SessionUpdated, {});
});
}}
>
Delete
</Button>
}}
>
Delete
</Button>
)}
</Flex>
</>
);
Expand Down
9 changes: 8 additions & 1 deletion packages/web-extension/src/popup/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
RecordStartedMessage,
RecordStoppedMessage,
Session,
EventName,
} from '../types';
import Browser from 'webextension-polyfill';
import { CircleButton } from '../components/CircleButton';
import { Timer } from './Timer';
import { pauseRecording, resumeRecording } from '../utils';
import { pauseRecording, resumeRecording, saveSession } from '../utils';
const RECORD_BUTTON_SIZE = 3;

const channel = new Channel();
Expand Down Expand Up @@ -111,6 +112,12 @@ export function App() {
});
if (res.session) {
setNewSession(res.session);
await saveSession(res.session, res.events).catch(
(e) => {
setErrorMessage((e as { message: string }).message);
},
);
channel.emit(EventName.SessionUpdated, {});
}
})
.catch((error: Error) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/web-extension/src/popup/Timer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function Timer({
return () => clearInterval(interval);
}, [startTime, ticking]);
return (
<Stat textAlign="center">
<Stat textAlign="center" mt={4}>
<StatNumber fontSize="3xl">{formatTime(time)}</StatNumber>
</Stat>
);
Expand Down
7 changes: 4 additions & 3 deletions packages/web-extension/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ export type Settings = {
};

export enum LocalDataKey {
sessions = 'sessions',
recorderStatus = 'recorder_status',
bufferedEvents = 'buffered_events',
}

export type LocalData = {
[LocalDataKey.sessions]: Record<string, Session>;
[LocalDataKey.recorderStatus]: {
status: RecorderStatus;
activeTabId: number;
Expand All @@ -42,7 +40,6 @@ export type Session = {
id: string;
name: string;
tags: string[];
events: eventWithTime[];
createTimestamp: number;
modifyTimestamp: number;
recorderVersion: string;
Expand All @@ -55,6 +52,10 @@ export enum ServiceName {
ResumeRecord = 'resume-record',
}

export enum EventName {
SessionUpdated = 'session-updated',
}

export enum MessageName {
RecordScriptReady = 'rrweb-extension-record-script-ready',
StartRecord = 'rrweb-extension-start-record',
Expand Down
12 changes: 4 additions & 8 deletions packages/web-extension/src/utils/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ class Channel {
* @param event - event name
* @param detail - event detail
*/
public emit(eventName: string, detail: unknown) {
const message = JSON.stringify({ type: 'event', eventName, detail });
public emit(event: string, detail: unknown) {
const message = JSON.stringify({ type: 'event', event, detail });
void Browser.runtime.sendMessage(message);
}

Expand All @@ -155,11 +155,7 @@ class Channel {
* @param event - event name
* @param detail - event detail
*/
public emitToTabs(
tabIds: number | number[],
eventName: string,
detail: unknown,
) {
public emitToTabs(tabIds: number | number[], event: string, detail: unknown) {
if (!Browser.tabs || !Browser.tabs.sendMessage)
return Promise.reject('Can not send message to tabs in current context!');

Expand All @@ -168,7 +164,7 @@ class Channel {
tabIds = [tabIds];
}

const message = JSON.stringify({ type: 'event', eventName, detail });
const message = JSON.stringify({ type: 'event', event, detail });
tabIds.forEach((tabId) => void Browser.tabs.sendMessage(tabId, message));
}

Expand Down
Loading