Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to Firestore Lite #523

Merged
merged 37 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
62e9485
Upgrade outdated.
ghinda Feb 8, 2024
b9779ad
Upgrade css-minimizer-webpack-plugin.
ghinda Feb 8, 2024
313516d
Use initializeAuth instead of getAuth for firebase auth, to tree-shak…
ghinda Feb 8, 2024
28038b3
Set popupRedirectResolver: undefined, since we don't use it in auth.
ghinda Feb 8, 2024
b901f5f
Bump version.
ghinda Feb 8, 2024
f994be2
Tweak css injection methods for manifest v3.
ghinda Feb 8, 2024
1316ced
Support browser action methods in manifest v3.
ghinda Feb 8, 2024
656a124
Use manifest v2 by default.
ghinda Feb 9, 2024
5b502ce
Upgrade mocha.
ghinda Feb 9, 2024
9401d20
Initial changes for not relying on firestore snapshots anymore.
ghinda Feb 9, 2024
6613c24
Always load data from the background when opening the dialog.
ghinda Feb 9, 2024
8646daa
Clean up older snapshot related functionality.
ghinda Feb 9, 2024
2f37b8b
Switch to firestore/lite.
ghinda Feb 9, 2024
32bf10d
Disable persistance for the background script on manifest v2.
ghinda Feb 9, 2024
57eb847
Initial work on dashboard events.
ghinda Feb 9, 2024
44c4f81
Fix issues with not clearning up the template cache.
ghinda Feb 9, 2024
b0b151c
Upgrade chai.
ghinda Feb 12, 2024
ac39586
Add TM to the Gmail string in the extension name and description.
ghinda Feb 13, 2024
c96d567
Fix dashboard events client not working on briskine.com.
ghinda Feb 13, 2024
7ac4796
Add share_all to list of default settings.
ghinda Feb 13, 2024
e10ba49
Remove the auto clear collection cache when opening the popup.
ghinda Feb 14, 2024
10e983b
Add a manual sync button in the popup dashboard, to refetch all colle…
ghinda Feb 14, 2024
7b508bc
Increase batched updates timer for dashboard events.
ghinda Feb 14, 2024
4f4c2d6
Styling for the new manual sync functionality.
ghinda Feb 14, 2024
37c3bc9
Don't refetch templates for free users.
ghinda Feb 14, 2024
4a90d89
Auto sync is last sync was more than 1 hour ago.
ghinda Feb 14, 2024
60dfd4f
Tweak uppercase title on account settings link.
ghinda Feb 14, 2024
ad93bd7
Improve text overflow ellipsis on the popup footer email address.
ghinda Feb 14, 2024
86d79e3
Fix loading indicator circle centering.
ghinda Feb 14, 2024
d7f8642
Revert to the old version of keyboard that uses content-script-cached…
ghinda Feb 14, 2024
feeedaa
Revert to the old version of dialog, that caches templates locally.
ghinda Feb 14, 2024
8b742a0
Upgrade firebase-tools.
ghinda Feb 15, 2024
3cc4abc
Upgrade to latest firebase.
ghinda Feb 15, 2024
de76e7d
Add a newline to the last sync tooltip.
ghinda Feb 15, 2024
45449f6
Attach the dashboard events message handler only on the dashboard.
ghinda Feb 15, 2024
8a3c4a5
Avoid multiple parallel refetches.
ghinda Feb 15, 2024
8deb833
Improve current url detection for blacklist, to work for nested ifram…
ghinda Feb 15, 2024
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
1,831 changes: 1,190 additions & 641 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "briskine",
"version": "7.10.7",
"version": "7.11.0",
"description": "Write everything faster.",
"private": true,
"type": "module",
Expand Down Expand Up @@ -45,7 +45,7 @@
"chai": "^5.0.0",
"copy-webpack-plugin": "^12.0.0",
"css-loader": "^6.0.0",
"css-minimizer-webpack-plugin": "^5.0.0",
"css-minimizer-webpack-plugin": "^6.0.0",
"cypress": "^13.0.0",
"cypress-plugin-tab": "^1.0.5",
"eslint": "^8.14.0",
Expand All @@ -64,7 +64,8 @@
"@webcomponents/custom-elements": "^1.4.3",
"bootstrap": "^5.3.0",
"bootstrap-icons": "^1.10.3",
"firebase": "~10.6.0",
"deep-equal": "^2.2.3",
"firebase": "^10.8.0",
"fuse.js": "^7.0.0",
"handlebars": "^4.5.3",
"html-to-text": "^9.0.0",
Expand Down
26 changes: 17 additions & 9 deletions src/background/background-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,29 @@ browser.runtime.onInstalled.addListener((details) => {
const scripts = contentScripts.js
const styles = contentScripts.css

let scriptingNamespace = 'scripting'
if (MANIFEST === '2') {
scriptingNamespace = 'tabs'
}

browser.tabs.query({
url: contentScripts.matches
}).then((tabs) => {
tabs.forEach((tab) => {
// remove and insert new content styles
styles.forEach((file) => {
browser[scriptingNamespace].removeCSS(tab.id, {file: file}).then(() => {
browser[scriptingNamespace].insertCSS(tab.id, {file: file})
if (MANIFEST === '2') {
styles.forEach((file) => {
browser.tabs.removeCSS(tab.id, {file: file}).then(() => {
browser.tabs.insertCSS(tab.id, {file: file})
})
})
} else {
const cssInjectParams = {
target: {
tabId: tab.id,
},
files: styles,
}

browser.scripting.removeCSS(cssInjectParams).then(() => {
browser.scripting.insertCSS(cssInjectParams)
})
})
}

// insert new content scripts
if (MANIFEST === '2') {
Expand Down
7 changes: 5 additions & 2 deletions src/background/badge-update.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/* globals MANIFEST */
import browser from 'webextension-polyfill'

const actionNamespace = (MANIFEST === '2') ? 'browserAction' : 'action'

export default function badgeUpdate(user = null) {
const suffix = user ? '' : '-loggedout'

const icons = {}
const sizes = ['16', '32', '48']
sizes.forEach((size) => {
icons[size] = `icons/icon-${size}${suffix}.png`
icons[size] = `/icons/icon-${size}${suffix}.png`
})

browser.browserAction.setIcon({
browser[actionNamespace].setIcon({
path: icons
})
}
70 changes: 70 additions & 0 deletions src/content/dashboard-events-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import store from '../store/store-client.js'
import config from '../config.js'

const prefix = 'briskine-dashboard'

const dashboardEvents = [
'templates',
'tags',
'users',
'customers',
].map((c) => {
return {
type: `${prefix}-${c}-updated`,
collection: c,
}
})

let batchedUpdates = []
let clearCacheTimer = null
let refetching = Promise.resolve()
function clearCache (collection) {
if (!batchedUpdates.includes(collection)) {
batchedUpdates.push(collection)
}

if (clearCacheTimer) {
clearTimeout(clearCacheTimer)
}

clearCacheTimer = setTimeout(() => {
const updates = batchedUpdates.slice()
refetching.then(() => {
refetching = store.refetchCollections(updates)
})

clearCacheTimer = null
batchedUpdates = []
}, 1000)
}

const templateCollections = [
'templatesOwned',
'templatesShared',
'templatesEveryone',
]

function dashboardEvent (e) {
const dashboardEvent = dashboardEvents.find((dEvent) => dEvent.type === e?.data?.type)
if (dashboardEvent) {
if (dashboardEvent.collection === 'templates') {
templateCollections.forEach((tc) => {
clearCache(tc)
})
} else {
clearCache(dashboardEvent.collection)
}
}
}

export function setup () {
if (window.location.origin !== config.functionsUrl) {
return
}

window.addEventListener('message', dashboardEvent)
}

export function destroy () {
window.removeEventListener('message', dashboardEvent)
}
21 changes: 19 additions & 2 deletions src/content/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// native custom elements are not supported in content scripts
// https://bugs.chromium.org/p/chromium/issues/detail?id=390807
import '@webcomponents/custom-elements'
import deepEqual from 'deep-equal'

import store from '../store/store-client.js'
import config from '../config.js'
Expand All @@ -12,15 +13,30 @@ import {setup as setupDialog, destroy as destroyDialog} from './dialog/dialog.js
import {setup as setupSandbox, destroy as destroySandbox} from './sandbox/sandbox-parent.js'
import {setup as setupPage, destroy as destroyPage} from './page/page-parent.js'
import {setup as setupAttachments, destroy as destroyAttachments} from './attachments/attachments.js'
import {setup as setupDashboardEvents, destroy as destroyDashboardEvents} from './dashboard-events-client.js'

function getParentUrl () {
let url = window.location.href
if (window !== window.parent) {
try {
url = window.parent.location.href
} catch (err) {
// iframe from different domain
}
}

return url
}

const currentUrl = window.location.href
const currentUrl = getParentUrl()

const blacklistPrivate = [
'.briskine.com',
]

function init (settings) {
setupStatus()
setupDashboardEvents()

// create the full blacklist
// from the editable and private one
Expand Down Expand Up @@ -104,6 +120,7 @@ function destructor () {
destroySandbox()
destroyPage()
destroyAttachments()
destroyDashboardEvents()

settingsCache = {}
store.off('users-updated', refreshContentScripts)
Expand All @@ -122,7 +139,7 @@ function refreshContentScripts () {
// restart the content components if any of the settings changed
store.getSettings()
.then((settings) => {
const settingsChanged = JSON.stringify(settings) !== JSON.stringify(settingsCache)
const settingsChanged = !deepEqual(settings, settingsCache)
if (settingsChanged) {
destructor()
init(settings)
Expand Down
4 changes: 4 additions & 0 deletions src/content/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ function respondToStatus () {
const requestEvent = `${config.eventStatus}-request`

export function setup () {
if (window.location.origin !== config.functionsUrl) {
return
}

document.addEventListener(requestEvent, respondToStatus)
}

Expand Down
4 changes: 2 additions & 2 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"manifest_version": 3,
"name": "Briskine: Email templates for Gmail",
"name": "Briskine: Email templates for Gmail",
"version": "",
"description": "Write emails faster! Increase your productivity with templates and keyboard shortcuts on Gmail, Outlook, or LinkedIn.",
"description": "Write emails faster! Increase your productivity with templates and keyboard shortcuts on Gmail, Outlook, or LinkedIn.",
"short_name": "Briskine",
"icons": {
"16": "icons/icon-16.png",
Expand Down
88 changes: 64 additions & 24 deletions src/popup/popup-dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {unsafeSVG} from 'lit-html/directives/unsafe-svg.js'
import Config from '../config.js'
import store from '../store/store-client.js'

import {plusSquareFill, archiveFill, gearFill} from './popup-icons.js'
import {plusSquareFill, archiveFill, gearFill, arrowRepeat} from './popup-icons.js'

function niceTime (minutes) {
if (!minutes) {
Expand All @@ -22,35 +22,42 @@ function niceTime (minutes) {
}
}

function getStats () {
const avgWPM = 25;
return store.getExtensionData()
.then((data) => {
const words = data.words
// average WPM: http://en.wikipedia.org/wiki/Words_per_minute
const time = niceTime(Math.round(words / avgWPM))

return {
time: time,
words: words
}
})
function getStats (words = 0) {
const avgWPM = 25
// average WPM: http://en.wikipedia.org/wiki/Words_per_minute
const time = niceTime(Math.round(words / avgWPM))

return {
time: time,
words: words
}
}

// one hour
const autoSyncTime = 60 * 60 * 1000

customElements.define(
'popup-dashboard',
class extends HTMLElement {
constructor() {
super()

this.stats = {
time: '0min',
words: 0,
}
getStats().then((res) => {
this.stats = res
this.connectedCallback()
})
this.syncing = false
this.stats = getStats(0)
this.lastSync = Date.now()

store.getExtensionData()
.then((data) => {
this.lastSync = new Date(data.lastSync)
// auto sync is last sync was more than one hour ago
if (new Date() - this.lastSync > autoSyncTime) {
this.sync()
}

this.stats = getStats(data.words)

this.connectedCallback()
})

this.user = {}
this.isFree = null
Expand Down Expand Up @@ -91,8 +98,28 @@ customElements.define(
}
})

this.addEventListener('click', (e) => {
if (e.target.closest('.js-sync-now')) {
this.sync()
}
})

this.refreshAccount()
}
sync () {
this.syncing = true
this.connectedCallback()

return store.refetchCollections()
.then(() => {
return store.getExtensionData()
})
.then((data) => {
this.syncing = false
this.lastSync = new Date(data.lastSync)
return this.connectedCallback()
})
}
refreshAccount () {
return store.getAccount()
.then((res) => {
Expand Down Expand Up @@ -152,10 +179,23 @@ customElements.define(
connectedCallback() {
render(html`
<div class="popup-dashboard">
<div class="popup-box popup-logo">
<div class="popup-box popup-logo d-flex justify-content-between">
<a href=${Config.websiteUrl} target="_blank">
<img src="../icons/briskine-combo.svg" width="132" alt="Briskine"/>
</a>

<button
type="button"
class=${classMap({
'btn-sync': true,
'btn-sync-loading': this.syncing,
'js-sync-now': true,
})}
?disabled=${this.syncing}
title=${`Sync templates now \n(Last sync: ${this.lastSync.toLocaleString()})`}
>
${unsafeSVG(arrowRepeat)}
</button>
</div>

<ul class="list-unstyled popup-menu">
Expand Down Expand Up @@ -263,7 +303,7 @@ customElements.define(
href=${`${Config.functionsUrl}/account`}
target=${Config.dashboardTarget}
class="popup-user"
title=${`Account Settings for ${this.user.email}`}
title=${`Account settings for ${this.user.email}`}
>
${this.user.email}
</a>
Expand Down
5 changes: 5 additions & 0 deletions src/popup/popup-icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ export const archiveFill = `<svg xmlns="http://www.w3.org/2000/svg" width="16" h
export const plusSquareFill = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z"/>
</svg>`

export const arrowRepeat = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-repeat" viewBox="0 0 16 16">
<path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41m-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9"/>
<path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5 5 0 0 0 8 3M3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9z"/>
</svg>`
Loading
Loading