chore: merge hoppscotch/staging into self-hosted/main
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
import { initializeApp } from "firebase/app"
|
||||
import { platform } from "~/platform"
|
||||
import { initAnalytics } from "./analytics"
|
||||
import { initHistory } from "./history"
|
||||
import { initSettings } from "./settings"
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: import.meta.env.VITE_API_KEY,
|
||||
@@ -23,9 +21,9 @@ export function initializeFirebase() {
|
||||
initializeApp(firebaseConfig)
|
||||
|
||||
platform.auth.performAuthInit()
|
||||
initSettings()
|
||||
platform.sync.settings.initSettingsSync()
|
||||
platform.sync.collections.initCollectionsSync()
|
||||
initHistory()
|
||||
platform.sync.history.initHistorySync()
|
||||
platform.sync.environments.initEnvironmentsSync()
|
||||
initAnalytics()
|
||||
|
||||
|
||||
@@ -163,6 +163,20 @@ const RESTHistoryDispatchers = defineDispatchers({
|
||||
}),
|
||||
}
|
||||
},
|
||||
// only used for history.sync.ts to prevent double insertion of history entries from storeSync and Subscriptions
|
||||
removeDuplicateEntry(currentVal: RESTHistoryType, { id }: { id: string }) {
|
||||
const entries = currentVal.state.filter((e) => e.id === id)
|
||||
|
||||
if (entries.length == 2) {
|
||||
const indexToRemove = currentVal.state.findIndex((e) => e.id === id)
|
||||
|
||||
currentVal.state.splice(indexToRemove, 1)
|
||||
}
|
||||
|
||||
return {
|
||||
state: currentVal.state,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const GQLHistoryDispatchers = defineDispatchers({
|
||||
@@ -212,6 +226,20 @@ const GQLHistoryDispatchers = defineDispatchers({
|
||||
}),
|
||||
}
|
||||
},
|
||||
// only used for history.sync.ts to prevent double insertion of history entries from storeSync and Subscriptions
|
||||
removeDuplicateEntry(currentVal: GraphqlHistoryType, { id }: { id: string }) {
|
||||
const entries = currentVal.state.filter((e) => e.id === id)
|
||||
|
||||
if (entries.length == 2) {
|
||||
const indexToRemove = currentVal.state.findIndex((e) => e.id === id)
|
||||
|
||||
currentVal.state.splice(indexToRemove, 1)
|
||||
}
|
||||
|
||||
return {
|
||||
state: currentVal.state,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const restHistoryStore = new DispatchingStore(
|
||||
@@ -297,6 +325,20 @@ export function toggleGraphqlHistoryEntryStar(entry: GQLHistoryEntry) {
|
||||
})
|
||||
}
|
||||
|
||||
export function removeDuplicateRestHistoryEntry(id: string) {
|
||||
restHistoryStore.dispatch({
|
||||
dispatcher: "removeDuplicateEntry",
|
||||
payload: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export function removeDuplicateGraphqlHistoryEntry(id: string) {
|
||||
graphqlHistoryStore.dispatch({
|
||||
dispatcher: "removeDuplicateEntry",
|
||||
payload: { id },
|
||||
})
|
||||
}
|
||||
|
||||
// Listen to completed responses to add to history
|
||||
completedRESTResponse$.subscribe((res) => {
|
||||
if (res !== null) {
|
||||
|
||||
3
packages/hoppscotch-common/src/platform/history.ts
Normal file
3
packages/hoppscotch-common/src/platform/history.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type HistoryPlatformDef = {
|
||||
initHistorySync: () => void
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import { AuthPlatformDef } from "./auth"
|
||||
import { UIPlatformDef } from "./ui"
|
||||
import { EnvironmentsPlatformDef } from "./environments"
|
||||
import { CollectionsPlatformDef } from "./collections"
|
||||
import { SettingsPlatformDef } from "./settings"
|
||||
import { HistoryPlatformDef } from "./history"
|
||||
|
||||
export type PlatformDef = {
|
||||
ui?: UIPlatformDef
|
||||
@@ -9,6 +11,8 @@ export type PlatformDef = {
|
||||
sync: {
|
||||
environments: EnvironmentsPlatformDef
|
||||
collections: CollectionsPlatformDef
|
||||
settings: SettingsPlatformDef
|
||||
history: HistoryPlatformDef
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
packages/hoppscotch-common/src/platform/settings.ts
Normal file
3
packages/hoppscotch-common/src/platform/settings.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type SettingsPlatformDef = {
|
||||
initSettingsSync: () => void
|
||||
}
|
||||
@@ -12,8 +12,11 @@ import {
|
||||
updateDoc,
|
||||
} from "firebase/firestore"
|
||||
import { FormDataKeyValue } from "@hoppscotch/data"
|
||||
import { platform } from "~/platform"
|
||||
import { getSettingSubject, settingsStore } from "~/newstore/settings"
|
||||
import { def as platformAuth } from "./firebase/auth"
|
||||
import {
|
||||
getSettingSubject,
|
||||
settingsStore,
|
||||
} from "@hoppscotch/common/newstore/settings"
|
||||
import {
|
||||
GQLHistoryEntry,
|
||||
graphqlHistoryStore,
|
||||
@@ -24,7 +27,8 @@ import {
|
||||
setRESTHistoryEntries,
|
||||
translateToNewGQLHistory,
|
||||
translateToNewRESTHistory,
|
||||
} from "~/newstore/history"
|
||||
} from "@hoppscotch/common/newstore/history"
|
||||
import { HistoryPlatformDef } from "@hoppscotch/common/platform/history"
|
||||
|
||||
type HistoryFBCollections = "history" | "graphqlHistory"
|
||||
|
||||
@@ -76,7 +80,7 @@ async function writeHistory(
|
||||
? purgeFormDataFromRequest(entry as RESTHistoryEntry)
|
||||
: entry
|
||||
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser === null)
|
||||
throw new Error("User not logged in to sync history")
|
||||
@@ -98,7 +102,7 @@ async function deleteHistory(
|
||||
entry: (RESTHistoryEntry | GQLHistoryEntry) & { id: string },
|
||||
col: HistoryFBCollections
|
||||
) {
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser === null)
|
||||
throw new Error("User not logged in to delete history")
|
||||
@@ -114,7 +118,7 @@ async function deleteHistory(
|
||||
}
|
||||
|
||||
async function clearHistory(col: HistoryFBCollections) {
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser === null)
|
||||
throw new Error("User not logged in to clear history")
|
||||
@@ -130,7 +134,7 @@ async function toggleStar(
|
||||
entry: (RESTHistoryEntry | GQLHistoryEntry) & { id: string },
|
||||
col: HistoryFBCollections
|
||||
) {
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser === null) throw new Error("User not logged in to toggle star")
|
||||
|
||||
@@ -145,11 +149,11 @@ async function toggleStar(
|
||||
}
|
||||
}
|
||||
|
||||
export function initHistory() {
|
||||
const currentUser$ = platform.auth.getCurrentUserStream()
|
||||
export function initHistorySync() {
|
||||
const currentUser$ = platformAuth.getCurrentUserStream()
|
||||
|
||||
const restHistorySub = restHistoryStore.dispatches$.subscribe((dispatch) => {
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (loadedRESTHistory && currentUser && settingsStore.value.syncHistory) {
|
||||
if (dispatch.dispatcher === "addEntry") {
|
||||
@@ -166,7 +170,7 @@ export function initHistory() {
|
||||
|
||||
const gqlHistorySub = graphqlHistoryStore.dispatches$.subscribe(
|
||||
(dispatch) => {
|
||||
const currentUser = platform.auth.getCurrentUser()
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (
|
||||
loadedGraphqlHistory &&
|
||||
@@ -262,7 +266,11 @@ export function initHistory() {
|
||||
gqlHistorySub.unsubscribe()
|
||||
currentUserSub.unsubscribe()
|
||||
|
||||
initHistory()
|
||||
initHistorySync()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const def: HistoryPlatformDef = {
|
||||
initHistorySync,
|
||||
}
|
||||
@@ -2,11 +2,15 @@ import { createHoppApp } from "@hoppscotch/common"
|
||||
import { def as authDef } from "./firebase/auth"
|
||||
import { def as envDef } from "./environments"
|
||||
import { def as collectionsDef } from "./collections"
|
||||
import { def as settingsDef } from "./settings"
|
||||
import { def as historyDef } from "./history"
|
||||
|
||||
createHoppApp("#app", {
|
||||
auth: authDef,
|
||||
sync: {
|
||||
environments: envDef,
|
||||
collections: collectionsDef,
|
||||
settings: settingsDef,
|
||||
history: historyDef,
|
||||
},
|
||||
})
|
||||
|
||||
108
packages/hoppscotch-web/src/settings.ts
Normal file
108
packages/hoppscotch-web/src/settings.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
collection,
|
||||
doc,
|
||||
getFirestore,
|
||||
onSnapshot,
|
||||
setDoc,
|
||||
} from "firebase/firestore"
|
||||
import { def as platformAuth } from "./firebase/auth"
|
||||
import {
|
||||
applySetting,
|
||||
settingsStore,
|
||||
SettingsDef,
|
||||
} from "@hoppscotch/common/newstore/settings"
|
||||
import { SettingsPlatformDef } from "@hoppscotch/common/platform/settings"
|
||||
|
||||
/**
|
||||
* Used locally to prevent infinite loop when settings sync update
|
||||
* is applied to the store which then fires the store sync listener.
|
||||
* When you want to update settings and not want to fire the update listener,
|
||||
* set this to true and then set it back to false once it is done
|
||||
*/
|
||||
let loadedSettings = false
|
||||
|
||||
/**
|
||||
* Write Transform
|
||||
*/
|
||||
async function writeSettings(setting: string, value: any) {
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser === null)
|
||||
throw new Error("Cannot write setting, user not signed in")
|
||||
|
||||
const st = {
|
||||
updatedOn: new Date(),
|
||||
author: currentUser.uid,
|
||||
author_name: currentUser.displayName,
|
||||
author_image: currentUser.photoURL,
|
||||
name: setting,
|
||||
value,
|
||||
}
|
||||
|
||||
try {
|
||||
await setDoc(
|
||||
doc(getFirestore(), "users", currentUser.uid, "settings", setting),
|
||||
st
|
||||
)
|
||||
} catch (e) {
|
||||
console.error("error updating", st, e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
export function initSettingsSync() {
|
||||
const currentUser$ = platformAuth.getCurrentUserStream()
|
||||
|
||||
settingsStore.dispatches$.subscribe((dispatch) => {
|
||||
const currentUser = platformAuth.getCurrentUser()
|
||||
|
||||
if (currentUser && loadedSettings) {
|
||||
if (dispatch.dispatcher === "bulkApplySettings") {
|
||||
Object.keys(dispatch.payload).forEach((key) => {
|
||||
writeSettings(key, dispatch.payload[key])
|
||||
})
|
||||
} else {
|
||||
writeSettings(
|
||||
dispatch.payload.settingKey,
|
||||
settingsStore.value[dispatch.payload.settingKey as keyof SettingsDef]
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let snapshotStop: (() => void) | null = null
|
||||
|
||||
// Subscribe and unsubscribe event listeners
|
||||
currentUser$.subscribe((user) => {
|
||||
if (!user && snapshotStop) {
|
||||
// User logged out
|
||||
snapshotStop()
|
||||
snapshotStop = null
|
||||
} else if (user) {
|
||||
snapshotStop = onSnapshot(
|
||||
collection(getFirestore(), "users", user.uid, "settings"),
|
||||
(settingsRef) => {
|
||||
const settings: any[] = []
|
||||
|
||||
settingsRef.forEach((doc) => {
|
||||
const setting = doc.data()
|
||||
setting.id = doc.id
|
||||
settings.push(setting)
|
||||
})
|
||||
|
||||
loadedSettings = false
|
||||
settings.forEach((e) => {
|
||||
if (e && e.name && e.value != null) {
|
||||
applySetting(e.name, e.value)
|
||||
}
|
||||
})
|
||||
loadedSettings = true
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const def: SettingsPlatformDef = {
|
||||
initSettingsSync,
|
||||
}
|
||||
Reference in New Issue
Block a user