added deviceId, ExtensionStore, working on CoursePopup

This commit is contained in:
Sriram Hariharan
2023-03-04 20:33:35 -06:00
parent e99ba5864a
commit 46282a0406
15 changed files with 119 additions and 49 deletions

51
package-lock.json generated
View File

@@ -13,7 +13,8 @@
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"sass": "^1.57.1" "sass": "^1.57.1",
"uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",
@@ -10027,6 +10028,15 @@
"which": "^2.0.2" "which": "^2.0.2"
} }
}, },
"node_modules/node-notifier/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.8", "version": "2.0.8",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
@@ -15272,6 +15282,15 @@
"websocket-driver": "^0.7.4" "websocket-driver": "^0.7.4"
} }
}, },
"node_modules/sockjs/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/source-list-map": { "node_modules/source-list-map": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@@ -16683,10 +16702,9 @@
} }
}, },
"node_modules/uuid": { "node_modules/uuid": {
"version": "8.3.2", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"dev": true,
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@@ -24729,6 +24747,14 @@
"shellwords": "^0.1.1", "shellwords": "^0.1.1",
"uuid": "^8.3.0", "uuid": "^8.3.0",
"which": "^2.0.2" "which": "^2.0.2"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
}
} }
}, },
"node-releases": { "node-releases": {
@@ -28540,6 +28566,14 @@
"faye-websocket": "^0.11.3", "faye-websocket": "^0.11.3",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"websocket-driver": "^0.7.4" "websocket-driver": "^0.7.4"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
}
} }
}, },
"source-list-map": { "source-list-map": {
@@ -29607,10 +29641,9 @@
"dev": true "dev": true
}, },
"uuid": { "uuid": {
"version": "8.3.2", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
"dev": true
}, },
"v8-compile-cache-lib": { "v8-compile-cache-lib": {
"version": "3.0.1", "version": "3.0.1",

View File

@@ -18,7 +18,8 @@
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"sass": "^1.57.1" "sass": "^1.57.1",
"uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",

View File

@@ -5,7 +5,7 @@ import onInstall from './events/onInstall';
import onNewChromeSession from './events/onNewChromeSession'; import onNewChromeSession from './events/onNewChromeSession';
import onServiceWorkerAlive from './events/onServiceWorkerAlive'; import onServiceWorkerAlive from './events/onServiceWorkerAlive';
import onUpdate from './events/onUpdate'; import onUpdate from './events/onUpdate';
import { sessionStore } from '../shared/storage/sessionStore'; import { SessionStore } from './storage/SessionStore';
import browserActionHandler from './handler/browserActionHandler'; import browserActionHandler from './handler/browserActionHandler';
import hotReloadingHandler from './handler/hotReloadingHandler'; import hotReloadingHandler from './handler/hotReloadingHandler';
import tabManagementHandler from './handler/tabManagementHandler'; import tabManagementHandler from './handler/tabManagementHandler';
@@ -38,9 +38,9 @@ const messageListener = new MessageListener<BACKGROUND_MESSAGES>({
messageListener.listen(); messageListener.listen();
sessionStore.getChromeSessionId().then(async chromeSessionId => { SessionStore.getChromeSessionId().then(async chromeSessionId => {
if (!chromeSessionId) { if (!chromeSessionId) {
await sessionStore.setChromeSessionId(generateRandomId(10)); await SessionStore.setChromeSessionId(generateRandomId(10));
onNewChromeSession(); onNewChromeSession();
} }
}); });

View File

@@ -1,26 +1,9 @@
import { SECOND } from 'src/shared/util/time'; import { SECOND } from 'src/shared/util/time';
import { ExtensionStore } from '../storage/ExtensionStore';
/** /**
* Called when the extension is first installed or synced onto a new machine * Called when the extension is first installed or synced onto a new machine
*/ */
export default async function onInstall() { export default async function onInstall() {
// set the uninstall url await ExtensionStore.setVersion(chrome.runtime.getManifest().version);
chrome.runtime.setUninstallURL('https://www.google.com');
logOnInstallEvent();
}
/**
* making sure we are not sending duplicate install event for users that have synced browsers
* sync storage get's cleared on browser uninstall, so re-installing the browser will trigger the event
*/
function logOnInstallEvent() {
setTimeout(async () => {
const manifest = chrome.runtime.getManifest();
const INSTALL_KEY = `${manifest.short_name}-installed`;
const storage = await chrome.storage.sync.get(INSTALL_KEY);
if (!storage[INSTALL_KEY]) {
// TODO: send install event
await chrome.storage.sync.set({ [INSTALL_KEY]: true });
}
}, 5 * SECOND);
} }

View File

@@ -1,9 +1,15 @@
import { hotReloadTab } from 'src/background/util/hotReloadTab'; import { hotReloadTab } from 'src/background/util/hotReloadTab';
import { ExtensionStore } from '../storage/ExtensionStore';
/** /**
* Called when the extension is updated (or when the extension is reloaded in development mode) * Called when the extension is updated (or when the extension is reloaded in development mode)
*/ */
export default function onUpdate() { export default async function onUpdate() {
await Promise.all([
ExtensionStore.setLastUpdate(Date.now()),
ExtensionStore.setVersion(chrome.runtime.getManifest().version),
]);
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
hotReloadTab(); hotReloadTab();
} }

View File

@@ -1,18 +1,18 @@
import HotReloadingMessages from 'src/shared/messages/HotReloadingMessages'; import HotReloadingMessages from 'src/shared/messages/HotReloadingMessages';
import { MessageHandler } from 'chrome-extension-toolkit'; import { MessageHandler } from 'chrome-extension-toolkit';
import { devStore } from 'src/shared/storage/devStore'; import { DevStore } from 'src/background/storage/DevStore';
const hotReloadingHandler: MessageHandler<HotReloadingMessages> = { const hotReloadingHandler: MessageHandler<HotReloadingMessages> = {
async reloadExtension({ sendResponse }) { async reloadExtension({ sendResponse }) {
const isExtensionReloading = await devStore.getIsExtensionReloading(); const isExtensionReloading = await DevStore.getIsExtensionReloading();
if (!isExtensionReloading) return sendResponse(); if (!isExtensionReloading) return sendResponse();
const isTabReloading = await devStore.getIsExtensionReloading(); const isTabReloading = await DevStore.getIsExtensionReloading();
if (isTabReloading) { if (isTabReloading) {
const tabs = await chrome.tabs.query({ active: true, currentWindow: true }); const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
const tabToReload = tabs[0]; const tabToReload = tabs[0];
await devStore.setReloadTabId(tabToReload?.id); await DevStore.setReloadTabId(tabToReload?.id);
} }
chrome.runtime.reload(); chrome.runtime.reload();
}, },

View File

@@ -16,7 +16,7 @@ interface IDevStore {
reloadTabId?: number; reloadTabId?: number;
} }
export const devStore = createStore<IDevStore>('DEV_STORE', { export const DevStore = createStore<IDevStore>('DEV_STORE', {
debugTabId: undefined, debugTabId: undefined,
isTabReloading: true, isTabReloading: true,
wasDebugTabVisible: false, wasDebugTabVisible: false,

View File

@@ -0,0 +1,31 @@
import { v4 as uuidv4 } from 'uuid';
import { createStore } from 'chrome-extension-toolkit';
/**
* A store that is used for storing user options
*/
interface IExtensionStore {
/** These values are cached in storage, so that we can know the previous version that the extension was before the current update. Is only used for onUpdate */
version: string;
/** When was the last update */
lastUpdate: number;
/** A unique identifier generated for the current user in lieu of a userId */
deviceId: string;
}
const base = createStore<IExtensionStore>('EXTENSION_STORE', {
version: chrome.runtime.getManifest().version,
lastUpdate: Date.now(),
deviceId: '',
});
export const ExtensionStore = base.modify({
async getDeviceId() {
const deviceId = await base.getDeviceId();
if (deviceId) {
return deviceId;
}
const newDeviceId = uuidv4();
return newDeviceId;
},
});

View File

@@ -10,7 +10,7 @@ interface IOptionsStore {
shouldScrollToLoad: boolean; shouldScrollToLoad: boolean;
} }
export const optionsStore = createStore<IOptionsStore>('OPTIONS_STORE', { export const OptionsStore = createStore<IOptionsStore>('OPTIONS_STORE', {
shouldHighlightConflicts: true, shouldHighlightConflicts: true,
shouldScrollToLoad: true, shouldScrollToLoad: true,
}); });

View File

@@ -4,7 +4,7 @@ interface ISessionStore {
chromeSessionId?: string; chromeSessionId?: string;
} }
export const sessionStore = createStore<ISessionStore>( export const SessionStore = createStore<ISessionStore>(
'SESSION_STORE', 'SESSION_STORE',
{ {
chromeSessionId: undefined, chromeSessionId: undefined,

View File

@@ -1,4 +1,4 @@
import { devStore } from 'src/shared/storage/devStore'; import { DevStore } from 'src/background/storage/DevStore';
/** /**
* A list of websites that we don't want to reload when the extension reloads (becuase it'd be hella annoying lmao) * A list of websites that we don't want to reload when the extension reloads (becuase it'd be hella annoying lmao)
@@ -24,7 +24,7 @@ const HOT_RELOADING_WHITELIST = [
* @returns a promise that resolves when the tab is reloaded * @returns a promise that resolves when the tab is reloaded
*/ */
export async function hotReloadTab(): Promise<void> { export async function hotReloadTab(): Promise<void> {
const { getIsTabReloading, getReloadTabId } = devStore; const { getIsTabReloading, getReloadTabId } = DevStore;
const [isTabReloading, reloadTabId] = await Promise.all([getIsTabReloading(), getReloadTabId()]); const [isTabReloading, reloadTabId] = await Promise.all([getIsTabReloading(), getReloadTabId()]);

View File

@@ -1,16 +1,16 @@
import { devStore } from 'src/shared/storage/devStore'; import { DevStore } from 'src/background/storage/DevStore';
/** /**
* Open the debug tab as the first tab * Open the debug tab as the first tab
*/ */
export async function openDebugTab() { export async function openDebugTab() {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
const debugTabId = await devStore.getDebugTabId(); const debugTabId = await DevStore.getDebugTabId();
const isAlreadyOpen = await (await chrome.tabs.query({})).some(tab => tab.id === debugTabId); const isAlreadyOpen = await (await chrome.tabs.query({})).some(tab => tab.id === debugTabId);
if (isAlreadyOpen) return; if (isAlreadyOpen) return;
const wasVisible = await devStore.getWasDebugTabVisible(); const wasVisible = await DevStore.getWasDebugTabVisible();
const tab = await chrome.tabs.create({ const tab = await chrome.tabs.create({
url: chrome.runtime.getURL('debug.html'), url: chrome.runtime.getURL('debug.html'),
@@ -19,6 +19,6 @@ export async function openDebugTab() {
index: 0, index: 0,
}); });
await devStore.setDebugTabId(tab.id); await DevStore.setDebugTabId(tab.id);
} }
} }

View File

@@ -1,7 +1,7 @@
import './hotReload'; import './hotReload';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { devStore } from 'src/shared/storage/devStore'; import { DevStore } from 'src/background/storage/DevStore';
const manifest = chrome.runtime.getManifest(); const manifest = chrome.runtime.getManifest();
@@ -70,9 +70,9 @@ function DevDashboard() {
useEffect(() => { useEffect(() => {
const onVisibilityChange = () => { const onVisibilityChange = () => {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
devStore.setWasDebugTabVisible(true); DevStore.setWasDebugTabVisible(true);
} else { } else {
devStore.setWasDebugTabVisible(false); DevStore.setWasDebugTabVisible(false);
} }
}; };
document.addEventListener('visibilitychange', onVisibilityChange); document.addEventListener('visibilitychange', onVisibilityChange);

View File

@@ -0,0 +1,16 @@
import React from 'react';
import { Course } from 'src/shared/types/Course';
import styles from './CoursePopup.module.scss';
interface Props {
course: Course;
}
export default function CoursePopup({ course }: Props) {
return (
<div>
<h1>{course.fullName}</h1>
<p>{course.description}</p>
</div>
);
}