added deviceId, ExtensionStore, working on CoursePopup
This commit is contained in:
51
package-lock.json
generated
51
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,
|
||||||
31
src/background/storage/ExtensionStore.ts
Normal file
31
src/background/storage/ExtensionStore.ts
Normal 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;
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -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,
|
||||||
});
|
});
|
||||||
@@ -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,
|
||||||
@@ -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()]);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
16
src/views/components/injected/CoursePopup/CoursePopup.tsx
Normal file
16
src/views/components/injected/CoursePopup/CoursePopup.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user