Merge branch 'main' into feat/search

This commit is contained in:
liyasthomas
2021-08-29 20:59:47 +05:30
12 changed files with 3348 additions and 2300 deletions

View File

@@ -22,6 +22,7 @@ module.exports = {
// add your custom rules here // add your custom rules here
rules: { rules: {
semi: [2, "never"], semi: [2, "never"],
"import/named": "off", // because, named import issue with typescript see: https://github.com/typescript-eslint/typescript-eslint/issues/154
"no-console": process.env.NODE_ENV === "production" ? "error" : "off", "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
"vue/max-attributes-per-line": "off", "vue/max-attributes-per-line": "off",

View File

@@ -116,17 +116,16 @@
</SmartModal> </SmartModal>
</template> </template>
<script> <script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api" import { defineComponent } from "@nuxtjs/composition-api"
import { applySetting } from "~/newstore/settings"
import { import {
signInUserWithGoogle, signInUserWithGoogle,
getSignInMethodsForEmail,
signInWithEmailAndPassword,
signInUserWithGithub, signInUserWithGithub,
setProviderInfo, setProviderInfo,
currentUser$, currentUser$,
signInWithEmail, signInWithEmail,
linkWithFBCredential,
getGithubCredentialFromResult,
} from "~/helpers/fb/auth" } from "~/helpers/fb/auth"
import { setLocalConfig } from "~/newstore/localpersistence" import { setLocalConfig } from "~/newstore/localpersistence"
import { useStreamSubscriber } from "~/helpers/utils/composables" import { useStreamSubscriber } from "~/helpers/utils/composables"
@@ -162,7 +161,7 @@ export default defineComponent({
}, },
methods: { methods: {
showLoginSuccess() { showLoginSuccess() {
this.$toast.success(this.$t("auth.login_success"), { this.$toast.success(this.$t("auth.login_success").toString(), {
icon: "vpn_key", icon: "vpn_key",
}) })
}, },
@@ -170,28 +169,7 @@ export default defineComponent({
this.signingInWithGoogle = true this.signingInWithGoogle = true
try { try {
const { additionalUserInfo } = await signInUserWithGoogle() await signInUserWithGoogle()
if (additionalUserInfo.isNewUser) {
this.$toast.info(
`${this.$t("action.turn_on")} ${this.$t("auth.sync")}`,
{
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("action.yes"),
onClick: (_, toastObject) => {
applySetting("syncHistory", true)
applySetting("syncCollections", true)
applySetting("syncEnvironments", true)
toastObject.remove()
},
},
}
)
}
this.showLoginSuccess() this.showLoginSuccess()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@@ -201,44 +179,24 @@ export default defineComponent({
// User's email already exists. // User's email already exists.
// The pending Google credential. // The pending Google credential.
const pendingCred = e.credential const pendingCred = e.credential
// The provider account's email address.
const email = e.email
// Get sign-in methods for this email.
const methods = await getSignInMethodsForEmail(email)
// Step 3.
// If the user has several sign-in methods,
// the first method in the list will be the "recommended" method to use.
if (methods[0] === "password") {
// Asks the user their password.
// In real scenario, you should handle this asynchronously.
const password = promptUserForPassword() // TODO: implement promptUserForPassword.
const user = await signInWithEmailAndPassword(email, password)
await user.linkWithCredential(pendingCred)
this.showLoginSuccess()
return
}
this.$toast.info(`${this.$t("auth.account_exists")}`, { this.$toast.info(`${this.$t("auth.account_exists")}`, {
icon: "vpn_key", icon: "vpn_key",
duration: null, duration: 0,
closeOnSwipe: false, closeOnSwipe: false,
action: { action: {
text: this.$t("action.yes"), text: this.$t("action.yes").toString(),
onClick: async (_, toastObject) => { onClick: async (_, toastObject) => {
const { user } = await signInWithGithub() const { user } = await signInUserWithGithub()
await user.linkWithCredential(pendingCred) await linkWithFBCredential(user, pendingCred)
this.showLoginSuccess() this.showLoginSuccess()
toastObject.remove() toastObject.goAway(0)
}, },
}, },
}) })
} else { } else {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong").toString(), {
icon: "error_outline", icon: "error_outline",
}) })
} }
@@ -250,29 +208,11 @@ export default defineComponent({
this.signingInWithGitHub = true this.signingInWithGitHub = true
try { try {
const { credential, additionalUserInfo } = await signInUserWithGithub() const result = await signInUserWithGithub()
const credential = getGithubCredentialFromResult(result)!
const token = credential.accessToken
setProviderInfo(credential.providerId, credential.accessToken) setProviderInfo(result.providerId!, token!)
if (additionalUserInfo.isNewUser) {
this.$toast.info(
`${this.$t("action.turn_on")} ${this.$t("auth.sync")}`,
{
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("action.yes"),
onClick: (_, toastObject) => {
applySetting("syncHistory", true)
applySetting("syncCollections", true)
applySetting("syncEnvironments", true)
toastObject.remove()
},
},
}
)
}
this.showLoginSuccess() this.showLoginSuccess()
} catch (e) { } catch (e) {
@@ -283,44 +223,24 @@ export default defineComponent({
// User's email already exists. // User's email already exists.
// The pending Google credential. // The pending Google credential.
const pendingCred = e.credential const pendingCred = e.credential
// The provider account's email address.
const email = e.email
// Get sign-in methods for this email.
const methods = await getSignInMethodsForEmail(email)
// Step 3.
// If the user has several sign-in methods,
// the first method in the list will be the "recommended" method to use.
if (methods[0] === "password") {
// Asks the user their password.
// In real scenario, you should handle this asynchronously.
const password = promptUserForPassword() // TODO: implement promptUserForPassword.
const user = await signInWithEmailAndPassword(email, password)
await user.linkWithCredential(pendingCred)
this.showLoginSuccess()
return
}
this.$toast.info(`${this.$t("auth.account_exists")}`, { this.$toast.info(`${this.$t("auth.account_exists")}`, {
icon: "vpn_key", icon: "vpn_key",
duration: null, duration: 0,
closeOnSwipe: false, closeOnSwipe: false,
action: { action: {
text: this.$t("action.yes"), text: this.$t("action.yes").toString(),
onClick: async (_, toastObject) => { onClick: async (_, toastObject) => {
const { user } = await signInUserWithGoogle() const { user } = await signInUserWithGoogle()
await user.linkWithCredential(pendingCred) await linkWithFBCredential(user, pendingCred)
this.showLoginSuccess() this.showLoginSuccess()
toastObject.remove() toastObject.goAway(0)
}, },
}, },
}) })
} else { } else {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong").toString(), {
icon: "error_outline", icon: "error_outline",
}) })
} }

View File

@@ -1,5 +1,11 @@
import firebase from "firebase/app" import {
import "firebase/analytics" Analytics,
getAnalytics,
logEvent,
setAnalyticsCollectionEnabled,
setUserId,
setUserProperties,
} from "firebase/analytics"
import { authEvents$ } from "./auth" import { authEvents$ } from "./auth"
import { import {
HoppAccentColor, HoppAccentColor,
@@ -8,7 +14,7 @@ import {
settingsStore, settingsStore,
} from "~/newstore/settings" } from "~/newstore/settings"
let analytics: firebase.analytics.Analytics | null let analytics: Analytics | null = null
type SettingsCustomDimensions = { type SettingsCustomDimensions = {
usesProxy: boolean usesProxy: boolean
@@ -29,7 +35,7 @@ type HoppRequestEvent =
| { platform: "wss" | "sse" | "socketio" | "mqtt" } | { platform: "wss" | "sse" | "socketio" | "mqtt" }
export function initAnalytics() { export function initAnalytics() {
analytics = firebase.app().analytics() analytics = getAnalytics()
initLoginListeners() initLoginListeners()
initSettingsListeners() initSettingsListeners()
@@ -38,16 +44,16 @@ export function initAnalytics() {
function initLoginListeners() { function initLoginListeners() {
authEvents$.subscribe((ev) => { authEvents$.subscribe((ev) => {
if (ev.event === "login") { if (ev.event === "login") {
if (settingsStore.value.TELEMETRY_ENABLED) { if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
analytics?.setUserId(ev.user.uid) setUserId(analytics, ev.user.uid)
analytics?.logEvent("login", { logEvent(analytics, "login", {
method: ev.user.providerData[0]?.providerId, // Assume the first provider is the login provider method: ev.user.providerData[0]?.providerId, // Assume the first provider is the login provider
}) })
} }
} else if (ev.event === "logout") { } else if (ev.event === "logout") {
if (settingsStore.value.TELEMETRY_ENABLED) { if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
analytics?.logEvent("logout") logEvent(analytics, "logout")
} }
} }
}) })
@@ -71,29 +77,30 @@ function initSettingsListeners() {
// User toggled telemetry mode to off or to on // User toggled telemetry mode to off or to on
if ( if (
(telemetryStatus && !settings.TELEMETRY_ENABLED) || ((telemetryStatus && !settings.TELEMETRY_ENABLED) ||
settings.TELEMETRY_ENABLED settings.TELEMETRY_ENABLED) &&
analytics
) { ) {
analytics?.setUserProperties(conf) setUserProperties(analytics, conf)
} }
telemetryStatus = settings.TELEMETRY_ENABLED telemetryStatus = settings.TELEMETRY_ENABLED
analytics?.setAnalyticsCollectionEnabled(telemetryStatus) if (analytics) setAnalyticsCollectionEnabled(analytics, telemetryStatus)
}) })
analytics?.setAnalyticsCollectionEnabled(telemetryStatus) if (analytics) setAnalyticsCollectionEnabled(analytics, telemetryStatus)
} }
export function logHoppRequestRunToAnalytics(ev: HoppRequestEvent) { export function logHoppRequestRunToAnalytics(ev: HoppRequestEvent) {
if (settingsStore.value.TELEMETRY_ENABLED) { if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
analytics?.logEvent("hopp-request", ev) logEvent(analytics, "hopp-request", ev)
} }
} }
export function logPageView(pagePath: string) { export function logPageView(pagePath: string) {
if (settingsStore.value.TELEMETRY_ENABLED) { if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
analytics?.logEvent("page_view", { logEvent(analytics, "page_view", {
page_path: pagePath, page_path: pagePath,
}) })
} }

View File

@@ -1,6 +1,29 @@
import firebase from "firebase/app" import {
import "firebase/firestore" User,
import "firebase/auth" getAuth,
onAuthStateChanged,
onIdTokenChanged,
signInWithPopup,
GoogleAuthProvider,
GithubAuthProvider,
signInWithEmailAndPassword as signInWithEmailAndPass,
isSignInWithEmailLink as isSignInWithEmailLinkFB,
fetchSignInMethodsForEmail,
sendSignInLinkToEmail,
signInWithEmailLink as signInWithEmailLinkFB,
ActionCodeSettings,
signOut,
linkWithCredential,
AuthCredential,
UserCredential,
} from "firebase/auth"
import {
onSnapshot,
getFirestore,
setDoc,
doc,
updateDoc,
} from "firebase/firestore"
import { import {
BehaviorSubject, BehaviorSubject,
distinctUntilChanged, distinctUntilChanged,
@@ -11,7 +34,7 @@ import {
} from "rxjs" } from "rxjs"
import { onBeforeUnmount, onMounted } from "@nuxtjs/composition-api" import { onBeforeUnmount, onMounted } from "@nuxtjs/composition-api"
export type HoppUser = firebase.User & { export type HoppUser = User & {
provider?: string provider?: string
accessToken?: string accessToken?: string
} }
@@ -39,9 +62,12 @@ export const authEvents$ = new Subject<AuthEvents>()
* Initializes the firebase authentication related subjects * Initializes the firebase authentication related subjects
*/ */
export function initAuth() { export function initAuth() {
const auth = getAuth()
const firestore = getFirestore()
let extraSnapshotStop: (() => void) | null = null let extraSnapshotStop: (() => void) | null = null
firebase.auth().onAuthStateChanged((user) => { onAuthStateChanged(auth, (user) => {
/** Whether the user was logged in before */ /** Whether the user was logged in before */
const wasLoggedIn = currentUser$.value !== null const wasLoggedIn = currentUser$.value !== null
@@ -62,19 +88,14 @@ export function initAuth() {
uid: profile.uid, uid: profile.uid,
} }
firebase setDoc(doc(firestore, "users", user.uid), us, { merge: true }).catch(
.firestore() (e) => console.error("error updating", us, e)
.collection("users") )
.doc(user.uid)
.set(us, { merge: true })
.catch((e) => console.error("error updating", us, e))
}) })
extraSnapshotStop = firebase extraSnapshotStop = onSnapshot(
.firestore() doc(firestore, "users", user.uid),
.collection("users") (doc) => {
.doc(user.uid)
.onSnapshot((doc) => {
const data = doc.data() const data = doc.data()
const userUpdate: HoppUser = user const userUpdate: HoppUser = user
@@ -86,7 +107,8 @@ export function initAuth() {
} }
currentUser$.next(userUpdate) currentUser$.next(userUpdate)
}) }
)
} }
currentUser$.next(user) currentUser$.next(user)
@@ -104,7 +126,7 @@ export function initAuth() {
} }
}) })
firebase.auth().onIdTokenChanged(async (user) => { onIdTokenChanged(auth, async (user) => {
if (user) { if (user) {
authIdToken$.next(await user.getIdToken()) authIdToken$.next(await user.getIdToken())
@@ -123,18 +145,17 @@ export function initAuth() {
* Sign user in with a popup using Google * Sign user in with a popup using Google
*/ */
export async function signInUserWithGoogle() { export async function signInUserWithGoogle() {
return await firebase return await signInWithPopup(getAuth(), new GoogleAuthProvider())
.auth()
.signInWithPopup(new firebase.auth.GoogleAuthProvider())
} }
/** /**
* Sign user in with a popup using Github * Sign user in with a popup using Github
*/ */
export async function signInUserWithGithub() { export async function signInUserWithGithub() {
return await firebase return await signInWithPopup(
.auth() getAuth(),
.signInWithPopup(new firebase.auth.GithubAuthProvider().addScope("gist")) new GithubAuthProvider().addScope("gist")
)
} }
/** /**
@@ -144,7 +165,7 @@ export async function signInWithEmailAndPassword(
email: string, email: string,
password: string password: string
) { ) {
return await firebase.auth().signInWithEmailAndPassword(email, password) return await signInWithEmailAndPass(getAuth(), email, password)
} }
/** /**
@@ -155,7 +176,14 @@ export async function signInWithEmailAndPassword(
* @returns Promise for string array of the auth provider methods accessible * @returns Promise for string array of the auth provider methods accessible
*/ */
export async function getSignInMethodsForEmail(email: string) { export async function getSignInMethodsForEmail(email: string) {
return await firebase.auth().fetchSignInMethodsForEmail(email) return await fetchSignInMethodsForEmail(getAuth(), email)
}
export async function linkWithFBCredential(
user: User,
credential: AuthCredential
) {
return await linkWithCredential(user, credential)
} }
/** /**
@@ -166,9 +194,9 @@ export async function getSignInMethodsForEmail(email: string) {
*/ */
export async function signInWithEmail( export async function signInWithEmail(
email: string, email: string,
actionCodeSettings: firebase.auth.ActionCodeSettings actionCodeSettings: ActionCodeSettings
) { ) {
return await firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) return await sendSignInLinkToEmail(getAuth(), email, actionCodeSettings)
} }
/** /**
@@ -177,7 +205,7 @@ export async function signInWithEmail(
* @param url - The URL to look in * @param url - The URL to look in
*/ */
export function isSignInWithEmailLink(url: string) { export function isSignInWithEmailLink(url: string) {
return firebase.auth().isSignInWithEmailLink(url) return isSignInWithEmailLinkFB(getAuth(), url)
} }
/** /**
@@ -187,7 +215,7 @@ export function isSignInWithEmailLink(url: string) {
* @param url - The action URL which is used to validate login * @param url - The action URL which is used to validate login
*/ */
export async function signInWithEmailLink(email: string, url: string) { export async function signInWithEmailLink(email: string, url: string) {
return await firebase.auth().signInWithEmailLink(email, url) return await signInWithEmailLinkFB(getAuth(), email, url)
} }
/** /**
@@ -196,7 +224,7 @@ export async function signInWithEmailLink(email: string, url: string) {
export async function signOutUser() { export async function signOutUser() {
if (!currentUser$.value) throw new Error("No user has logged in") if (!currentUser$.value) throw new Error("No user has logged in")
await firebase.auth().signOut() await signOut(getAuth())
} }
/** /**
@@ -216,18 +244,20 @@ export async function setProviderInfo(id: string, token: string) {
} }
try { try {
await firebase await updateDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid),
.collection("users") us
.doc(currentUser$.value.uid) ).catch((e) => console.error("error updating", us, e))
.update(us)
.catch((e) => console.error("error updating", us, e))
} catch (e) { } catch (e) {
console.error("error updating", e) console.error("error updating", e)
throw e throw e
} }
} }
export function getGithubCredentialFromResult(result: UserCredential) {
return GithubAuthProvider.credentialFromResult(result)
}
/** /**
* A Vue composable function that is called when the auth status * A Vue composable function that is called when the auth status
* is being updated to being logged in (fired multiple times), * is being updated to being logged in (fired multiple times),

View File

@@ -1,5 +1,10 @@
import firebase from "firebase/app" import {
import "firebase/firestore" collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "firebase/firestore"
import { currentUser$ } from "./auth" import { currentUser$ } from "./auth"
import { import {
restCollections$, restCollections$,
@@ -49,13 +54,10 @@ export async function writeCollections(
} }
try { try {
await firebase await setDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid, flag, "sync"),
.collection("users") cl
.doc(currentUser$.value.uid) )
.collection(flag)
.doc("sync")
.set(cl)
} catch (e) { } catch (e) {
console.error("error updating", cl, e) console.error("error updating", cl, e)
throw e throw e
@@ -98,12 +100,9 @@ export function initCollections() {
graphqlSnapshotStop = null graphqlSnapshotStop = null
} }
} else { } else {
restSnapshotStop = firebase restSnapshotStop = onSnapshot(
.firestore() collection(getFirestore(), "users", user.uid, "collections"),
.collection("users") (collectionsRef) => {
.doc(user.uid)
.collection("collections")
.onSnapshot((collectionsRef) => {
const collections: any[] = [] const collections: any[] = []
collectionsRef.forEach((doc) => { collectionsRef.forEach((doc) => {
const collection = doc.data() const collection = doc.data()
@@ -124,14 +123,12 @@ export function initCollections() {
} }
loadedRESTCollections = true loadedRESTCollections = true
}) }
)
graphqlSnapshotStop = firebase graphqlSnapshotStop = onSnapshot(
.firestore() collection(getFirestore(), "users", user.uid, "collectionsGraphql"),
.collection("users") (collectionsRef) => {
.doc(user.uid)
.collection("collectionsGraphql")
.onSnapshot((collectionsRef) => {
const collections: any[] = [] const collections: any[] = []
collectionsRef.forEach((doc) => { collectionsRef.forEach((doc) => {
const collection = doc.data() const collection = doc.data()
@@ -150,7 +147,8 @@ export function initCollections() {
} }
loadedGraphqlCollections = true loadedGraphqlCollections = true
}) }
)
} }
}) })
} }

View File

@@ -1,5 +1,10 @@
import firebase from "firebase/app" import {
import "firebase/firestore" collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "firebase/firestore"
import { currentUser$ } from "./auth" import { currentUser$ } from "./auth"
import { import {
Environment, Environment,
@@ -39,13 +44,16 @@ async function writeEnvironments(environment: Environment[]) {
} }
try { try {
await firebase await setDoc(
.firestore() doc(
.collection("users") getFirestore(),
.doc(currentUser$.value.uid) "users",
.collection("environments") currentUser$.value.uid,
.doc("sync") "envrionments",
.set(ev) "sync"
),
ev
)
} catch (e) { } catch (e) {
console.error("error updating", ev, e) console.error("error updating", ev, e)
throw e throw e
@@ -65,13 +73,10 @@ async function writeGlobalEnvironment(variables: Environment["variables"]) {
} }
try { try {
await firebase await setDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid, "globalEnv", "sync"),
.collection("users") ev
.doc(currentUser$.value.uid) )
.collection("globalEnv")
.doc("sync")
.set(ev)
} catch (e) { } catch (e) {
console.error("error updating", ev, e) console.error("error updating", ev, e)
throw e throw e
@@ -115,12 +120,9 @@ export function initEnvironments() {
globalsSnapshotStop = null globalsSnapshotStop = null
} }
} else if (user) { } else if (user) {
envSnapshotStop = firebase envSnapshotStop = onSnapshot(
.firestore() collection(getFirestore(), "users", user.uid, "environments"),
.collection("users") (environmentsRef) => {
.doc(user.uid)
.collection("environments")
.onSnapshot((environmentsRef) => {
const environments: any[] = [] const environments: any[] = []
environmentsRef.forEach((doc) => { environmentsRef.forEach((doc) => {
@@ -134,13 +136,11 @@ export function initEnvironments() {
replaceEnvironments(environments[0].environment) replaceEnvironments(environments[0].environment)
} }
loadedEnvironments = true loadedEnvironments = true
}) }
globalsSnapshotStop = firebase )
.firestore() globalsSnapshotStop = onSnapshot(
.collection("users") collection(getFirestore(), "users", user.uid, "globalEnv"),
.doc(user.uid) (globalsRef) => {
.collection("globalEnv")
.onSnapshot((globalsRef) => {
if (globalsRef.docs.length === 0) { if (globalsRef.docs.length === 0) {
loadedGlobals = true loadedGlobals = true
return return
@@ -150,7 +150,8 @@ export function initEnvironments() {
loadedGlobals = false loadedGlobals = false
setGlobalEnvVariables(doc.variables) setGlobalEnvVariables(doc.variables)
loadedGlobals = true loadedGlobals = true
}) }
)
} }
}) })
} }

View File

@@ -1,5 +1,16 @@
import firebase from "firebase/app" import {
import "firebase/firestore" addDoc,
collection,
deleteDoc,
doc,
getDocs,
getFirestore,
limit,
onSnapshot,
orderBy,
query,
updateDoc,
} from "firebase/firestore"
import { currentUser$ } from "./auth" import { currentUser$ } from "./auth"
import { settingsStore } from "~/newstore/settings" import { settingsStore } from "~/newstore/settings"
import { import {
@@ -46,12 +57,10 @@ async function writeHistory(entry: any, col: HistoryFBCollections) {
} }
try { try {
await firebase await addDoc(
.firestore() collection(getFirestore(), "users", currentUser$.value.uid, col),
.collection("users") hs
.doc(currentUser$.value.uid) )
.collection(col)
.add(hs)
} catch (e) { } catch (e) {
console.error("error writing to history", hs, e) console.error("error writing to history", hs, e)
throw e throw e
@@ -63,13 +72,9 @@ async function deleteHistory(entry: any, col: HistoryFBCollections) {
throw new Error("User not logged in to delete history") throw new Error("User not logged in to delete history")
try { try {
await firebase await deleteDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid, col, entry.id)
.collection("users") )
.doc(currentUser$.value.uid)
.collection(col)
.doc(entry.id)
.delete()
} catch (e) { } catch (e) {
console.error("error deleting history", entry, e) console.error("error deleting history", entry, e)
throw e throw e
@@ -80,12 +85,9 @@ async function clearHistory(col: HistoryFBCollections) {
if (currentUser$.value == null) if (currentUser$.value == null)
throw new Error("User not logged in to clear history") throw new Error("User not logged in to clear history")
const { docs } = await firebase const { docs } = await getDocs(
.firestore() collection(getFirestore(), "users", currentUser$.value.uid, col)
.collection("users") )
.doc(currentUser$.value.uid)
.collection(col)
.get()
await Promise.all(docs.map((e) => deleteHistory(e, col))) await Promise.all(docs.map((e) => deleteHistory(e, col)))
} }
@@ -95,13 +97,10 @@ async function toggleStar(entry: any, col: HistoryFBCollections) {
throw new Error("User not logged in to toggle star") throw new Error("User not logged in to toggle star")
try { try {
await firebase await updateDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid, col, entry.id),
.collection("users") { star: !entry.star }
.doc(currentUser$.value.uid) )
.collection(col)
.doc(entry.id)
.update({ star: !entry.star })
} catch (e) { } catch (e) {
console.error("error toggling star", entry, e) console.error("error toggling star", entry, e)
throw e throw e
@@ -161,14 +160,13 @@ export function initHistory() {
graphqlSnapshotStop = null graphqlSnapshotStop = null
} }
} else { } else {
restSnapshotStop = firebase restSnapshotStop = onSnapshot(
.firestore() query(
.collection("users") collection(getFirestore(), "users", user.uid, "history"),
.doc(user.uid) orderBy("updatedOn", "desc"),
.collection("history") limit(HISTORY_LIMIT)
.orderBy("updatedOn", "desc") ),
.limit(HISTORY_LIMIT) (historyRef) => {
.onSnapshot((historyRef) => {
const history: RESTHistoryEntry[] = [] const history: RESTHistoryEntry[] = []
historyRef.forEach((doc) => { historyRef.forEach((doc) => {
@@ -180,16 +178,16 @@ export function initHistory() {
loadedRESTHistory = false loadedRESTHistory = false
setRESTHistoryEntries(history) setRESTHistoryEntries(history)
loadedRESTHistory = true loadedRESTHistory = true
}) }
)
graphqlSnapshotStop = firebase graphqlSnapshotStop = onSnapshot(
.firestore() query(
.collection("users") collection(getFirestore(), "users", user.uid, "graphqlHistory"),
.doc(user.uid) orderBy("updatedOn", "desc"),
.collection("graphqlHistory") limit(HISTORY_LIMIT)
.orderBy("updatedOn", "desc") ),
.limit(HISTORY_LIMIT) (historyRef) => {
.onSnapshot((historyRef) => {
const history: GQLHistoryEntry[] = [] const history: GQLHistoryEntry[] = []
historyRef.forEach((doc) => { historyRef.forEach((doc) => {
@@ -201,7 +199,8 @@ export function initHistory() {
loadedGraphqlHistory = false loadedGraphqlHistory = false
setGraphqlHistoryEntries(history) setGraphqlHistoryEntries(history)
loadedGraphqlHistory = true loadedGraphqlHistory = true
}) }
)
} }
}) })
} }

View File

@@ -1,4 +1,4 @@
import firebase from "firebase/app" import { initializeApp } from "firebase/app"
import { initAnalytics } from "./analytics" import { initAnalytics } from "./analytics"
import { initAuth } from "./auth" import { initAuth } from "./auth"
import { initCollections } from "./collections" import { initCollections } from "./collections"
@@ -22,7 +22,7 @@ let initialized = false
export function initializeFirebase() { export function initializeFirebase() {
if (!initialized) { if (!initialized) {
try { try {
firebase.initializeApp(firebaseConfig) initializeApp(firebaseConfig)
initAuth() initAuth()
initSettings() initSettings()

View File

@@ -1,5 +1,3 @@
import firebase from "firebase/app"
import "firebase/firestore"
import { import {
audit, audit,
combineLatest, combineLatest,
@@ -9,6 +7,7 @@ import {
map, map,
Subscription, Subscription,
} from "rxjs" } from "rxjs"
import { doc, getDoc, getFirestore, setDoc } from "firebase/firestore"
import { import {
HoppRESTRequest, HoppRESTRequest,
translateToNewRequest, translateToNewRequest,
@@ -23,13 +22,10 @@ import { restRequest$ } from "~/newstore/RESTSession"
* @param request The request to write to the request sync * @param request The request to write to the request sync
*/ */
function writeCurrentRequest(user: HoppUser, request: HoppRESTRequest) { function writeCurrentRequest(user: HoppUser, request: HoppRESTRequest) {
return firebase return setDoc(
.firestore() doc(getFirestore(), "users", user.uid, "requests", "rest"),
.collection("users") request
.doc(user.uid) )
.collection("requests")
.doc("rest")
.set(request)
} }
/** /**
@@ -43,15 +39,11 @@ export async function loadRequestFromSync(): Promise<HoppRESTRequest | null> {
if (!currentUser) if (!currentUser)
throw new Error("Cannot load request from sync without login") throw new Error("Cannot load request from sync without login")
const doc = await firebase const fbDoc = await getDoc(
.firestore() doc(getFirestore(), "users", currentUser.uid, "requests", "rest")
.collection("users") )
.doc(currentUser.uid)
.collection("requests")
.doc("rest")
.get()
const data = doc.data() const data = fbDoc.data()
if (!data) return null if (!data) return null
else return translateToNewRequest(data) else return translateToNewRequest(data)

View File

@@ -1,5 +1,10 @@
import firebase from "firebase/app" import {
import "firebase/firestore" collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "@firebase/firestore"
import { currentUser$ } from "./auth" import { currentUser$ } from "./auth"
import { applySetting, settingsStore, SettingsType } from "~/newstore/settings" import { applySetting, settingsStore, SettingsType } from "~/newstore/settings"
@@ -28,13 +33,10 @@ async function writeSettings(setting: string, value: any) {
} }
try { try {
await firebase await setDoc(
.firestore() doc(getFirestore(), "users", currentUser$.value.uid, "settings", setting),
.collection("users") st
.doc(currentUser$.value.uid) )
.collection("settings")
.doc(setting)
.set(st)
} catch (e) { } catch (e) {
console.error("error updating", st, e) console.error("error updating", st, e)
throw e throw e
@@ -66,12 +68,9 @@ export function initSettings() {
snapshotStop() snapshotStop()
snapshotStop = null snapshotStop = null
} else if (user) { } else if (user) {
snapshotStop = firebase snapshotStop = onSnapshot(
.firestore() collection(getFirestore(), "users", user.uid, "settings"),
.collection("users") (settingsRef) => {
.doc(user.uid)
.collection("settings")
.onSnapshot((settingsRef) => {
const settings: any[] = [] const settings: any[] = []
settingsRef.forEach((doc) => { settingsRef.forEach((doc) => {
@@ -87,7 +86,8 @@ export function initSettings() {
} }
}) })
loadedSettings = true loadedSettings = true
}) }
)
} }
}) })
} }

5102
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@
"*.{css,scss,vue}": "stylelint" "*.{css,scss,vue}": "stylelint"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.4.8", "@apollo/client": "^3.4.10",
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",
"@nuxtjs/composition-api": "^0.27.0", "@nuxtjs/composition-api": "^0.27.0",
"@nuxtjs/gtm": "^2.4.0", "@nuxtjs/gtm": "^2.4.0",
@@ -34,9 +34,9 @@
"ace-builds": "^1.4.12", "ace-builds": "^1.4.12",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"acorn-walk": "^8.1.1", "acorn-walk": "^8.1.1",
"core-js": "^3.16.2", "core-js": "^3.16.4",
"esprima": "^4.0.1", "esprima": "^4.0.1",
"firebase": "^8.10.0", "firebase": "^9.0.0",
"graphql": "^15.5.0", "graphql": "^15.5.0",
"graphql-language-service-interface": "^2.8.4", "graphql-language-service-interface": "^2.8.4",
"json-loader": "^0.5.7", "json-loader": "^0.5.7",
@@ -73,7 +73,7 @@
"@nuxtjs/google-fonts": "^1.3.0", "@nuxtjs/google-fonts": "^1.3.0",
"@nuxtjs/pwa": "^3.3.5", "@nuxtjs/pwa": "^3.3.5",
"@nuxtjs/stylelint-module": "^4.0.0", "@nuxtjs/stylelint-module": "^4.0.0",
"@nuxtjs/svg": "^0.1.12", "@nuxtjs/svg": "^0.2.0",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@types/cookie": "^0.4.1", "@types/cookie": "^0.4.1",
"@types/lodash": "^4.14.172", "@types/lodash": "^4.14.172",
@@ -81,28 +81,28 @@
"@vue/runtime-dom": "^3.2.6", "@vue/runtime-dom": "^3.2.6",
"@vue/test-utils": "^1.2.2", "@vue/test-utils": "^1.2.2",
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",
"babel-jest": "^27.0.6", "babel-jest": "^27.1.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.1.0", "eslint-config-prettier": "^8.1.0",
"eslint-plugin-nuxt": ">=2.0.0", "eslint-plugin-nuxt": ">=2.0.0",
"eslint-plugin-prettier": "^3.4.1", "eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^7.16.0", "eslint-plugin-vue": "^7.17.0",
"husky": "^7.0.1", "husky": "^7.0.2",
"jest": "^27.0.6", "jest": "^27.1.0",
"jest-serializer-vue": "^2.0.2", "jest-serializer-vue": "^2.0.2",
"lint-staged": "^11.1.2", "lint-staged": "^11.1.2",
"nuxt-windicss": "^1.2.3", "nuxt-windicss": "^1.2.3",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"pretty-quick": "^3.1.1", "pretty-quick": "^3.1.1",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"sass": "^1.38.0", "sass": "^1.38.2",
"sass-loader": "^10.2.0", "sass-loader": "^10.2.0",
"stylelint": "^13.12.0", "stylelint": "^13.12.0",
"stylelint-config-prettier": "^8.0.2", "stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^22.0.0", "stylelint-config-standard": "^22.0.0",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^4.2", "typescript": "^4.2",
"unplugin-vue2-script-setup": "^0.4.2", "unplugin-vue2-script-setup": "^0.5.4",
"vue-jest": "^3.0.7", "vue-jest": "^3.0.7",
"worker-loader": "^3.0.8" "worker-loader": "^3.0.8"
} }